Compare commits

..
Author SHA1 Message Date
Joachim Wiberg 58e31dbd22 .github: try running with older Ubuntu version
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-06 19:57:46 +02:00
Joachim Wiberg 85058b54a8 plugins: bootmisc: use relative symlink for /var/run
In an upside world, much like the Finit test cases, the root may be
relocated.  This make /var/run relative to /var, instead of /.  Which
hopefully is safer and covers more use-cases.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-05 17:46:43 +02:00
Joachim Wiberg f16df142d7 Minor shellcheck fixes to debug code
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-05 17:46:20 +02:00
Joachim Wiberg f9f52a46a6 Debug sys plugin
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-05 07:27:22 +02:00
Joachim Wiberg ef1bfb869f test: HUP Finit from inside container instead ...
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-05 06:49:52 +02:00
Joachim Wiberg 5002c74876 test: force enable debug logs and HUP Finit before test
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-05 06:39:23 +02:00
Joachim Wiberg a0bc23c48f test: enable finit debug to see why API socket isn't created
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-04 20:52:08 +02:00
Joachim Wiberg 350cf6e578 test: dump contents of /var/run/finit/ to check for socket
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-04 20:46:48 +02:00
Joachim Wiberg b96a8d8766 test: dump correct root dir and add more PID 1 debug
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-04 20:31:13 +02:00
Joachim Wiberg a419828dea .github: no ~/.cache, check rest
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-04 20:22:05 +02:00
Joachim Wiberg 702b22d4a3 .github: check if ~/.cache exists, dump test root files
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-04-04 20:19:13 +02:00
318 changed files with 5518 additions and 20521 deletions
+5 -5
View File
@@ -9,9 +9,9 @@ For email questions/requests/alerts there is always the risk of memory
exhaustion on the part of the maintainer(s). exhaustion on the part of the maintainer(s).
If you are unsure of what to do, or how to implement an idea or bugfix, 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 open an issue with `"[RFC: Unsure if this is a bug ... ?"`, or similar,
GitHub discussions forum, so we can discuss it. Talking about the code so we can discuss it. Talking about the code first is the best way to
first is the best way to get started before submitting a pull request. get started before submitting a pull request.
Either way, when sending an email, patch, or pull request, start by 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. stating the version the change is made against, what it does, and why.
@@ -24,8 +24,7 @@ the maintainer(s) and make it easier for them to include your code.
Coding Style Coding Style
------------ ------------
> [!TIP] > **Tip:** Always submit code that follows the style of surrounding code!
> Always submit code that follows the style of surrounding code!
First of all, lines are allowed to be longer than 72 characters these First of all, lines are allowed to be longer than 72 characters these
days. In fact, there exist no enforced maximum, but keeping it around days. In fact, there exist no enforced maximum, but keeping it around
@@ -74,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]. Bill & Ted; [be excellent to each other][conduct].
[github]: https://github.com/troglobit/finit/
[KNF]: https://en.wikipedia.org/wiki/Kernel_Normal_Form [KNF]: https://en.wikipedia.org/wiki/Kernel_Normal_Form
[gitbook]: https://git-scm.com/book/ch5-2.html [gitbook]: https://git-scm.com/book/ch5-2.html
[conduct]: CODE-OF-CONDUCT.md [conduct]: CODE-OF-CONDUCT.md
+1 -1
View File
@@ -5,7 +5,7 @@
finit is a small project, as such we have no possibility to support older versions. finit is a small project, as such we have no possibility to support older versions.
The only supported version is the latest released on GitHub: The only supported version is the latest released on GitHub:
<https://github.com/finit-project/finit/releases> <https://github.com/troglobit/finit/releases>
## Reporting a Vulnerability ## Reporting a Vulnerability
+24 -41
View File
@@ -8,80 +8,63 @@ on:
- '**' - '**'
- '!dev' - '!dev'
pull_request: pull_request:
types: [opened, synchronize, reopened, labeled] branches:
- '**'
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: true
jobs: jobs:
build: build:
# Verify we can build on latest Ubuntu with both gcc and clang # Verify we can build on latest Ubuntu with both gcc and clang
name: ${{ matrix.compiler }} name: ${{ matrix.compiler }}
runs-on: ubuntu-latest runs-on: ubuntu-18.04
# Skip redundant builds for PRs - prefer PR builds over push builds
if: github.event_name != 'push' || github.ref == 'refs/heads/master'
strategy: strategy:
matrix: matrix:
compiler: [gcc, clang] compiler: [gcc, clang]
fail-fast: false fail-fast: false
env: env:
MAKEFLAGS: -j3
CC: ${{ matrix.compiler }} CC: ${{ matrix.compiler }}
steps: steps:
- name: Install dependencies - name: Install dependencies
run: | run: |
sudo apt-get -y update sudo apt-get -y update
sudo apt-get -y install pkg-config tree jq libcap-dev
sudo apt-get -y install pkg-config sudo apt-get -y install pkg-config
wget https://github.com/troglobit/libuev/releases/download/v2.4.1/libuev-2.4.1.tar.xz 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.6.2/libite-2.6.2.tar.gz wget https://github.com/troglobit/libite/releases/download/v2.3.1/libite-2.3.1.tar.gz
tar xf libuev-2.4.1.tar.xz tar xf libuev-2.3.2.tar.xz
tar xf libite-2.6.2.tar.gz tar xf libite-2.3.1.tar.gz
(cd libuev-2.4.1 && ./configure && make -j9 && sudo make install-strip) (cd libuev-2.3.2 && ./configure --prefix=/usr && make && sudo make install-strip)
(cd libite-2.6.2 && ./configure && make -j9 && sudo make install-strip) (cd libite-2.3.1 && ./configure --prefix=/usr && make && sudo make install-strip)
sudo ldconfig sudo ldconfig
- uses: actions/checkout@v4 - uses: actions/checkout@v2
- name: Static Finit - name: Static Finit
run: | run: |
./autogen.sh ./autogen.sh
./configure --prefix= --enable-static ./configure --prefix= --enable-static
make -j9 V=1 make V=1
- name: Regular Finit - name: Regular Finit
run: | run: |
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \ ./configure --prefix= --enable-x11-common-plugin --with-watchdog --with-keventd
--enable-x11-common-plugin --enable-testserv-plugin --with-watchdog \ make clean
--with-keventd --with-libsystemd \ make V=1
CFLAGS="-fsanitize=address -ggdb" - name: Install to ~/tmp and Inspect
make -j9 clean
make -j9 V=1
- name: Install to /tmp
run: | run: |
DESTDIR=/tmp make install-strip DESTDIR=/tmp make install-strip
tree /tmp || true tree /tmp
- name: Check dependencies
run: |
ldd /tmp/sbin/finit ldd /tmp/sbin/finit
size /tmp/sbin/finit size /tmp/sbin/finit
ldd /tmp/sbin/initctl ldd /tmp/sbin/initctl
size /tmp/sbin/initctl size /tmp/sbin/initctl
ldd /tmp/sbin/reboot ldd /tmp/sbin/reboot
size /tmp/sbin/reboot size /tmp/sbin/reboot
- name: Verify starting and showing usage text /tmp/sbin/finit -h
run: | /tmp/sbin/initctl -h
sudo /tmp/sbin/finit -h
sudo /tmp/sbin/initctl -h
- name: Enable unprivileged userns (unshare)
run: |
sudo sysctl kernel.apparmor_restrict_unprivileged_userns=0
- name: Run Unit Tests - name: Run Unit Tests
run: | run: |
make -j1 check || (cat test/test-suite.log; false) ver=$(/tmp/sbin/initctl -V | awk '/Finit.*/ {print $2;}')
dir=finit-$ver/_build/sub
make -j1 distcheck || (cat $dir/test/setup-root.log; cat $dir/test/test-suite.log; false)
- name: Upload Test Results - name: Upload Test Results
if: always() uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with: with:
name: finit-test-${{ matrix.compiler }} name: finit-test-${{ matrix.compiler }}
path: test/*.log path: test/*
+22 -51
View File
@@ -4,10 +4,6 @@ on:
push: push:
branches: branches:
- 'dev' - 'dev'
workflow_dispatch:
permissions:
contents: read
env: env:
PROJECT_NAME: finit PROJECT_NAME: finit
@@ -19,60 +15,40 @@ jobs:
coverity: coverity:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v2
- name: Fetch latest Coverity Scan MD5 - uses: actions/cache@v2
id: var id: coverity-toolchain-cache
env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
run: |
wget -q https://scan.coverity.com/download/cxx/linux64 \
--post-data "token=$TOKEN&project=${COVERITY_PROJ}&md5=1" \
-O coverity-latest.tar.gz.md5
echo "md5=$(cat coverity-latest.tar.gz.md5)" | tee -a $GITHUB_OUTPUT
- uses: actions/cache@v4
id: cache
with: with:
path: coverity-latest.tar.gz path: cov-analysis-linux64
key: ${{ runner.os }}-coverity-${{ steps.var.outputs.md5 }} key: ${{ runner.os }}-coverity
restore-keys: |
${{ runner.os }}-coverity-${{ steps.var.outputs.md5 }}
${{ runner.os }}-coverity-
${{ runner.os }}-coverity
- name: Download Coverity Scan - name: Download Coverity Scan
if: steps.coverity-toolchain-cache.outputs.cache-hit != 'true'
env: env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
run: | run: |
if [ ! -f coverity-latest.tar.gz ]; then wget -q https://scan.coverity.com/download/cxx/linux64 \
wget -q https://scan.coverity.com/download/cxx/linux64 \ --post-data "token=$TOKEN&project=${COVERITY_PROJ}" \
--post-data "token=$TOKEN&project=${COVERITY_PROJ}" \ -O cov-analysis-linux64.tar.gz
-O coverity-latest.tar.gz mkdir cov-analysis-linux64
else tar xzf cov-analysis-linux64.tar.gz --strip 1 -C cov-analysis-linux64
echo "Latest Coverity Scan available from cache :-)"
md5sum coverity-latest.tar.gz
fi
mkdir coverity
tar xzf coverity-latest.tar.gz --strip 1 -C coverity
- name: Install dependencies - name: Install dependencies
run: | run: |
sudo apt-get -y update sudo apt-get -y update
sudo apt-get -y install pkg-config libcap-dev sudo apt-get -y install pkg-config
wget https://github.com/troglobit/libuev/releases/download/v2.4.1/libuev-2.4.1.tar.xz 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.6.2/libite-2.6.2.tar.gz wget https://github.com/troglobit/libite/releases/download/v2.3.1/libite-2.3.1.tar.gz
tar xf libuev-2.4.1.tar.xz tar xf libuev-2.3.2.tar.xz
tar xf libite-2.6.2.tar.gz tar xf libite-2.3.1.tar.gz
(cd libuev-2.4.1 && ./configure && make -j9 && sudo make install-strip) (cd libuev-2.3.2 && ./configure --prefix=/usr && make && sudo make install-strip)
(cd libite-2.6.2 && ./configure && make -j9 && sudo make install-strip) (cd libite-2.3.1 && ./configure --prefix=/usr && make && sudo make install-strip)
sudo ldconfig sudo ldconfig
- name: Configure
run: |
./autogen.sh
./configure --prefix= --enable-x11-common-plugin --with-watchdog \
--with-keventd --with-libsystemd
- name: Build - name: Build
run: | run: |
export PATH=`pwd`/coverity/bin:$PATH ./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 cov-build --dir cov-int make
- name: Submit results to Coverity Scan - name: Submit result to Coverity Scan
env: env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
run: | run: |
@@ -85,8 +61,3 @@ jobs:
--form version=trunk \ --form version=trunk \
--form description="${PROJECT_NAME} $(git rev-parse HEAD)" \ --form description="${PROJECT_NAME} $(git rev-parse HEAD)" \
https://scan.coverity.com/builds?project=${COVERITY_PROJ} https://scan.coverity.com/builds?project=${COVERITY_PROJ}
- name: Upload build.log
uses: actions/upload-artifact@v4
with:
name: coverity-build.log
path: cov-int/build-log.txt
-100
View File
@@ -1,100 +0,0 @@
name: Dotty the Documenteer
on:
push:
branches:
- master
paths:
- 'doc/**'
- 'README.md'
- 'mkdocs.yml'
- '.github/workflows/docs.yml'
pull_request:
types: [opened, synchronize, reopened, labeled]
paths:
- 'doc/**'
- 'README.md'
- 'mkdocs.yml'
- '.github/workflows/docs.yml'
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0 # Needed for git-revision-date-localized plugin
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Install dependencies
run: |
pipx install mkdocs
pipx inject mkdocs mkdocs-material
pipx inject mkdocs pymdown-extensions
pipx inject mkdocs mkdocs-callouts
pipx inject mkdocs mkdocs-glightbox
- name: Build documentation
run: mkdocs build --clean
- name: Upload site artifact
uses: actions/upload-artifact@v4
with:
name: site
path: site/
deploy:
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
needs: build
runs-on: ubuntu-latest
steps:
- name: Download site artifact
uses: actions/download-artifact@v4
with:
name: site
path: site/
- name: Checkout pages repo
uses: actions/checkout@v4
with:
repository: finit-project/finit-project.github.io
path: pages
ssh-key: ${{ secrets.DOCS_DEPLOY_KEY }}
persist-credentials: true
- name: Setup SSH for push
run: |
mkdir -p ~/.ssh
chmod 700 ~/.ssh
ssh-keyscan github.com >> ~/.ssh/known_hosts
- name: Sync site to pages repo
run: |
rsync -a --delete --exclude .git site/ pages/
- name: Commit and push
run: |
cd pages/
if [ -z "$(git status --porcelain)" ]; then
exit 0
fi
SRC_REPO="${GITHUB_REPOSITORY}"
SRC_REF="${GITHUB_SHA::7}"
SRC_URL="https://github.com/${SRC_REPO}/commit/${SRC_REF}"
git config user.name "GitHub Actions"
git config user.email "actions@github.com"
git add -A
git commit -m "docs: update from ${SRC_REPO}@${SRC_REF}" \
-m "For details, see ${SRC_URL}"
git push
+47 -60
View File
@@ -3,80 +3,67 @@ name: Release General
on: on:
push: push:
tags: tags:
- '[0-9]+.[0-9]+*' - '[0-9]+.[0-9]+'
permissions:
contents: write
jobs: jobs:
release: release:
name: Create GitHub release
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
outputs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
release_id: ${{ steps.create_release.outputs.id }}
steps:
- uses: actions/checkout@v2
- name: Extract ChangeLog entry ...
# Hack to extract latest entry for body_path below
run: |
awk '/-----*/{if (x == 1) exit; x=1;next}x' ChangeLog.md \
|head -n -1 > release.md
cat release.md
- name: Create release ...
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Finit v${{ github.ref }}
body_path: release.md
draft: false
prerelease: false
tarball:
name: Build and upload release tarball name: Build and upload release tarball
needs: release
if: startsWith(github.ref, 'refs/tags/') if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v2
- name: Installing dependencies ... - name: Installing dependencies
run: | run: |
sudo apt-get -y update sudo apt-get -y update
sudo apt-get -y install pkg-config jq libcap-dev sudo apt-get -y install pkg-config
wget https://github.com/troglobit/libuev/releases/download/v2.4.1/libuev-2.4.1.tar.xz 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.6.2/libite-2.6.2.tar.gz wget https://github.com/troglobit/libite/releases/download/v2.3.1/libite-2.3.1.tar.gz
tar xf libuev-2.4.1.tar.xz tar xf libuev-2.3.2.tar.xz
tar xf libite-2.6.2.tar.gz tar xf libite-2.3.1.tar.gz
(cd libuev-2.4.1 && ./configure && make -j9 && sudo make install-strip) (cd libuev-2.3.2 && ./configure --prefix=/usr && make && sudo make install-strip)
(cd libite-2.6.2 && ./configure && make -j9 && sudo make install-strip) (cd libite-2.3.1 && ./configure --prefix=/usr && make && sudo make install-strip)
sudo ldconfig sudo ldconfig
- name: Setting release variables ... - name: Creating Makefiles
id: build
run: |
ver=${GITHUB_REF#refs/tags/}
echo "ver=${ver}" >> $GITHUB_OUTPUT
if echo $ver | grep -qE '^[0-9]+\.[0-9]+(\.[0-9]+)?(-alpha|-beta|-rc)[0-9]*$'; then
echo "pre=true" >> $GITHUB_OUTPUT
else
echo "pre=false" >> $GITHUB_OUTPUT
fi
if echo $ver | grep -qE '^[0-9.]+\.[0-9.]+(\.[0-9]+)?$'; then
echo "latest=true" >> $GITHUB_OUTPUT
else
echo "latest=false" >> $GITHUB_OUTPUT
fi
- name: Creating Makefiles ...
run: | run: |
./autogen.sh ./autogen.sh
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc \ ./configure --prefix= --enable-x11-common-plugin --with-watchdog --with-keventd
--localstatedir=/var --enable-x11-common-plugin \ - name: Building release
--enable-testserv-plugin --with-watchdog \
--with-keventd --with-libsystemd
- name: Enable unprivileged userns (unshare)
run: | run: |
sudo sysctl kernel.apparmor_restrict_unprivileged_userns=0 make release
- name: Build release ...
run: |
# Get version for finding distcheck build directory
./configure --version | head -1
ver=$(./configure --version | head -1 | awk '{print $NF}')
dir=finit-$ver/_build/sub
make -j1 release || (cat $dir/test/test-suite.log; false)
ls -lF ../ ls -lF ../
mkdir -p artifacts/ mkdir -p artifacts/
mv ../*.tar.* artifacts/ mv ../*.tar.* artifacts/
- name: Upload Test Results - name: Uploading release artifacts
if: always() uses: skx/github-action-publish-binaries@release-0.15
uses: actions/upload-artifact@v4 env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
name: finit-release-test-logs releaseId: ${{ needs.release.outputs.release_id }}
path: finit-*/_build/sub/test/*.log args: artifacts/*
- name: Extract ChangeLog entry ...
run: |
awk '/-----*/{if (x == 1) exit; x=1;next}x' doc/ChangeLog.md \
|head -n -1 > release.md
cat release.md
- uses: ncipollo/release-action@v1
with:
name: Finit v${{ github.ref_name }}
prerelease: ${{ steps.build.outputs.pre }}
makeLatest: ${{ steps.build.outputs.latest }}
bodyFile: "release.md"
artifacts: "artifacts/*"
-67
View File
@@ -1,67 +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:
permissions:
contents: read
jobs:
schedule:
runs-on: ubuntu-latest
outputs:
run: ${{ steps.schedule.outputs.run }}
steps:
- uses: actions/checkout@v4
- name: Check for any commits since last week
id: schedule
run: |
commits="$(git log --format=%H --since='1 week ago')"
if [ -z "$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 libcap-dev
wget https://github.com/troglobit/libuev/releases/download/v2.4.1/libuev-2.4.1.tar.xz
wget https://github.com/troglobit/libite/releases/download/v2.6.2/libite-2.6.2.tar.gz
tar xf libuev-2.4.1.tar.xz
tar xf libite-2.6.2.tar.gz
(cd libuev-2.4.1 && ./configure && make -j9 && sudo make install-strip)
(cd libite-2.6.2 && ./configure && make -j9 && sudo make install-strip)
sudo ldconfig
- uses: actions/checkout@v4
- 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: Enable unprivileged userns (unshare)
run: |
sudo sysctl kernel.apparmor_restrict_unprivileged_userns=0
- 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)
- name: Upload Test Results
if: always()
uses: actions/upload-artifact@v4
with:
name: finit-weekly-test-logs
path: finit-*/_build/sub/test/*.log
-4
View File
@@ -14,7 +14,6 @@ GTAGS
/autom4te.cache /autom4te.cache
/aclocal.m4 /aclocal.m4
/ar-lib /ar-lib
/backup/
/compile /compile
/config.cache /config.cache
/config.h /config.h
@@ -37,9 +36,6 @@ GTAGS
/test-driver /test-driver
/test-suite.log /test-suite.log
# Misc
/.gdb_history
# TroglOS build system # TroglOS build system
/.config /.config
/.stamp /.stamp
-15
View File
@@ -1,15 +0,0 @@
# GNU Global .conf file, see /etc/gtags/gtags.conf for details.
# This configuration is optimized for the Finit project structure.
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,*.la,\
*.zip,*.gz,*.bz2,*.xz,*.lzh,*.Z,*.tgz,\
*.log,*.trs,test-suite.log,stamp-*,\
sysroot/:
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,5 +1,5 @@
Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com> Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
Copyright (c) 2008-2025 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 Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
+3 -18
View File
@@ -1,6 +1,7 @@
ACLOCAL_AMFLAGS = -I m4 ACLOCAL_AMFLAGS = -I m4
SUBDIRS = man plugins src system tmpfiles.d SUBDIRS = man plugins src test
dist_doc_DATA = README.md LICENSE contrib/finit.conf doc_DATA = README.md LICENSE contrib/finit.conf
EXTRA_DIST = README.md LICENSE ChangeLog.md contrib/finit.conf
if CONTRIB if CONTRIB
SUBDIRS += contrib SUBDIRS += contrib
@@ -8,17 +9,6 @@ endif
if DOC if DOC
SUBDIRS += doc SUBDIRS += doc
endif endif
if LIBSYSTEMD
SUBDIRS += libsystemd
endif
if LIBSYSTEMD
SUBDIRS += test
# Explicit dependency to ensure libsystemd is built before test
test: libsystemd
else
SUBDIRS += test
endif
# Compat hook # Compat hook
install-dev: install-dev:
@@ -39,8 +29,3 @@ release: distcheck
printf "$$file.md5\t"; cat ../$$file.md5 | cut -f1 -d' '; \ printf "$$file.md5\t"; cat ../$$file.md5 | cut -f1 -d' '; \
printf "$$file.sha256\t"; cat ../$$file.sha256 | cut -f1 -d' '; \ printf "$$file.sha256\t"; cat ../$$file.sha256 | cut -f1 -d' '; \
done 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 \
--with-libsystemd --with-bash-completion-dir=no
+590 -36
View File
@@ -1,50 +1,604 @@
[![License Badge][]][License] [![Release Badge][]][Release] [![GitHub Status][]][GitHub] [![Coverity Status][]][Coverity Scan] [![License Badge][]][License] [![GitHub Status][]][GitHub] [![Coverity Status][]][Coverity Scan]
<img align="right" src="doc/img/finit3.png" alt="Finit: Fast Init"> <img align="right" src="img/finit3.png" alt="Finit: Fast Init">
Finit is a fast, simple alternative to [SysV init](https://en.wikipedia.org/wiki/Init) * [Introduction](#introduction)
and [systemd](https://systemd.io), designed for small and embedded Linux systems. * [Features](#features)
It can also run on desktop and server systems, like [finix][]. * [Bootstrap](doc/bootstrap.md#bootstrap)
* [Runlevels](#runlevels)
* [Syntax](doc/config.md#syntax)
* [Runparts & /etc/rc.local](#runparts--etcrclocal)
* [Hooks, Callbacks & Plugins](doc/plugins.md#hooks-callbacks--plugins)
* [Rebooting & Halting](#rebooting--halting)
* [Commands & Status](#commands--status)
* [Tips & Tricks with the kernel cmdline](doc/cmdline.md)
* [Building](doc/build.md#building)
* [Running](doc/build.md#running)
* [Recovery](doc/build.md#recovery)
* [Debugging](doc/build.md#debugging)
* [Requirements](#requirements)
* [Origin & References](#origin--references)
> Reverse engineered from the [EeePC fastinit][]
> "gaps filled with frog DNA …"
> — [Claudio Matsuoka][]
For detailed information, explore our extensive documentation Introduction
:books: **<http://finit-project.github.io>** ------------
<div align="center"> Fast init for Linux systems. Reverse engineered from the [EeePC
<img src="doc/img/alpine-screenshot2.png" alt="Alpine screenshot"><br/> fastinit][] over ten years ago by [Claudio Matsuoka][] — "gaps filled
</div> with frog DNA …"
For working examples, see the :rocket: [contrib/](contrib/) section or these ![Alpine screenshot](img/finit4-screenshot.png)
tutorials: *Figure 1: Screenshot showing Finit booting [Alpine Linux](https://www.alpinelinux.org/).*
* :hammer_and_wrench: [Buildroot embedded Linux][br2demo], Features include:
* :package: [Debian GNU/Linux](contrib/debian/),
* :mountain: [Alpine Linux](contrib/alpine/), and
* :milky_way: [Void Linux](contrib/void/)
> [!NOTE] * Runlevels, defined per service
> Finit can run on various Linux distributions, but the bundled install * One-shot tasks, services (daemons), or [SysV init][4] start/stop scripts
> scripts are examples only. They have been tested on amd64 (x86_64) systems * Runparts and `/etc/rc.local` support
> with standard configurations. * Process supervision similar to [systemd][]
> * Sourcing environment files
> For embedded systems, see these [Buildroot][]-based examples: * Conditions for network/process/custom dependencies
> [myLinux][], [Infix][], or [br2-finit-demo][]. * Pre/Post script actions
* 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
[finix]: https://github.com/finix-community/finix Focus is on small and embedded systems, although Finit is fully usable
[Buildroot]: https://buildroot.org on server and desktop systems as well. For working examples, see the
[Infix]: https://kernelkit.github.io [contrib/](contrib/) section with tutorials for:
[myLinux]: https://github.com/troglobit/myLinux/
[br2demo]: https://troglobit.com/post/2022-12-26-buildroot-demo-of-fastinit-finit/ * [Void Linux](contrib/void/),
* [Alpine Linux](contrib/alpine/), and
* [Debian GNU/Linux](contrib/debian/)
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.
```ApacheConf
# Fallback if /etc/hostname is missing
host default
# Runlevel to start after bootstrap, 'S', default: 2
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)
# 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
# log file is rotated with the above settings. The condition declares
# a dependency on a system default route (gateway) to be set. A single
# <!> at the beginning means ntpd does not respect SIGHUP for restart.
service [2345] log:/var/log/ntpd.log <!net/route/default> ntpd -n -l -I eth0 -- NTP daemon
# For multiple instances of the same service, add :ID somewhere between
# the service/run/task keyword and the command.
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
# 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
# Use built-in getty for serial port and USB serial
#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
```
The `service` stanza, as well as `task`, `run` and others are described
in full in [doc/config.md](doc/config.md). Here's a quick overview of
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 env. file
| | | `-------------------------------------------------------- Redirect output to log
| | `--------------------------------------------------------------- Optional conditions
| `---------------------------------------------------------------------- Optional Runlevels
`------------------------------------------------------------------------------ Monitored application
```
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
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
Here is another example where we instruct Finit to not start BusyBox
`ntpd` until `syslogd` has started properly. Finit waits for `syslogd`
to create its PID file, by default `/var/run/syslogd.pid`.
service [2345] log <!pid/syslogd> ntpd -n -N -p pool.ntp.org
service [S12345] syslogd -n -- Syslog daemon
Notice the `log` keyword, BusyBox `ntpd` uses `stderr` for logging when
run in the foreground. With `log` Finit redirects `stdout` + `stderr`
to the system log daemon using the command line `logger(1)` tool.
A service, or task, can have multiple dependencies listed. Here we wait
for *both* `syslogd` to have started and basic networking to be up:
service [2345] log <pid/syslogd,net/route/default> ntpd -n -N -p pool.ntp.org
If either condition fails, e.g. loss of networking, `ntpd` is stopped
and as soon as it comes back up again `ntpd` is restarted automatically.
**Note:** Make sure daemons *do not* fork and detach themselves from the
controlling TTY, usually an `-n` or `-f` flag, or `-D` as in the case
of OpenSSH above. If it detaches itself, Finit cannot monitor it and
will instead try to restart it.
Features
--------
**Process Supervision**
Start, monitor and restart services should they fail.
**Getty**
Finit supports external getty but also comes with a limited built-in
Getty, useful for really small systems. A getty sets up the TTY and
waits for user input before handing over to `/bin/login`, which is
responsible for handling the actual authentication.
```conf
tty [12345] /dev/tty1 nowait linux
tty [12345] /dev/ttyAMA0 noclear vt100
tty [12345] /sbin/getty -L /dev/ttyAMA0 vt100
```
Users of embedded systems may want to enable automatic serial console
with the special `@console` device. This works regardless weather the
system uses `ttyS0`, `ttyAMA0`, `ttyMXC0`, or anything else. Finit
figures it out by querying sysfs: `/sys/class/tty/console/active`.
```conf
tty [12345] @console linux noclear
```
Notice the optional `noclear`, `nowait`, and `nologin` flags. The
latter is for skipping the login process entirely. For more information,
see [doc/config.md](doc/config.md#syntax).
**Runlevels**
Support for SysV init-style [runlevels][5] is available, in the same
minimal style as everything else in Finit. The `[2345]` syntax can be
applied to service, task, run, and TTY stanzas.
Reserved runlevels are 0 and 6, halt and reboot, respectively just like
SysV init. Runlevel 1 can be configured freely, but is recommended to
be kept as the system single-user runlevel since Finit will not start
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(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.
**Plugins**
Plugins can *extend* the functionality of Finit and *hook into* the
different stages of the boot process and at runtime. Plugins are
written in C and compiled into a dynamic library loaded automatically by
finit at boot. A basic set of plugins are bundled in the `plugins/`
directory.
Capabilities:
- **Hooks**
Hook into the boot at predefined points to extend Finit
- **I/O**
Listen to external events and control Finit behavior/services
Extensions and functionality not purely related to what an `/sbin/init`
needs to start a system are available as a set of plugins that either
hook into the boot process or respond to various I/O.
For more information, see [doc/plugins.md](doc/plugins.md).
**Automatic Reload**
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.
For some use-cases the extra step of calling `initctl reload` creates an
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.
Runparts & /etc/rc.local
------------------------
At the end of the boot, when all bootstrap (`S`) tasks and services have
started, but not networking, Finit calls its built-in [run-parts(8)][]
command on any configured `runparts <DIR>` directory. This happens just
before changing to the configured runlevel (default 2). (Networking is
enabled just prior to changing from single user mode.)
```shell
runparts /etc/rc.d/
```
Right after the runlevel change when all services have started properly,
`/etc/rc.local` is called.
No configuration stanza in `/etc/finit.conf` is required for `rc.local`.
If it exists and is an executable shell script Finit calls it at the very
end of the boot, before calling the `HOOK_SYSTEM_UP`. See more on hooks
in [doc/plugins.md](doc/plugins.md#hooks), and about the system bootstrap
in [doc/bootstrap.md](doc/bootstrap.md).
Runlevels
---------
Basic support for [runlevels][5] is included in Finit from v1.8. By
default all services, tasks, run commands and TTYs listed without a set
of runlevels get a default set `[234]` assigned. The default runlevel
after boot is 2.
Finit supports runlevels 0-9, and S, with 0 reserved for halt, 6 reboot
and S for services to only run at bootstrap. Runlevel 1 is the single
user level, where usually no networking is enabled. In Finit this is
more of a policy for the user to define. Normally only runlevels 1-6
are used, and even more commonly, only the default runlevel is used.
To specify an allowed set of runlevels for a `service`, `run` command,
`task`, or `tty`, add `[NNN]` to your `/etc/finit.conf`, like this:
```
service [S12345] syslogd -n -x -- System log daemon
run [S] /etc/init.d/acpid start -- Starting ACPI Daemon
task [S] /etc/init.d/kbd start -- Preparing console
service [S12345] <pid/syslogd> klogd -n -x -- Kernel log daemon
tty [12345] /dev/tty1
tty [2] /dev/tty2
tty [2] /dev/tty3
tty [2] /dev/tty4
tty [2] /dev/tty5
tty [2] /dev/tty6
```
In this example syslogd is first started, in parallel, and then acpid is
called using a conventional SysV init script. It is called with the run
command, meaning the following task command to start the kbd script is
not called until the acpid init script has fully completed. Then the
keyboard setup script is called in parallel with klogd as a monitored
service.
Again, tasks and services are started in parallel, while run commands
are called in the order listed and subsequent commands are not started
until a run command has completed. Also, task and run commands are run
in a shell, so pipes and redirects can be used.
The following examples illustrate this. Bootstrap task and run commands
are also removed when they have completed, `initctl show` will not list
them.
```
task [S] echo "foo" | cat >/tmp/bar
run [S] echo "$HOME" >/tmp/secret
```
Switching between runlevels can be done by calling init with a single
argument, e.g. <kbd>init 5</kbd>, or using `initctl runlevel 5`, both
switch to runlevel 5. When changing runlevels Finit also automatically
reloads all `.conf` files in the `/etc/finit.d/` directory. So if you
want to set a new system config, switch to runlevel 1, change all config
files in the system, and touch all `.conf` files in `/etc/finit.d`
before switching back to the previous runlevel again — that way Finit
can both stop old services and start any new ones for you, without
rebooting the system.
Rebooting & Halting
-------------------
Traditionally, rebooting and halting a UNIX system is done by changing
its runlevel. Finit comes with its own tooling providing: `shutdown`,
`reboot`, `poweroff`, and `suspend`, but also the `initctl` tool,
detailed in the next section.
For compatibility reasons Finit listens to the same set of signals as
BusyBox init. This is not 100% compatible with SysV init, but clearly
the more common combination for Finit. For more details, see
[doc/signals.md](doc/signals.md).
Commands & Status
-----------------
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.
```
alpine:~# initctl help
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
-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
-h, --help This help text
Commands:
debug Toggle Finit (daemon) debug
help This help text
version Show Finit 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 condition +usr/COND
cond clear <COND> Clear (deassert) user-defined condition -usr/COND
cond status Show condition status, default cond command
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 by name (SIGHUP or restart)
restart <NAME>[:ID] Restart (stop/start) service by name
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
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
```
For services *not* supporting `SIGHUP` the `<!>` notation in the .conf
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.
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 [S12345----] Kernel log daemon
1512 ntpd running [--2345----] NTP daemon
1473 syslogd running [S12345----] 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 [S12345----] klogd -n $KLOGD_OPTS
1512 ntpd running [--2345----] ntpd -n $NTPD_OPTS
1473 syslogd running [S12345----] 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
```
Requirements
------------
Finit is capable of running on both desktop/server systems with udev and
embedded systems that usually come with BusyBox mdev. Some systems have
systemd-udev or eudev today instead of the original udev, Finit probes
for all of them at runtime and expects `/dev/` to be a writable file
system using `devtmpfs`. It is also possible to run on a statically set
up `/dev` if needed. It is however not a good idea to have both udev
and mdev installed at the same time, this will lead to unpredictable
results.
At boot Finit calls either `mdev` or `udevd` to populate `/dev`, this is
done slightly differently and on systems with udev you might want to add
the following one-shot task early in your `/etc/finit.conf`:
```conf
run [S] udevadm settle --timeout=120 -- Waiting for udev
```
Finit has a built-in Getty for TTYs, but requires a working `/bin/login`
or `/bin/sh`, if no TTYs are configured in `/etc/finit.conf`.
For a fully operational system `/var`, `/run` and `/tmp` must be set up
properly in `/etc/fstab` -- which is iterated over at boot.
Origin & References
-------------------
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].
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
[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/
[run-parts(8)]: https://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
[original finit]: http://helllabs.org/finit/
[EeePC fastinit]: https://web.archive.org/web/20071208212450/http://wiki.eeeuser.com/boot_process:the_boot_process [EeePC fastinit]: https://web.archive.org/web/20071208212450/http://wiki.eeeuser.com/boot_process:the_boot_process
[Claudio Matsuoka]: https://github.com/cmatsuoka [Claudio Matsuoka]: https://github.com/cmatsuoka
[Joachim Wiberg]: https://troglobit.com
[License]: https://en.wikipedia.org/wiki/MIT_License [License]: https://en.wikipedia.org/wiki/MIT_License
[License Badge]: https://img.shields.io/badge/License-MIT-teal.svg [License Badge]: https://img.shields.io/badge/License-MIT-teal.svg
[Release]: https://github.com/finit-project/finit/releases [GitHub]: https://github.com/troglobit/finit/actions/workflows/build.yml/
[Release Badge]: https://img.shields.io/github/v/release/finit-project/finit [GitHub Status]: https://github.com/troglobit/finit/actions/workflows/build.yml/badge.svg
[GitHub]: https://github.com/finit-project/finit/actions/workflows/build.yml/
[GitHub Status]: https://github.com/finit-project/finit/actions/workflows/build.yml/badge.svg
[Coverity Scan]: https://scan.coverity.com/projects/3545 [Coverity Scan]: https://scan.coverity.com/projects/3545
[Coverity Status]: https://scan.coverity.com/projects/3545/badge.svg [Coverity Status]: https://scan.coverity.com/projects/3545/badge.svg
[br2-finit-demo]: https://github.com/finit-project/br2-finit-demo
+32 -189
View File
@@ -1,25 +1,21 @@
AC_INIT([Finit], [4.16], [https://github.com/finit-project/finit/issues], AC_INIT(Finit, 4.3-dev, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/finit.html)
[finit], [https://http://finit-project.github.io/])
AC_CONFIG_AUX_DIR(aux) AC_CONFIG_AUX_DIR(aux)
AM_INIT_AUTOMAKE([1.11 foreign subdir-objects]) AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
AM_SILENT_RULES([yes]) AM_SILENT_RULES([yes])
AC_CONFIG_SRCDIR([src/finit.c]) AC_CONFIG_SRCDIR([src/finit.c])
AC_CONFIG_HEADERS([config.h]) AC_CONFIG_HEADER([config.h])
AC_CONFIG_FILES([Makefile AC_CONFIG_FILES([Makefile
contrib/Makefile contrib/Makefile
contrib/alpine/Makefile contrib/alpine/finit.d/Makefile contrib/alpine/finit.d/available/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/void/Makefile contrib/void/finit.d/Makefile contrib/void/finit.d/available/Makefile contrib/void/Makefile contrib/void/finit.d/Makefile contrib/void/finit.d/available/Makefile
doc/Makefile doc/config/Makefile doc/Makefile
libsystemd/Makefile libsystemd/libsystemd.pc
man/Makefile man/Makefile
plugins/Makefile plugins/Makefile
src/Makefile src/Makefile
system/Makefile system/10-hotplug.conf
test/test.env test/Makefile test/test.env test/Makefile
test/lib/Makefile test/src/Makefile test/tenv/Makefile test/common/Makefile])
tmpfiles.d/Makefile])
# Older versions of autoconf (<2.58) do not have AC_CONFIG_MACRO_DIR() # Older versions of autoconf (<2.58) do not have AC_CONFIG_MACRO_DIR()
#m4_include([m4/plugin.m4]) #m4_include([m4/plugin.m4])
@@ -36,8 +32,9 @@ AC_PROG_INSTALL
AC_PROG_MKDIR_P AC_PROG_MKDIR_P
# Configuration. # Configuration.
AC_CHECK_HEADERS([termios.h sys/ioctl.h mntent.h sys/sysmacros.h]) AC_HEADER_STDC
AC_CHECK_FUNCS([strstr getopt getmntent getmntent_r]) AC_CHECK_HEADERS([fstaby.h termios.h sys/ioctl.h])
AC_CHECK_FUNCS([strstr getopt getfsenty])
# Check for uint[8,16,32]_t # Check for uint[8,16,32]_t
AC_TYPE_UINT8_T AC_TYPE_UINT8_T
@@ -48,8 +45,8 @@ AC_TYPE_UINT32_T
PKG_PROG_PKG_CONFIG PKG_PROG_PKG_CONFIG
# Check for required libraries # Check for required libraries
PKG_CHECK_MODULES([uev], [libuev >= 2.4.1]) PKG_CHECK_MODULES([uev], [libuev >= 2.2.0])
PKG_CHECK_MODULES([lite], [libite >= 2.6.1]) PKG_CHECK_MODULES([lite], [libite >= 2.2.0])
# Check for configured Finit features # Check for configured Finit features
AC_ARG_ENABLE(auto_reload, AC_ARG_ENABLE(auto_reload,
@@ -68,24 +65,12 @@ AC_ARG_ENABLE(fsckfix,
AS_HELP_STRING([--enable-fsckfix], [Run fsck fix mode (options: -yf) on filesystems listed in /etc/fstab]),,[ AS_HELP_STRING([--enable-fsckfix], [Run fsck fix mode (options: -yf) on filesystems listed in /etc/fstab]),,[
enable_fsckfix=no]) enable_fsckfix=no])
AC_ARG_ENABLE(cgroup,
AS_HELP_STRING([--disable-cgroup], [Disable cgroup v2 support, default: autodetect from /sys/fs/cgroup]),,[
enable_cgroup=yes])
AC_ARG_ENABLE(libcap,
AS_HELP_STRING([--disable-libcap], [Disable Linux capabilities support]),,[
enable_libcap=yes])
AC_ARG_ENABLE(redirect, AC_ARG_ENABLE(redirect,
AS_HELP_STRING([--disable-redirect], [Disable redirection of service output to /dev/null]),,[ AS_HELP_STRING([--disable-redirect], [Disable redirection of service output to /dev/null]),,[
enable_redirect=yes]) enable_redirect=yes])
AC_ARG_ENABLE(kernel_logging,
AS_HELP_STRING([--disable-kernel-logging], [Disable kernel logging to console (use 'quiet' instead!]),,[
enable_kernel_logging=yes])
AC_ARG_ENABLE(logrotate, AC_ARG_ENABLE(logrotate,
AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp]),,[ AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp, default enabled]),,[
enable_logrotate=yes]) enable_logrotate=yes])
AC_ARG_ENABLE(doc, AC_ARG_ENABLE(doc,
@@ -96,37 +81,21 @@ AC_ARG_ENABLE(contrib,
AS_HELP_STRING([--disable-contrib], [Disable build and install of contrib section]),,[ AS_HELP_STRING([--disable-contrib], [Disable build and install of contrib section]),,[
enable_contrib=yes]) enable_contrib=yes])
AC_ARG_ENABLE([rescue],
AS_HELP_STRING([--disable-rescue], [Disable potentially unsafe rescue mode]),,
[enable_rescue=yes])
# Check for extra plugins to enable # Check for extra plugins to enable
AC_ARG_ENABLE(all_plugins, enable_all_plugins=auto
AS_HELP_STRING([--enable-all-plugins], [Enable all plugins, default: auto]),
enable_all_plugins=$enableval, enable_all_plugins=auto)
AC_PLUGIN([alsa-utils], [no], [Save and restore ALSA sound settings using alsactl]) 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([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([modules-load], [no], [Scans /etc/modules-load.d for modules to load])
AC_PLUGIN([modprobe], [no], [Coldplug modules using modalias magic]) AC_PLUGIN([modprobe], [yes], [Coldplug modules using modalias magic])
AC_PLUGIN([resolvconf], [no], [Setup necessary files for resolvconf]) AC_PLUGIN([resolvconf], [no], [Setup necessary files for resolvconf])
AC_PLUGIN([x11-common], [no], [Console setup (for X)]) 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([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([hotplug], [yes], [Start udevd or mdev kernel event datamon])
AC_PLUGIN([rtc], [yes], [Save and restore RTC using hwclock]) 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([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([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 # Check for extra arguments or packages
AC_ARG_WITH([bash-completion-dir],
AS_HELP_STRING([--with-bash-completion-dir[=PATH]], [Directory to install Bash completion, default: auto]),
[bash_dir=$withval], [bash_dir=yes])
AC_ARG_WITH(fstab,
AS_HELP_STRING([--with-fstab=FILE], [System default fstab, default $sysconfdir/fstab]),
[fstab=$withval], [fstab=yes])
AC_ARG_WITH(heading, 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], [Heading for boot progress. Default: PRETTY_NAME from /etc/os-release, fallback to "Finit vX.YY"]),
[heading=$withval], [heading=yes]) [heading=$withval], [heading=yes])
@@ -156,7 +125,7 @@ AC_ARG_WITH(hostname,
[hostname=$withval], [hostname=yes]) [hostname=$withval], [hostname=yes])
AC_ARG_WITH(runlevel, 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]) [runlevel=$withval], [runlevel=yes])
AC_ARG_WITH(random-seed, AC_ARG_WITH(random-seed,
@@ -166,33 +135,10 @@ AC_ARG_WITH(random-seed,
AC_ARG_WITH(keventd, AC_ARG_WITH(keventd,
AS_HELP_STRING([--with-keventd], [Enable built-in keventd, default: no]),, [with_keventd=no]) AS_HELP_STRING([--with-keventd], [Enable built-in keventd, default: no]),, [with_keventd=no])
AC_ARG_WITH(sulogin,
AS_HELP_STRING([--with-sulogin@<:@=USER@:>@], [Enable built-in sulogin, optional USER to request password for (default root), default: no.]),[sulogin=$withval],[with_sulogin=no])
AC_ARG_WITH(watchdog, AC_ARG_WITH(watchdog,
AS_HELP_STRING([--with-watchdog@<:@=DEV@:>@], [Enable built-in watchdog, default: /dev/watchdog]), AS_HELP_STRING([--with-watchdog=[DEV]], [Enable built-in watchdog, default: /dev/watchdog]),
[watchdog=$withval], [with_watchdog=no watchdog=]) [watchdog=$withval], [with_watchdog=no watchdog=])
AC_ARG_WITH(libsystemd,
AS_HELP_STRING([--with-libsystemd], [Build replacement libsystemd library, default: yes]),
[with_libsystemd=$withval], [with_libsystemd=no])
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:SS", default "2000-01-01 00:00:00"]),
[rtc_date=$withval], [rtc_date=no])
AC_ARG_WITH(rtc-file,
AS_HELP_STRING([--with-rtc-file=FILE], [If RTC is missing, save and restore system clock from this file, default: no]),
[rtc_file=$withval], [rtc_file=no])
### Enable features ########################################################################### ### Enable features ###########################################################################
# Create config.h from selected features and fallback defaults # Create config.h from selected features and fallback defaults
@@ -202,22 +148,6 @@ AS_IF([test "x$enable_auto_reload" = "xyes"], [
AS_IF([test "x$enable_kernel_cmdline" = "xyes"], [ AS_IF([test "x$enable_kernel_cmdline" = "xyes"], [
AC_DEFINE(KERNEL_CMDLINE, 1, [Dumpster diving after init args from /proc/cmdline])]) AC_DEFINE(KERNEL_CMDLINE, 1, [Dumpster diving after init args from /proc/cmdline])])
AS_IF([test "x$enable_kernel_logging" = "xyes"], [
AC_DEFINE(KERNEL_LOGGING, 1, [Keep kernel warn/err logs to console])])
AS_IF([test "x$enable_cgroup" = "xyes"], [
AC_DEFINE(CGROUP2_ENABLED, 1, [Autodetect cgroup v2 support from /sys/fs/cgroup])])
AS_IF([test "x$enable_libcap" = "xyes"], [
AC_CHECK_LIB([cap], [cap_from_text], [
AC_DEFINE(HAVE_LIBCAP, 1, [Have libcap for Linux capabilities support])
LIBS="$LIBS -lcap"
], [
AC_MSG_WARN([libcap not found, capabilities support disabled])
enable_libcap=no
])
])
AS_IF([test "x$enable_fastboot" = "xyes"], [ AS_IF([test "x$enable_fastboot" = "xyes"], [
AC_DEFINE(FAST_BOOT, 1, [Skip fsck check on filesystems listed in /etc/fstab])]) AC_DEFINE(FAST_BOOT, 1, [Skip fsck check on filesystems listed in /etc/fstab])])
@@ -231,24 +161,9 @@ AS_IF([test "x$enable_redirect" = "xyes"], [
AS_IF([test "x$enable_logrotate" != "xno"], [ AS_IF([test "x$enable_logrotate" != "xno"], [
AC_DEFINE(LOGROTATE_ENABLED, 1, [Enable built-in rotation of /var/log/wtmp et al.])]) AC_DEFINE(LOGROTATE_ENABLED, 1, [Enable built-in rotation of /var/log/wtmp et al.])])
AS_IF([test "x$enable_rescue" != "xno"], [
AC_DEFINE([RESCUE_MODE], 1, [Define to enable support for rescue mode.])])
AM_CONDITIONAL(LOGROTATE, [test "x$enable_logrotate" = "xyes"]) AM_CONDITIONAL(LOGROTATE, [test "x$enable_logrotate" = "xyes"])
### With features ############################################################################## ### With features ##############################################################################
AS_IF([test "x$bash_dir" = "xyes"], [
PKG_CHECK_MODULES([BASH_COMPLETION], [bash-completion >= 2.0],
[BASH_DIR="$(pkg-config --variable=completionsdir bash-completion)"],
[BASH_DIR="$datadir/bash-completion/completions"])], [
BASH_DIR="$bash_dir"])
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$with_config" != "xno"], [
AS_IF([test "x$conf" = "xyes"], [ AS_IF([test "x$conf" = "xyes"], [
conf=$sysconfdir/finit.conf])]) conf=$sysconfdir/finit.conf])])
@@ -264,9 +179,10 @@ AC_DEFINE_UNQUOTED(FINIT_RCSD, "$rcsd_path", [Finit rcS.d/, default /etc/finit.d
AC_SUBST(FINIT_RCSD, "$rcsd_path") AC_SUBST(FINIT_RCSD, "$rcsd_path")
AS_IF([test "x$with_rc_local" != "xno"], [ AS_IF([test "x$with_rc_local" != "xno"], [
AS_IF([test "x$rclocal" = "xyes"], [rclocal=$sysconfdir/rc.local]) AS_IF([test "x$rclocal" = "xyes"], [
AC_EXPAND_DIR(rclocal_path, "$rclocal") rclocal=$sysconfdir/rc.local])])
AC_DEFINE_UNQUOTED(FINIT_RC_LOCAL, "$rclocal_path", [Compat SysV /etc/rc.local file to run last at boot.])]) AC_EXPAND_DIR(rclocal_path, "$rclocal")
AC_DEFINE_UNQUOTED(FINIT_RC_LOCAL, "$rclocal_path", [Compat SysV /etc/rc.local file to run last at boot.])
AS_IF([test "x$with_sysconfig" != "xno"], [ AS_IF([test "x$with_sysconfig" != "xno"], [
AS_IF([test "x$sysconfig" != "xdefault"], [ AS_IF([test "x$sysconfig" != "xdefault"], [
@@ -300,26 +216,8 @@ AS_IF([test "x$with_random_seed" != "xno"], [
AC_EXPAND_DIR(random_path, "$random_seed") AC_EXPAND_DIR(random_path, "$random_seed")
AC_DEFINE_UNQUOTED(RANDOMSEED, "$random_path", [Improve random at boot by seeding it with sth from before.])]) 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_UNQUOTED(RTC_TIMESTAMP_CUSTOM, "$rtc_date", [Custom RTC restore date, default: 2000-01-01 00:00])], [
rtc_date=""])
AS_IF([test "x$rtc_file" != "xno"], [
AS_IF([test "x$rtc_file" = "xyes"], [
rtc_file=/var/lib/misc/rtc])
AC_EXPAND_DIR(rtcfile_path, "$rtc_file")
AC_DEFINE_UNQUOTED(RTC_FILE, "$rtcfile_path", [Save and restore system time from this file if /dev/rtc is missing.])],[
AC_DEFINE_UNQUOTED(RTC_FILE, NULL)])
AS_IF([test "x$with_keventd" != "xno"], [with_keventd=yes]) AS_IF([test "x$with_keventd" != "xno"], [with_keventd=yes])
AS_IF([test "x$with_sulogin" != "xno"], [
AS_IF([test "x$sulogin" = "xyes"], [
sulogin=root])
with_sulogin=yes
AC_DEFINE_UNQUOTED(SULOGIN_USER, "$sulogin", [Built-in sulogin user, default: root])], [
sulogin=])
AS_IF([test "x$with_watchdog" != "xno"], [ AS_IF([test "x$with_watchdog" != "xno"], [
AS_IF([test "x$watchdog" = "xyes"], [ AS_IF([test "x$watchdog" = "xyes"], [
watchdog=/dev/watchdog]) watchdog=/dev/watchdog])
@@ -327,74 +225,31 @@ AS_IF([test "x$with_watchdog" != "xno"], [
AC_DEFINE_UNQUOTED(WDT_DEVNODE, "$watchdog", [Built-in watchdog device node])], [ AC_DEFINE_UNQUOTED(WDT_DEVNODE, "$watchdog", [Built-in watchdog device node])], [
watchdog=]) watchdog=])
AS_IF([test "x$with_libsystemd" != "xno"], [
AC_DEFINE(HAVE_LIBSYSTEMD, 1, [Build replacement libsystemd library support])])
AS_IF([test "x$enable_hook_scripts_plugin" != "xno"], [
AS_IF([test "x$hook_scripts_path" = "xyes"], [hook_scripts_path=$libexecdir/finit/hook])
AC_EXPAND_DIR(hook_scripts_path, "$hook_scripts_path")
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 # Control build with automake flags
AM_CONDITIONAL(BASH, [test "x$bash_dir" != "xno"]) AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"]) AM_CONDITIONAL(KEVENTD, [test "x$with_keventd" != "xno"])
AM_CONDITIONAL(KEVENTD, [test "x$with_keventd" != "xno"]) AM_CONDITIONAL(WATCHDOGD, [test "x$with_watchdog" != "xno"])
AM_CONDITIONAL(SULOGIN, [test "x$with_sulogin" != "xno"]) AM_CONDITIONAL(DOC, [test "x$enable_doc" = "xyes"])
AM_CONDITIONAL(WATCHDOGD, [test "x$with_watchdog" != "xno"]) AM_CONDITIONAL(CONTRIB, [test "x$enable_contrib" = "xyes"])
AM_CONDITIONAL(LIBSYSTEMD, [test "x$with_libsystemd" != "xno"])
AM_CONDITIONAL(DOC, [test "x$enable_doc" = "xyes"])
AM_CONDITIONAL(CONTRIB, [test "x$enable_contrib" = "xyes"])
AM_CONDITIONAL(TESTSERV, [test "x$enable_testserv_plugin" = "xyes"])
# Workaround for as-of-yet unreleased runstatedir support, planned for
# autoconf 2.70, which some major distros have backported.
AS_IF([test -z "$runstatedir"], runstatedir="$localstatedir/run")
AC_SUBST(runstatedir)
# Override default libdir, used for plugins and rescue.conf # Override default libdir, used for plugins and rescue.conf
pkglibdir=$libdir/finit pkglibdir=$libdir/finit
AC_SUBST(pkglibexecdir) AC_SUBST(pkglibexecdir)
AC_EXPAND_DIR(pkglibexecdir, "$libexecdir/finit") 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(finit_runpath, "$runstatedir/finit/system")
AC_DEFINE_UNQUOTED(FINIT_RUNPATH_, "$finit_runpath", [Finit runtime dynamic system services])
AC_EXPAND_DIR(plugin_path, "$pkglibdir/plugins") AC_EXPAND_DIR(plugin_path, "$libdir/finit/plugins")
AC_SUBST(plugin_path) AC_SUBST(plugin_path)
AC_DEFINE_UNQUOTED(PLUGIN_PATH, "$plugin_path", [Finit plugin path]) AC_DEFINE_UNQUOTED(PLUGIN_PATH, "$plugin_path", [Finit plugin path])
AC_EXPAND_DIR(tmpfiles_path, "$libdir/tmpfiles.d") AC_EXPAND_DIR(rescue_conf, "$libdir/finit/rescue.conf")
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_DEFINE_UNQUOTED(RESCUE_CONF, "$rescue_conf", [Finit rescue mode .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]) AC_DEFINE_UNQUOTED(SAMPLE_CONF, "$sample_conf", [Finit sameple.conf for initctl create])
AC_EXPAND_DIR(bash_completion_dir, "$BASH_DIR")
AC_SUBST(BASH_DIR, "$bash_completion_dir")
AS_IF([test "$heading" = ""], [heading="<DEFAULT>"]) AS_IF([test "$heading" = ""], [heading="<DEFAULT>"])
AS_IF([test "$heading" = "no"], [heading="<NONE>"]) 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>"])
# Generate all files # Generate all files
AC_OUTPUT AC_OUTPUT
@@ -402,16 +257,14 @@ cat <<EOF
------------------ Summary ------------------ ------------------ Summary ------------------
$PACKAGE_NAME version $PACKAGE_VERSION $PACKAGE_NAME version $PACKAGE_VERSION
Prefix................: $(eval echo $prefix) Prefix................: $prefix
Exec prefix...........: $(eval echo $exec_prefix) Exec prefix...........: $eprefix
Libdir................: $(eval echo $libdir)
Sysconfdir............: `eval echo $sysconfdir` Sysconfdir............: `eval echo $sysconfdir`
Localstatedir.........: `eval echo $localstatedir` Localstatedir.........: `eval echo $localstatedir`
Default fstab.........: `eval echo $fstab`
Finit config file.....: $conf_path Finit config file.....: $conf_path
Finit config.d path...: $rcsd_path Finit config.d path...: $rcsd_path
Finit plugin path.....: $plugin_path Finit plugin path.....: $plugin_path
Compat rc.local path..: `eval echo $rclocal` Compat rc.local path..: $rclocal_path
System environment....: ${sysconfig_path:-${sysconfig}} System environment....: ${sysconfig_path:-${sysconfig}}
Random seed path......: $random_path Random seed path......: $random_path
C Compiler............: $CC $CFLAGS $CPPFLAGS $LDFLAGS $LIBS C Compiler............: $CC $CFLAGS $CPPFLAGS $LDFLAGS $LIBS
@@ -420,26 +273,16 @@ cat <<EOF
Behavior: Behavior:
Boot heading..........: $heading Boot heading..........: $heading
Plugins...............: $plugins Plugins...............: $plugins
RTC restore date......: $RTC_DATE
RTC fallback file.....: $rtc_file
Optional features: Optional features:
Install doc/..........: $enable_doc Install doc/..........: $enable_doc
Install contrib/......: $enable_contrib Install contrib/......: $enable_contrib
Bash completion.......: $bash_completion_dir
Built-in keventd......: $with_keventd Built-in keventd......: $with_keventd
Built-in sulogin......: $with_sulogin $sulogin
Built-in watchdogd....: $with_watchdog $watchdog Built-in watchdogd....: $with_watchdog $watchdog
Built-in logrotate....: $enable_logrotate Built-in logrotate....: $enable_logrotate
Replacement libsystemd: $with_libsystemd
Use cgroup v2.........: $enable_cgroup
Use libcap............: $enable_libcap
Parse kernel cmdline..: $enable_kernel_cmdline
Keep kernel logging...: $enable_kernel_logging
Skip fsck check.......: $enable_fastboot Skip fsck check.......: $enable_fastboot
Run fsck fix mode.....: $enable_fsckfix Run fsck fix mode.....: $enable_fsckfix
Redirect output.......: $enable_redirect Redirect output.......: $enable_redirect
Rescue mode...........: $enable_rescue
Default hostname......: $hostname Default hostname......: $hostname
Default group.........: $group Default group.........: $group
Default runlevel......: $runlevel Default runlevel......: $runlevel
-5
View File
@@ -3,8 +3,3 @@ bin_SCRIPT = service
docsdir := @docdir@/contrib docsdir := @docdir@/contrib
docs_DATA = README.md finit.conf procmon.sh docs_DATA = README.md finit.conf procmon.sh
EXTRA_DIST = $(docs_DATA) EXTRA_DIST = $(docs_DATA)
if BASH
bashdir = $(BASH_DIR)
dist_bash_DATA = initctl
endif
-1
View File
@@ -6,7 +6,6 @@ install and try out Finit on various Linux distributions.
* [Alpine](alpine/) * [Alpine](alpine/)
* [Debian](debian/) * [Debian](debian/)
* [Void](void/)
If you have ideas on how to simplify, extend, or even add new example If you have ideas on how to simplify, extend, or even add new example
configurations for other distributions you are most welcome! :) configurations for other distributions you are most welcome! :)
+2 -5
View File
@@ -1,8 +1,5 @@
HowTo: Finit on Alpine Linux 3.4...3.19 HowTo: Finit on Alpine Linux 3.4-3.6
======================================= ====================================
> [!TIP]
> https://troglobit.com/post/2021-02-12-alpine-linux-with-finit/
HowTo use Finit to boot an [Alpine Linux][] system. It is assumed that HowTo use Finit to boot an [Alpine Linux][] system. It is assumed that
the user has already installed make, a compiler, C library header files, the user has already installed make, a compiler, C library header files,
+3 -2
View File
@@ -17,8 +17,8 @@ PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig ./configure \
--prefix=/usr --exec-prefix= \ --prefix=/usr --exec-prefix= \
--sysconfdir=/etc --localstatedir=/var \ --sysconfdir=/etc --localstatedir=/var \
--enable-dbus-plugin --enable-x11-common-plugin \ --enable-dbus-plugin --enable-x11-common-plugin \
--enable-alsa-utils-plugin --without-watchdog \ --enable-alsa-utils-plugin --with-watchdog \
--with-keventd --with-sulogin --with-keventd
echo echo
echo "*** Building ..." echo "*** Building ..."
@@ -35,3 +35,4 @@ fi
echo echo
echo "*** Done" echo "*** Done"
echo echo
+2 -1
View File
@@ -1,7 +1,8 @@
SUBDIRS = available SUBDIRS = available
docsdir := @docdir@/contrib/alpine/finit.d docsdir := @docdir@/contrib/alpine/finit.d
d_LINKS = acpid.conf crond.conf dropbear.conf getty.conf \ d_LINKS = acpid.conf crond.conf dropbear.conf getty.conf \
keymap.conf modules.conf ntpd.conf syslogd.conf keymap.conf modules.conf ntpd.conf \
klogd.conf syslogd.conf
install-exec-hook: install-exec-hook:
@$(MKDIR_P) $(DESTDIR)$(docsdir)/available @$(MKDIR_P) $(DESTDIR)$(docsdir)/available
+1 -1
View File
@@ -1,4 +1,4 @@
docsdir := @docdir@/contrib/alpine/finit.d/available docsdir := @docdir@/contrib/alpine/finit.d/available
docs_DATA = acpid.conf crond.conf dropbear.conf getty.conf keymap.conf \ docs_DATA = acpid.conf crond.conf dropbear.conf getty.conf keymap.conf \
lxdm.conf modules.conf ntpd.conf syslogd.conf watchdog.conf lxdm.conf modules.conf ntpd.conf syslog.conf watchdog.conf
EXTRA_DIST = $(docs_DATA) EXTRA_DIST = $(docs_DATA)
@@ -4,4 +4,4 @@
#module evdev #module evdev
#module mousedev #module mousedev
#module 8139cp #module 8139cp
#module softdog module softdog
+29 -35
View File
@@ -1,53 +1,45 @@
#!/bin/sh #!/bin/sh
if [ "$(id -u)" != "0" ]; then if [ "x`id -u`" != "x0" ]; then
printf "\n\e[1m*** This script must run as root\e[0m\n\n" echo
echo "*** This script must run as root"
echo
exit 1 exit 1
fi fi
# shellcheck disable=SC3037,SC3045,SC2154
yorn()
{
printf "\e[1m> %s (y/N)?\e[0m " "$*"
read -rn1 yorn
echo
if [ "$yorn" = "y" ] || [ "$yorn" = "Y" ]; then
return 0
fi
return 1
}
# Adjust base directory # Adjust base directory
if grep -q contrib/alpine Makefile 2>/dev/null; then grep -q alpine Makefile 2>/dev/null
if [ $? -eq 0 ]; then
cd ../.. cd ../..
fi elif [ ! -e configure.ac ]; then
echo "*** Please run this script from the Finit base directory."
if [ ! -e configure.ac ]; then
printf "\n\e[1m*** Please run this script from the Finit base directory.\e[0m\n"
exit 1 exit 1
fi fi
printf "\n\e[1mInstall Finit on Alpine Linux\n" echo
printf "========================================================================\e[0m\n" echo "*** Install Finit on Alpine Linux"
printf "/sbin/finit - PID 1\n" echo "========================================================================"
printf "/lib/finit/plugins/* - All enabled Finit plugins\n" echo "/sbin/finit - PID 1"
printf "/etc/finit.conf - Finit configuration file\n" echo "/lib/finit/plugins/* - All enabled Finit plugins"
printf "/etc/finit.d/ - Finit services\n" echo "/etc/finit.conf - Finit configuration file"
echo "/etc/finit.d/ - Finit services"
echo
read -p "Do you want to continue (y/N)? " yorn
if yorn "Do you want to continue"; then if [ "x$yorn" = "xy" -o "x$yorn" = "xY" ]; then
printf "\n\e[1m*** Installing Finit files ...\e[0m\n" echo
echo "*** Installing Finit files ..."
make install make install
cd /usr/share/doc/finit/contrib/alpine || exit 1 cd /usr/share/doc/finit/contrib/alpine
for file in finit.conf rc.local; do for file in finit.conf rc.local; do
install -vbD $file /etc/$file install -vbD $file /etc/$file
done done
cp -va finit.d /etc/ cp -va finit.d /etc/
if yorn "Install Finit as the system default Init"; then read -p "*** Install Finit as the system default Init (y/N)? " yorn
printf "\e[1m*** Updating /sbin/init symlink --> finit ...\e[0m\n" if [ "x$yorn" = "xy" -o "x$yorn" = "xY" ]; then
cd /sbin || exit 1 echo "*** Updating /sbin/init symlink --> finit ..."
cd /sbin
rm init rm init
ln -s finit init ln -s finit init
@@ -56,8 +48,10 @@ if yorn "Do you want to continue"; then
ln -s reboot shutdown ln -s reboot shutdown
ln -s reboot suspend ln -s reboot suspend
fi fi
printf "\n\e[1m*** Done\e[0m\n" echo "*** Done"
echo echo
else else
printf "\n\e[1m*** Aborting install.\e[0m\n\n" echo
echo "*** Aborting install."
echo
fi fi
+3 -5
View File
@@ -20,9 +20,8 @@ tools pre-systemd work as intended.
root@debian:~# apt install initscripts console-setup root@debian:~# apt install initscripts console-setup
> [!TIP] > **Note:** as of Debian 11 (Bullseye), libuev and libite are part of
> As of Debian 11 (Bullseye), libuev and libite are part of the main > the main section of Debian. So just install the -dev packages :)
> section of Debian. So just install the -dev packages :)
The following script can then be used to configure, build, install and The following script can then be used to configure, build, install and
set up your system to run Finit: set up your system to run Finit:
@@ -48,8 +47,7 @@ comands to `initctl`, followed by `reload` to activate your changes.
You can also use a standard [/etc/rc.local](rc.local) for one-shot tasks You can also use a standard [/etc/rc.local](rc.local) for one-shot tasks
and initialization like keyboard language etc. and initialization like keyboard language etc.
> [!NOTE] > **NOTE:** X Window system, you may need to `sudo apt install elogind`
> For the X Window system, you may need to `sudo apt install elogind`
> (Bullseye and later), followed by `initctl reload` to activate it (it > (Bullseye and later), followed by `initctl reload` to activate it (it
> is enabled by default), and logout/login again. The elogind daemon > is enabled by default), and logout/login again. The elogind daemon
> ensures a regular non-root user can start and interact with an X > ensures a regular non-root user can start and interact with an X
+3
View File
@@ -59,3 +59,6 @@ else
echo "*** Use 'sudo contrib/debian/install.sh' later to install Finit" echo "*** Use 'sudo contrib/debian/install.sh' later to install Finit"
echo echo
fi fi
@@ -1,4 +1,4 @@
# On some systems, bootstrap can be really quick and cause elogind # On some systems, bootstrap can be really quick and cause elogind
# to not start before a user has managed to log in. To prevent # 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 # this, add <pid/elogind> as condition to your TTYs in getty.conf
service [2345] <pid/syslogd> /usr/libexec/elogind -- Login manager service [2345] <pid/syslogd> /lib/elogind/elogind -- Login manager
-141
View File
@@ -1,141 +0,0 @@
_cond()
{
initctl -pt cond dump | awk '{print $4}' | sed 's/<\(.*\)>/\1/'
}
_ident()
{
if [ -n "$1" ]; then
initctl ident | grep -q $1
else
initctl ident
fi
}
_svc()
{
initctl ls -pt | grep $1 | sed "s/.*\/\(.*\)/\1/g" | sort -u
}
_enabled()
{
echo "$(_svc enabled)"
}
_available()
{
all=$(mktemp)
ena=$(mktemp)
echo "$(_svc available)" >$all
echo "$(_svc enabled)" >$ena
grep -v -f $ena $all
rm $all $ena
}
# Determine first non-option word. Usually the command
_firstword() {
local firstword i
firstword=
for ((i = 1; i < ${#COMP_WORDS[@]}; ++i)); do
if [[ ${COMP_WORDS[i]} != -* ]]; then
firstword=${COMP_WORDS[i]}
break
fi
done
echo $firstword
}
# Determine last non-option word. Uusally a sub-command
_lastword() {
local lastword i
lastword=
for ((i = 1; i < ${#COMP_WORDS[@]}; ++i)); do
if [[ ${COMP_WORDS[i]} != -* ]] && [[ -n ${COMP_WORDS[i]} ]] && [[ ${COMP_WORDS[i]} != $cur ]]; then
lastword=${COMP_WORDS[i]}
fi
done
echo $lastword
}
_initctl()
{
local cur command
cur=${COMP_WORDS[COMP_CWORD]}
prev="${COMP_WORDS[COMP_CWORD-1]}"
firstword=$(_firstword)
lastword=$(_lastword)
commands="status cond debug help kill ls log version list enable \
disable touch show cat edit create delete reload start \
stop restart signal cgroup ps top plugins runlevel reboot \
halt poweroff suspend utmp"
cond_cmds="set get clear status dump"
cond_types="hook net pid service task usr"
signals="int term hup stop tstp cont usr1 usr2 pwr"
options="-b --batch \
-c --create \
-d --debug \
-f --force \
-h --help \
-j --json \
-n --noerr \
-1 --once \
-p --plain \
-q --quiet \
-t --no-heading \
-v --verbose \
-V --version"
case "${firstword}" in
enable)
COMPREPLY=($(compgen -W "$(_available)" -- $cur))
;;
disable|touch)
COMPREPLY=($(compgen -W "$(_enabled)" -- $cur))
;;
show|cat|edit|delete)
COMPREPLY=($(compgen -W "$(_svc .)" -- $cur))
;;
start|stop|restart|log|status)
COMPREPLY=($(compgen -W "$(_ident)" -- $cur))
;;
signal|kill)
if $(_ident "${prev}"); then
COMPREPLY=($(compgen -W "$signals" -- $cur))
else
COMPREPLY=($(compgen -W "$(_ident)" -- $cur))
fi
;;
cond)
case "${lastword}" in
set|clear)
compopt -o nospace
COMPREPLY=($(compgen -W "usr/" -- $cur))
;;
get)
COMPREPLY=($(compgen -W "$(_cond)" -- $cur))
;;
dump)
COMPREPLY=($(compgen -W "$cond_types" -- $cur))
;;
*)
COMPREPLY=($(compgen -W "$cond_cmds" -- $cur))
;;
esac
;;
*)
COMPREPLY=($(compgen -W "$commands" -- $cur))
;;
esac
if [[ $cur == -* ]]; then
COMPREPLY=($(compgen -W "$options" -- $cur))
fi
}
complete -F _initctl initctl
+2 -1
View File
@@ -18,7 +18,7 @@ PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig ./configure \
--sysconfdir=/etc --localstatedir=/var \ --sysconfdir=/etc --localstatedir=/var \
--enable-dbus-plugin --enable-x11-common-plugin \ --enable-dbus-plugin --enable-x11-common-plugin \
--enable-alsa-utils-plugin --with-watchdog \ --enable-alsa-utils-plugin --with-watchdog \
--with-keventd --with-sulogin --with-keventd
echo echo
echo "*** Building ..." echo "*** Building ..."
@@ -35,3 +35,4 @@ fi
echo echo
echo "*** Done" echo "*** Done"
echo echo
+4 -11
View File
@@ -1,11 +1,4 @@
SUBDIRS = config docsdir := @docdir@/doc
EXTRA_DIST = AUTHORS ChangeLog.md docs_DATA = config.md conditions.md distro.md plugins.md \
service.md signals.md svc-machine.png cmdline.md
docsdir := @docdir@/doc EXTRA_DIST = $(docs_DATA)
dist_docs_DATA = build.md cmdline.md commands.md conditions.md \
distro.md example.md features.md index.md initctl.md \
keventd.md plugins.md requirements.md runlevels.md \
runparts.md service.md signals.md state-machine.md \
watchdog.md
dist_docs_DATA += img/logo.png img/svc-machine.png img/svc-machine.svg \
img/alpine-screenshot2.png
+1 -1
View File
@@ -1 +1 @@
index.md config.md
+57
View File
@@ -0,0 +1,57 @@
Bootstrap
=========
1. Prepare emergency shell, if enabled
2. Set up initial signal handlers
3. Set up default $PATH early
4. Mount `/proc` and `/sys`
5. Check kernel command line for `debug` to figure out log level
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
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
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
18. Load kernel params from `/etc/sysctl.d/*.conf`, `/etc/sysctl.conf`
et al. (Supports all locations that SysV init does.), handled by
`procps` plugin
19. Start all 'S' runlevel tasks and services
20. Bring up loopback interface and all `/etc/network/interfaces`, if
the `.conf` setting `network <SCRIPT>` is set, it is called instead
21. Call 3rd level hooks, `HOOK_NETWORK_UP`
22. If `runparts <DIR>` is set, [run-parts(8)][] is called on `<DIR>`
23. Switch to the configured runlevel from `/etc/finit.conf`, default 2.
At every runlevel change all `*.conf` files in `/etc/finit.d/` are
(re)loaded and new services, tasks, and blocking run commands are
started. Provided they are allowed in the new runlevel and all of
their conditions, if any, are set.
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
In (19) and (23) tasks and services defined in `/etc/finit.conf` and
`/etc/finit.d/*.conf` are started.
Notice the seven hook points that are called at various point in the
bootstrap process. This is where plugins can extend the boot in any
way they please. There are other hook points available, for more on
this, see [plugins.md](plugins.md).
For instance, at `HOOK_BASEFS_UP` a plugin could read an XML file from a
USB stick, convert/copy its contents to the system's `/etc/` directory,
well before all 'S' runlevel tasks are started. This could be used with
system images that are created read-only and all configuration is stored
on external media.
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
+37 -48
View File
@@ -1,5 +1,15 @@
Building Finit Building
============== ========
* [Introduction](#introduction)
* [Configure](#configure)
* [Example](#example)
* [Running](#running)
* [Debugging](#debugging)
Introduction
------------
Finit comes with a traditional configure script to control features and Finit comes with a traditional configure script to control features and
optional plugins to enable. It depends on two external libraries: optional plugins to enable. It depends on two external libraries:
@@ -7,21 +17,20 @@ optional plugins to enable. It depends on two external libraries:
- [libuEv][], the event loop - [libuEv][], the event loop
- [libite][] (-lite), much needed frog DNA - [libite][] (-lite), much needed frog DNA
> [!IMPORTANT] **NOTE:** Most free/open source software that uses `configure` default
> Most free/open source software packages that use `configure` default to install to `/usr/local`. However, some Linux distributions do no
> to install to `/usr/local`. However, some Linux distributions do no longer search that path for installed software, e.g. Fedora and Alpine
> longer search that path for installed software, e.g. Fedora and Alpine Linux. To get finit's configure script to find its dependencies you
> Linux. To get finit's configure script to find its dependencies you have to help the `pkg-config` tool a bit if you do not change the
> have to help the `pkg-config` tool a bit if you do not change the default prefix path:
> default prefix path:
> PKG_CONFIG_LIBDIR=/usr/local/lib/pkgconfig ./configure
> PKG_CONFIG_LIBDIR=/usr/local/lib/pkgconfig ./configure
The configure script checks for all dependencies, including the correct 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 required versions:
- libite v2.2.0, or later - libite v2.2.0
- libuEv v2.2.0, or later - libuEv v2.2.0
Configure Configure
@@ -45,7 +54,7 @@ Below are a few of the main switches to configure:
will be linked statically. will be linked statically.
* `--enable-kernel-cmdline`: Enable Finit pre-4.1 parsing of init args from * `--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 `/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 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-alsa-utils-plugin`: Enable the optional `alsa-utils.so` sound plugin.
@@ -56,20 +65,8 @@ Below are a few of the main switches to configure:
* `--enable-x11-common-plugin`: Enable the optional X Window `x11-common.so` plugin. * `--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> 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 Example
------- -------
@@ -77,8 +74,8 @@ Example
First, unpack the archive: First, unpack the archive:
```shell ```shell
$ tar xf finit-4.3.tar.gz $ tar xf finit-4.1.tar.gz
$ cd finit-4.3/ $ cd finit-4.1/
``` ```
Then configure, build and install: Then configure, build and install:
@@ -86,7 +83,7 @@ Then configure, build and install:
```shell ```shell
$ ./configure --prefix=/usr --exec-prefix= \ $ ./configure --prefix=/usr --exec-prefix= \
--sysconfdir=/etc --localstatedir=/var \ --sysconfdir=/etc --localstatedir=/var \
--with-keventd --with-watchdog --with-keventd --with-watchdog
$ make $ make
. .
. .
@@ -94,7 +91,7 @@ $ make
$ DESTDIR=/tmp/finit make install $ 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-4.1.tar.gz][1] archive is unpacked to the
user's home directory, configured, built and installed to a temporary user's home directory, configured, built and installed to a temporary
staging directory. The environment variable `DESTDIR` controls the staging directory. The environment variable `DESTDIR` controls the
destination directory when installing, very useful for building binary destination directory when installing, very useful for building binary
@@ -107,11 +104,10 @@ Linux config to:
CONFIG_UEVENT_HELPER_PATH="/sbin/mdev" CONFIG_UEVENT_HELPER_PATH="/sbin/mdev"
> [!TIP] **Note:** If you run into problems starting Finit, take a look at
> If you run into problems starting Finit, take a look at `finit.c`. `finit.c`. One of the most common problems is a custom Linux kernel
> One of the most common problems is a custom Linux kernel build that build that lack `CONFIG_DEVTMPFS`. Another is too much cruft in the
> lack `CONFIG_DEVTMPFS`. Another is too much cruft in the system system `/etc/fstab`.
> `/etc/fstab`.
Running Running
@@ -150,24 +146,17 @@ enabled. The default Finit rescue mode configuration is installed into
By default the a root shell, without login, is started. By default the a root shell, without login, is started.
> [!IMPORTANT]
> In rescue mode `initctl` will not work, the same goes for `reboot`,
> `shutdown`, and `poweroff` commands, provided they are the Finit
> versions of these commands. Use the `-f` flag to force the action.
Debugging Debugging
--------- ---------
Edit, or append to, the kernel command line: remove `quiet` to enable 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 ```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 To debug startup issues, in particular issues with getty/login, add
the following to your Finit .conf file: the following to your Finit .conf file:
@@ -182,10 +171,10 @@ kernel usually reboots: `configure --enable-emergency-shell`. However,
the behavior of Finit is severely limited when this is enabled, so use the behavior of Finit is severely limited when this is enabled, so use
it only for debugging start up issues when Finit crashes. it only for debugging start up issues when Finit crashes.
> [!CAUTION] **NOTE:** Neither of these options should be enabled on production
> None of these options should be enabled on production systems since systems since they can potentially give a user root access.
> they can potentially give a user root access.
[1]: https://github.com/finit-project/finit/releases/download/4.3/finit-4.3.tar.gz
[1]: ftp://troglobit.com/finit/finit-4.1.tar.gz
[libuEv]: https://github.com/troglobit/libuev [libuEv]: https://github.com/troglobit/libuev
[libite]: https://github.com/troglobit/libite [libite]: https://github.com/troglobit/libite
+20 -89
View File
@@ -4,70 +4,19 @@ Tips & Tricks with the kernel cmdline
This document summarizes the different boot parameters that can be This document summarizes the different boot parameters that can be
passed on the Linux kernel command line. Not limited to Finit. passed on the Linux kernel command line. Not limited to Finit.
> [!IMPORTANT]
> Remember to use `--` to separate kernel parameters from parameters to
> init. E.g., `init=/sbin/finit -- finit.debug rescue`
The `bool` setting is one of `on, off, true false, 1, 0`. 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 * `debug`: Enable kernel debug. Debug messages are printed to the
console until Finit starts up, unless `loglevel=7` (below) is used. console until Finit starts up.
* `fsck.mode=<auto,force,skip>`, default: `auto`, unless built with
`configure --enable-fastboot`, in which case the default is `skip`
* `fsck.repair=<preen,yes,no>`, default: `preen`, unless built with
`configure --enable-fsckfix`, in which case the default is `yes`.
This configure option also sets `fsck.mode=force`, unless fastboot
is selected at the same time. I.e., the `--enable-fastboot` build
option overrides the `fsck.mode` default value.
* `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][rescue].
> [!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][rescue], factory, or
production test setups. Use the top-level configuration file
directive `rcsd /path/to/finit.d` to override the default rcS.d
directory.
* `finit.debug[=bool]`: Enable finit debug. This is operated * `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 * `finit.show_status[=bool]`: Control finit boot progress, including
alternate `fstab` to mount the file system from. Remember, this file banner.
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.status_style=<classic,modern>`: Set Finit boot progress style, * `finit.status_style=<classic,modern>`: Set Finit boot progress style,
when enabled. when enabled.
@@ -75,45 +24,27 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
* `init=/bin/sh`: Bypass system default init and tell kernel to start a * `init=/bin/sh`: Bypass system default init and tell kernel to start a
shell. Note, this shell is very limited and does not support shell. Note, this shell is very limited and does not support
signals and has no job control. Recommend using, and modifying, signals and has no job control. Recommend using, and modifying,
[`rescue` mode][rescue] instead. `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=SEC`: By default the kernel does not reboot after a kernel
panic. This setting will cause a kernel reboot after SEC seconds. panic. This setting will cause a kernel reboot after SEC seconds.
* `quiet`: Suppress kernel logging to console, except for warnings and * `quiet`: Suppress kernel logging to console, except for warnings and
errors. Also, see `loglevel` and `quiet` above. errors.
* `rescue`: Start [rescue/maintenance mode][rescue]. If your system * `rescue`: Start rescue/maintenance mode. If your system comes with
comes with the bundled `sulogin` program (Finit, or from util-linux, the bundled `sulogin` program (Finit, or from util-linux/Busybox),
or Busybox), you will be given a root login to a maintenance shell. you will be given a root login to a maintenance shell. However, if
However, if `sulogin` is missing, the file `/lib/finit/rescue.conf` `sulogin` is missing, the file `/lib/finit/rescue.conf` is read and
is read and the system booted in a limited fallback mode. the system booted in a limited fallback mode. See [config.md][]
for more information.
This option can be disabled with `configure --without-rescue` * `single`, or `S`: Single user mode, runlevel 1, in Finit. Useful to
debug problems with the regular runlevel. All services and TTYs in
**Note:** in this mode `initctl` will not work. Correct the problem `[1]` will be started, so a `tty [1] @console nologin` configuration
and use `reboot -f` to force reboot. presents you with a root console without login.
* `single`, or `S`: Overrides the configured runlevel (default: 2) to go
to after bootstrap by forcing it to runlevel 1, this is also known
as single user mode. Useful to debug startup problems. All services
and TTYs in `[1]` will be started, so a `tty [1] @console nologin`
configuration presents you with a root console without login.
* `1-9`, except `6`: override the configured `runlevel`. Like the `S`
and `rescue`, giving a single number on the kernel command line tells
Finit to ignore any `runlevel` in `/etc/finit.conf` as well as the
configure fallback `--with-runlevel=N` setting. Remember, `6` is the
reboot runlevel and is not permitted. Any other values are ignored.
For more on kernel boot parameters, see the man page [bootparam(7)][]. For more on kernel boot parameters, see the man page [bootparam(7)][].
[rescue]: config/rescue.md [config.md][]: config.md#rescue-mode
[bootparam(7)]: https://www.man7.org/linux/man-pages/man7/bootparam.7.html [bootparam(7)]: https://www.man7.org/linux/man-pages/man7/bootparam.7.html
-13
View File
@@ -1,13 +0,0 @@
Rebooting & Halting
===================
Traditionally, rebooting and halting a UNIX system is done by switching
to the corresponding runlevel (0 or 6). Over time this has changed and
Finit comes with its own tooling providing: `shutdown`, `reboot`,
`poweroff`, and `suspend`. These commands are also available from the
[`initctl`](initctl.md) tool.
For compatibility reasons Finit listens to the same set of signals as
BusyBox init. This is not 100% compatible with SysV init, but clearly
the more common combination for Finit. For more details, see the
[Signal](signals.md) section.
+45 -130
View File
@@ -1,8 +1,21 @@
Conditions Finit Conditions
========== ================
Conditions were added to Finit in v3 with the intention of providing a ![The service state machine](svc-machine.png "The service state machine")
mechanism for common synchronization problems. For example:
* [Introduction](#introduction)
* [Triggering](#triggering)
* [Built-in Conditions](#built-in--conditions)
* [Debugging](#debugging)
* [Internals](#internals)
Introduction
------------
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 service A to start before starting service B"*, or
- *"wait for basic network access to be available"* - *"wait for basic network access to be available"*
@@ -14,16 +27,6 @@ specified separated by comma. Multiple conditions are logically AND'ed
during evaluation, i.e. all conditions must be satisfied in order for a during evaluation, i.e. all conditions must be satisfied in order for a
service to run. service to run.
Two special prefixes can be used inside the angle brackets:
- `!` -- service does not support `SIGHUP` (noreload), or run/task
should not block runlevel changes (i.e., bootstrap)
- `~` -- propagate reload from this dependency, see below
Finit guarantees by default that all run/tasks run (at least) once
per runlevel. For most tasks this is a good default, for example
checking SSH host keys or loading keymap. However, for conditions
that are unlikely to happen it is not. (See example below.)
### Example ### Example
@@ -32,65 +35,22 @@ that are unlikely to happen it is not. (See example below.)
In this example the Network monitor daemon `netd` is not started until In this example the Network monitor daemon `netd` is not started until
both the `pid/setupd` *and* `pid/zebra` conditions are satisfied. A both the `pid/setupd` *and* `pid/zebra` conditions are satisfied. A
`pid/` condition is satisfied by the corresponding service's PID file `pid/` condition is satisfied by the corresponding service's PID file
being created, i.e., the service's default readiness notification. being created.
> [!IMPORTANT] **NOTE:** Conditions also stop services when a condition is no longer
> Conditions also stop services when a condition is no longer asserted. asserted. I.e., if the Zebra process above stops or restarts, netd
> I.e., if the `zebra` process above stops or restarts, `netd` will also will also stop or restart.
> stop or restart.
Another example is `dropbear`, it does not support `SIGHUP`, but we can
also see optional sourcing of arguments from an environment file:
service [2345789] <!> env:-/etc/default/dropbear dropbear -F -R $DROPBEAR_ARGS -- Dropbear SSH daemon
Finally, the weird "block runlevel changes" example. Here we see what
happens when Finit receives `SIGPWR`, sent from a power daemon like
[powstatd(8)][]. A condition is asserted and a user can set up their
own task to act on it. We do not want this task to block Finit from
moving to the next runlevel after bootstrap, so we set `<!>`:
task [S0123456789] <!sys/pwr/fail> name:pwrfail initctl poweroff -- Power failure, shutting down
Propagating Reload in Dependencies
-----------------------------------
By default, when a service reloads during `initctl reload`, dependent
services are paused (`SIGSTOP`) and simply resumed (`SIGCONT`) when the
condition is reasserted. This is correct for barrier-style dependencies
like `<pid/syslogd>`, where dependents just need syslogd running and do
not care if it reloads its config.
For services that need to react when their upstream reloads, the `~`
prefix propagates the reload from the dependency:
service <pid/svc_a> name:svc_b /sbin/svc_b -- Needs A (barrier)
service <!~pid/svc_b> name:svc_c /sbin/svc_c -- Propagate reload from B
Here, `<~pid/svc_b>` means: propagate a reload of `svc_b` to `svc_c`.
When `svc_b` reloads, `svc_c` will be restarted (because of `!`,
noreload) instead of merely resumed. If `svc_c` supported `SIGHUP`
(no `!` prefix), it would be sent `SIGHUP` instead.
This is similar to systemd's `PropagatesReloadTo=` directive, but
declared on the consumer side rather than the provider side.
Triggering Triggering
---------- ----------
Conditions are mainly triggered (asserted) by built-in plugins, e.g., Conditions are mainly triggered (asserted) by built-in plugins, e.g.,
`netlink.so` and `pidfile.so`, see below for built-in conditions. Finit
- `netlink.so`: provides `<net/...>` also supports user-defined conditions, sometimes referred to as static
- `pidfile.so`: provides `<pid/...>` or one-shot conditions. They live in the `<usr/...` namespace and are
- Cmdline `finit.cond=arg`: provides `<boot/arg>` constrained to a flat hierarchy without any sub-directories, unlike the
pidfile plugin, for instance.
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 User-defined conditions are controlled using the `initctl cond set` and
`initctl cond clear` commands: `initctl cond clear` commands:
@@ -100,8 +60,7 @@ User-defined conditions are controlled using the `initctl cond set` and
The purpose of user-defined conditions is to be able to start or stop The purpose of user-defined conditions is to be able to start or stop
services, or run/task jobs, on external site-dependent stimuli. services, or run/task jobs, on external site-dependent stimuli.
Example:
**Example:**
service [2345] <usr/foo> alarm --arg foo -- Foo alarm service [2345] <usr/foo> alarm --arg foo -- Foo alarm
@@ -119,49 +78,24 @@ on this, see [Internals](#internals).) Thus, after a reconfiguration it
is up to the "owner" of the condition to convey the new (or possibly is up to the "owner" of the condition to convey the new (or possibly
unchanged) state of it. unchanged) state of it.
Static (one-shot) conditions, like `usr/`, never enter the `flux` state. > **Note:** For `pid/` conditions it is expected that services "touch"
> or recreate their PID file on `SIGHUP`.
> [!IMPORTANT] Static (one-shot) conditions, like `usr/`, never enter the `flux` state.
> For `pid/` conditions it is expected that the service reassert, i.e.,
> "touch" or recreate, their PID file on `SIGHUP`. This can be done by
> calling `utimensat()` on the PID file. Provided, of course, that the
> service supports reloading on `SIGHUP`, otherwise it will be restarted
> by Finit when they instead exit on the signal. For such services, use
> `<!>` to tell Finit the service does not support `SIGHUP`.
Built-in Conditions Built-in Conditions
------------------- -------------------
Finit comes with a set of plugins for conditions: Finit comes with a set of plugins for conditions: `pidfile`, `netlink`,
`sys`, and `usr`. The `pidfile` plugin (recursively) watches `/run/`
- `devmon` (built-in) (recursively) for PID files created by the monitored services, and sets
- `netlink` a corresponding condition in the `pid/` namespace. Similarly, the
- `pidfile` `netlink` plugin provides basic conditions for when an interface is
- `sys` brought up/down and when a default route (gateway) is set, in the `net/`
- `usr` namespace. The `sys` and `usr` plugins monitor are passive condition
monitors where the action is provided by `keventd`, signal handlers,
The `devmon` (built-in) plugin monitors `/dev` and `/dev/dir` for device and in the case of `usr`, the end-user via the `initctl` tool
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`.
With the example listed above, finit does not start the `/sbin/netd` With the example listed above, finit does not start the `/sbin/netd`
daemon until `setupd` and `zebra` has started *and* created their PID daemon until `setupd` and `zebra` has started *and* created their PID
@@ -180,19 +114,14 @@ Built-in conditions:
- `net/<IFNAME>/exist` - `net/<IFNAME>/exist`
- `net/<IFNAME>/up` - `net/<IFNAME>/up`
- `net/<IFNAME>/running` - `net/<IFNAME>/running`
- `service/<NAME[:ID]>/<STATE>`
- `{run, task, sysv}/<NAME[:ID]>/{<STATE>, success, failure}`
- `sys/pwr/ac` - `sys/pwr/ac`
- `sys/pwr/fail` - `sys/pwr/fail`
- `sys/key/ctrlaltdel` - `sys/key/ctrlaltdel`
- `usr/foo` - `usr/foo`
- `boot/arg`
- `dev/node` and `dev/dir/node`
> [!NOTE] **Note:** `up` means administratively up, the interface flag `IFF_UP`.
> Here, `up` means administratively up, the interface flag `IFF_UP`. `running` is the `IFF_RUNNING` flag, meaning operatively up. The
> `running` is the `IFF_RUNNING` flag, meaning operatively up. The difference is that `running` tells if the NIC has link.
> difference is that `running` tells if the NIC has link.
Composition Composition
@@ -218,19 +147,14 @@ When Finit configuration files are changed and the `initctl reload`
command is called, it is expected of services to touch their PID files command is called, it is expected of services to touch their PID files
for Finit to reassert their conditions. for Finit to reassert their conditions.
Similarly, when a single service is reloaded with `initctl reload NAME`,
its conditions are cleared and reasserted, ensuring dependent services
are properly updated.
Daemons that don't create PID files, or fail to touch them on reload, Daemons that don't create PID files, or fail to touch them on reload,
can be worked around by using the `pid:/path/to/file.pid` syntax in can be worked around by using the `pid:/path/to/file.pid` syntax in
the service stanza for the daemon. It is far from optimal since any the service stanza for the daemon. It is far from optimal since any
synchronization of depending services may fail due to the daemon not synchronization of depending services may fail due to the daemon not
having reinitialized/created their IPC sockets, or similar. having reinitialized/created their IPC sockets, or similar.
> [!NOTE] > **Note:** in versions of Finit prior to v4, the PID conditions were
> In versions of Finit prior to v4, the PID conditions were called 'svc' > called 'svc' conditions, and they were far more complex.
> conditions, and they were far more complex.
Debugging Debugging
@@ -239,7 +163,7 @@ Debugging
If a service is not being started as it should, the problem might be 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 that one of its conditions is not in the expected state. Use the
command `initctl status` to inspect service status. Services in 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 In that situation, running `initctl cond show` reveals which of the
conditions that are not satisfied. Listed as `off` below. conditions that are not satisfied. Listed as `off` below.
@@ -293,8 +217,6 @@ A condition is always in one of three states:
All conditions that have not explicitly been set are interpreted as All conditions that have not explicitly been set are interpreted as
being in the `off` state. being in the `off` state.
![The service state machine](img/svc-machine.png "The service state machine")
When a reconfiguration is requested, Finit transitions all conditions to When a reconfiguration is requested, Finit transitions all conditions to
the `flux` state. As a result, services that depend on a condition are the `flux` state. As a result, services that depend on a condition are
sent `SIGSTOP`. Once the new state of the condition is asserted, the sent `SIGSTOP`. Once the new state of the condition is asserted, the
@@ -305,14 +227,7 @@ This STOP/CONT handling minimizes the number of unnecessary service
restarts that would otherwise occur because a depending service was sent restarts that would otherwise occur because a depending service was sent
`SIGHUP` for example. `SIGHUP` for example.
Services with the `~` prefix are an exception to this rule: when their
conditions return to `on` after being in `flux`, the reload is propagated
-- the service is reloaded (SIGHUP) or restarted (noreload `!`) instead
of simply being resumed.
Therefore, any plugin that supplies Finit with conditions must ensure Therefore, any plugin that supplies Finit with conditions must ensure
that their state is updated after each reconfiguration. This can be that their state is updated after each reconfiguration. This can be
done by binding to the `HOOK_SVC_RECONF` hook. For an example of how done by binding to the `HOOK_SVC_RECONF` hook. For an example of how
to do this, see `plugins/pidfile.c`. to do this, see `plugins/pidfile.c`.
[powstatd(8)]: https://manpages.ubuntu.com/manpages/trusty/en/man8/powstatd.8.html
+743
View File
@@ -0,0 +1,743 @@
Configuration
=============
* [Introduction](#introduction)
* [Service Environment](#service-environment)
* [Service Wrapper Scripts](#service-wrapper-scripts)
* [Cgroups](#cgroups)
* [Configuration File Syntax](#configuration-file-syntax)
* [Hostname](#hostname)
* [Kernel Modules](#kernel-modules)
* [Networking](#networking)
* [Resource Limits](#resource-limits)
* [Runlevels](#runlevels)
* [One-shot Commands (sequence)](#one-shot-commands--sequence-)
* [One-shot Commands (parallel)](#one-shot-commands--parallel-)
* [SysV Init Scripts](#sysv-init-scripts)
* [Services](#services)
* [Run-parts Scripts](#run-parts-scripts)
* [Including Finit Configs](#including-finit-configs)
* [General Logging](#general-logging)
* [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 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
Not all configuration directives are available in `/etc/finit.d/*.conf`
and some directives are only available at [bootstrap][], runlevel `S`,
see the section [Limitations](#limitations) below for details.
To add a new service, drop a `.conf` file in `/etc/finit.d` and run
`initctl reload`. (It is also possible to `SIGHUP` to PID 1, or call
`finit q`, but that has been deprecated with the `initctl` tool). Finit
monitors all known active `.conf` files, so if you want to force a
restart of any service you can touch its corresponding `.conf` file in
`/etc/finit.d` and call `initctl reload`. Finit handle any and all
conditions and dependencies between services automatically.
It is also possible to drop `.conf` files in `/etc/finit.d/available/`
and use `initctl enable` to enable a service `.conf` file. This may be
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.
- 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
runlevels and return values from any callbacks.
For more info on the different states of a service, see the separate
document [Finit Services](service.md).
> 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
-------------------
Finit supports sourcing environment variables from `/etc/default/*`, or
similar `--with-sysconfig=DIR`. This is a common pattern from SysV init
scripts, where the start-stop script is a generic script for the given
service, `foo`, and the options for the service are sourced from the
file `/etc/default/foo`. Like this:
* `/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
Here the service `foo` is started with `-n`, to make sure it runs in the
foreground, and the with the options found in the environment file. With
the `ps` command we can see that the process is started with:
foo -n --extra-arg=bar -s -x
> **Note:** the leading `-` determines if Finit should treat a missing
> environment file as blocking the start of the service or not. When
> `-` is used, a missing environment file does *not* block the start.
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.
The Finit service `.conf` file can be put into `/etc/finit.d/available`,
so you can control the service using `initctl`. Then use the path to
the wrapper script in the Finit `.conf` service stanza. The following
example employs a wrapper script in `/etc/start.d`.
**Example:**
* `/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
> **Note:** the example sets `<!>` to denote that it doesn't support
> `SIGHUP`. That way Finit will stop/start the service
> instead of sending SIGHUP at restart/reload events.
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
-------------------------
### Hostname
**Syntax:** `host <NAME>`, or `hostname <NAME>`
Set system hostname to NAME, unless `/etc/hostname` exists in which case
the contents of that file is used.
Deprecated. We recommend using `/etc/hostname` instead.
> **Note:** only read and executed in runlevel S ([bootstrap][]).
### Kernel Modules
**Syntax:** `module <MODULE> [ARGS]`
Load a kernel module, with optional arguments. Similar to `insmod`
command line tool.
Deprecated, there is both a `modules-load.so` and a `modprobe.so` plugin
that can handle module loading better. The former supports loading from
`/etc/modules-load.d/`, the latter uses kernel modinfo to automatically
load (or coldplug) every required module. For hotplug we recommend the
BusyBox mdev tool, add to `/etc/mdev.conf`:
$MODALIAS=.* root:root 0660 @modprobe -b "$MODALIAS"
> **Note:** only read and executed in runlevel S ([bootstrap][]).
### Networking
**Syntax:** `network <PATH>`
Script or program to bring up networking, with optional arguments.
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][]).
### Resource Limits
**Syntax:** `rlimit [hard|soft] RESOURCE <LIMIT|unlimited>`
Set the hard or soft limit for a resource, or both if that argument is
omitted. `RESOURCE` is the lower-case `RLIMIT_` string constants from
`setrlimit(2)`, without prefix. E.g. to set `RLIMIT_CPU`, use `cpu`.
LIMIT is an integer that depends on the resource being modified, see
the man page, or the kernel `/proc/PID/limits` file, for details.
Finit versions before v3.1 used `infinity` for `unlimited`, which is
still supported, albeit deprecated.
# 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
`rlimit` can be set globally, in `/etc/finit.conf`, or locally per
each `/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.
### Runlevels
**Syntax:** `runlevel <N>`
The system runlevel to go to after [bootstrap][] (S) has completed. `N`
is the runlevel number 0-9, where 6 is reserved for reboot and 0 for
halt.
Default: 2
> **Note:** only read and executed in runlevel S ([bootstrap][]).
### One-shot Commands (sequence)
**Syntax:** `run [LVLS] <COND> /path/to/cmd ARGS -- Optional description`
One-shot command to run in sequence when entering a runlevel, with
optional arguments and description.
`run` commands are guaranteed to be completed before running the next
command. Highly useful if true serialization is needed.
> `<COND>` is described in the [Services](#services) section.
### One-shot Commands (parallel)
**Syntax:** `task [LVLS] <COND> /path/to/cmd ARGS -- Optional description`
One-shot like 'run', but starts in parallel with the next command.
Both `run` and `task` commands are run in a shell, so pipes and
redirects can be freely used:
task [s] echo "foo" | cat >/tmp/bar
> `<COND>` is described in the [Services](#services) section.
### SysV Init Scripts
**Syntax:** `sysv [LVLS] <COND> /path/to/init-script -- Optional description`
Similar to `task` is the `sysv` stanza, which can be used to call SysV
style scripts. The primary intention for this command is to be able to
re-use much of existing setup and init scripts in Linux distributions.
When entering an allowed runlevel, Finit calls `init-script start`, when
entering a disallowed runlevel, Finit calls `init-script stop`, and if
the Finit .conf, where `sysv` stanza is declared, is modified, Finit
calls `init-script restart` on `initctl reload`. Similar to how
`service` stanzas work.
Forking services started with `sysv` scripts can be monitored by Finit
by declaring the PID file to look for: `pid:!/path/to/pidfile.pid`.
> `<COND>` is described in the [Services](#services) section.
### Services
**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.
For daemons that support it, we recommend appending `--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.
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 `sysv`
services, using the `pid:!/path/to/pidfile.pid` syntax.
**Example:**
In the case of `ospfd` (below), we omit the `-d` flag (daemonize) to
prevent it from forking to the background:
service [2345] <pid/zebra> /sbin/ospfd -- OSPF daemon
`[2345]` denote the runlevels `ospfd` is allowed to run in, they are
optional and default to level 2-5 if omitted.
`<...>` is the condition for starting `ospfd`. In this example Finit
waits for another service, `zebra`, to have created its PID file in
`/var/run/quagga/zebra.pid` before starting `ospfd`. Finit watches
*all* files in `/var/run`, for each file named `*.pid`, or `*/pid`,
Finit opens it and find the matching `NAME:ID` using the PID.
Some services do not maintain a PID file and rather than patching each
application Finit provides a workaround. A `pid` 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 `/var/run`
directory using the `basename(1)` of the service. The default can be
modified with an optional `pid:`-argument:
pid[:[/path/to/]filename[.pid]]
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>`.
> For a detailed description of conditions, and how to debug them,
> see the [Finit Conditions](conditions.md) document.
If a service should not be automatically started, it can be configured
as manual with the optional `manual` argument. The service can then be
started at any time by running `initctl start <service>`.
manual:yes
The name of a service, shown by the `initctl` tool, defaults to the
basename of the service executable. It can be changed with the
optional `name` argument:
name:<service-name>
As mentioned previously, services are automatically restarted, this is
configurable with the following options:
* `restart:NUM` -- number of times Finit tries to restart a crashing
service, default: 10. When this limit is reached the service is
marked *crashed* and must be restarted manually with `initctl`
* `restart_sec:SEC` -- number of seconds before Finit tries to restart
a crashing service, default: 2 seconds for the first five retries,
then back-off to 5 seconds. The maximum of this configured value
and the above (2 and 5) will be used
* `norestart` -- dont restart on failures, same as `restart:0`
* `oncrash:reboot` -- when all retries have failed, and the service
has *crashed*, if this option is set the system is rebooted.
Note, future releases may include other `oncrash:` actions
When stopping a service (run/task/sysv/service), either manually or
when moving to another runlevel, Finit starts by sending `SIGTERM`, to
allow the process to shut down gracefully. If the process has not
been collected within 3 seconds, Finit sends `SIGKILL`. To halt the
process using a different signal, use the option `halt:SIGNAL`, e.g.,
`halt:SIGPWR`. To change the delay between your halt signal and KILL,
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
The scripts have a default execution time of 3 seconds before they are
SIGKILLed, this can be adjusted using the above `kill:SEC` syntax.
> **Note:** the `pre:script` _must_ be idempotent, because a service
> can transition between READY and HALTED states any number
> of times before going to RUNNING.
### Run-parts Scripts
**Syntax:** `runparts <DIR>`
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][].
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.
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][]).
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
### Including Finit Configs
**Syntax:** `include <CONF>`
Include another configuration file. Absolute path required.
### General Logging
**Syntax:** `log size:200k count:5`
Log rotation for run/task/services using the `log` sub-option with
redirection to a log file. Global setting, applies to all services.
The size can be given as bytes, without a specifier, or in `k`, `M`,
or `G`, e.g. `size:10M`, or `size:3G`. A value of `size:0` disables
log rotation. The default is `200k`.
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.
### 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]`
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.
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.
**Example:**
tty [12345] /sbin/getty -L 115200 /dev/ttyAMA0 vt100
tty [12345] /sbin/agetty -L ttyAMA0 115200 vt100 nowait
The `noclear` option disables clearing the TTY after each session.
Clearing the TTY when a user logs out is usually preferable.
The `nowait` option disables the `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.
The `nologin` option disables getty and `/bin/login`, and gives the
user a root (login) shell on the given TTY `<DEV>` immediately.
Needless to say, this is a rather insecure option, but can be very
useful for developer builds, during board bringup, or similar.
Notice the ordering, the `TERM` option to the built-in getty must be
the last argument.
Embedded systems may want to enable automatic `DEV` by supplying the
special `@console` device. This works regardless weather the system
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
may give a user root access without having to log in. However, for
board bringup and system debugging it can come in handy.
One can also use the `service` stanza to start a stand-alone shell:
service [12345] /bin/sh -l
### 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:
run [2345] @joe:users logger "Hello world"
For multiple instances of the same command, e.g. a DHCP client or
multiple web servers, add `:ID` somewhere between the `run`, `task`,
`service` keyword and the command, like this:
service :80 [2345] httpd -f -h /http -p 80 -- Web server
service :8080[2345] httpd -f -h /http -p 8080 -- Old web server
Without the `:ID` to the service the latter will overwrite the former
and only the old web server would be started and supervised.
### Redirecting Output
The `run`, `task`, and `service` stanzas also allow the keyword `log` to
redirect `stderr` and `stdout` of the application to a file or syslog
using the native `logit` tool. This is useful for programs that do not
support syslog on their own, which is sometimes the case when running
in the foreground.
The full syntax is:
log:/path/to/file
log:prio:facility.level,tag:ident
log:console
log:null
log
Default `prio` is `daemon.info` and default `tag` is the basename of the
service or run/task command.
Log rotation is controlled using the global `log` setting.
**Example:**
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
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*.
### 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.
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.
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`.
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 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.
-6
View File
@@ -1,6 +0,0 @@
docsdir := @docdir@/doc/config
dist_docs_DATA = cgroups.md env.md files.md index.md limitations.md \
logging.md rescue.md runlevels.md runparts.md \
service-env.md service-opts.md service-sync.md \
service-wrappers.md services.md sysv.md \
task-and-run.md templating.md tty.md
-1
View File
@@ -1 +0,0 @@
index.md
-186
View File
@@ -1,186 +0,0 @@
Linux Capabilities
==================
Finit supports Linux capabilities, allowing services to run with minimal
required privileges instead of running as root. This significantly improves
system security by following the principle of least privilege.
## Overview
Linux capabilities divide the traditional root privileges into distinct units
that can be independently granted to processes. For example, a web server only
needs the capability to bind to privileged ports (< 1024), not full root access.
Finit uses the modern IAB (Inheritable, Ambient, Bounding) API from libcap,
which is the same approach used by other modern service managers like dinit.
## Basic Usage
Capabilities are specified using the `caps:` directive in service configuration:
```conf
service [2345] name:nginx \
@www-data:www-data \
caps:^cap_net_bind_service \
/usr/sbin/nginx -g 'daemon off;' \
-- Web server
```
This example allows nginx to bind to privileged ports (like 80 and 443) while
running as the unprivileged `www-data` user.
## IAB Format
The capability string uses the IAB (Inheritable, Ambient, Bounding) format
with the following prefixes:
- `^` **Ambient** (and Inheritable) - **Recommended for most use cases**
- Capabilities survive across `exec()` calls
- Automatically raised to effective after exec
- Example: `^cap_net_bind_service`
- `%` **Inheritable** only
- Requires the executed binary to have matching file capabilities
- Less common, more complex setup
- Example: `%cap_net_admin`
- `!` **Bounding** - Block capability from bounding set
- Prevents the service from ever acquiring this capability
- Useful for security hardening
- Example: `!cap_sys_admin`
Multiple capabilities can be specified as a comma-separated list:
```conf
caps:^cap_net_raw,^cap_net_admin,^cap_net_bind_service
```
## Common Use Cases
### Web Server (Privileged Ports)
Allow a web server to bind to ports 80 and 443 without running as root:
```conf
service [2345] name:webserver \
@www-data:www-data \
caps:^cap_net_bind_service \
/usr/sbin/nginx -g 'daemon off;'
```
### Network Monitoring (Raw Sockets)
Allow packet capture without root privileges:
```conf
service [2345] name:tcpdump \
@tcpdump \
caps:^cap_net_raw,^cap_net_admin \
/usr/sbin/tcpdump -i eth0 -w /var/log/capture.pcap
```
### NTP Daemon (System Time)
Allow time synchronization without full root:
```conf
service [2345] name:ntpd \
@ntp \
caps:^cap_sys_time,^cap_sys_nice \
/usr/sbin/ntpd -n
```
## Available Capabilities
Common capabilities include (see `man 7 capabilities` for the complete list):
- `cap_chown` - Make arbitrary changes to file UIDs and GIDs
- `cap_dac_override` - Bypass file read, write, and execute permission checks
- `cap_dac_read_search` - Bypass file read permission checks
- `cap_fowner` - Bypass permission checks on operations that normally require filesystem UID
- `cap_kill` - Bypass permission checks for sending signals
- `cap_net_admin` - Perform various network-related operations
- `cap_net_bind_service` - Bind to privileged ports (< 1024)
- `cap_net_raw` - Use RAW and PACKET sockets
- `cap_setgid` - Make arbitrary manipulations of process GIDs
- `cap_setuid` - Make arbitrary manipulations of process UIDs
- `cap_sys_admin` - Perform system administration operations (very powerful!)
- `cap_sys_module` - Load and unload kernel modules
- `cap_sys_nice` - Raise process nice value and change scheduling
- `cap_sys_time` - Set system clock
## Security Best Practices
1. **Use the minimum required capabilities**
- Only grant what the service actually needs
- Don't grant `cap_sys_admin` unless absolutely necessary
2. **Specify a user (preferably non-root)**
- The `@user` directive is **required** for `caps:` to take effect
- For ambient capabilities (`^`), use a non-root user (not `@root`)
- Example: `@www-data`, `@nginx`, `@tcpdump`
3. **Use ambient capabilities (`^`)**
- The `^` prefix ensures capabilities survive exec()
- Simpler than setting file capabilities on binaries
4. **Block dangerous capabilities**
- Use `!` to explicitly block capabilities you don't want
- Example: `!cap_sys_admin,!cap_sys_module`
5. **Test with `getpcaps`**
- After starting a service, verify its capabilities:
```bash
getpcaps $(pidof nginx)
```
- Should show only the capabilities you granted
## Verification
After configuring a service with capabilities, verify it works correctly:
```bash
# Start the service
initctl start webserver
# Check the process capabilities
getpcaps $(pidof nginx)
# Should show something like:
# 12345: cap_net_bind_service=eip
# Verify the user
ps -o user,pid,cmd -p $(pidof nginx)
# Should show the service running as the specified user
```
## Requirements
- Linux kernel 4.3+ (for ambient capabilities support)
- libcap library installed
- Finit built with `--enable-libcap`
## Limitations
- The `caps:` directive requires `@user` to be specified for it to take effect
- Without `@user`, the service runs as root with full capabilities and
the `caps:` configuration is silently ignored
- You can use `@root` with `caps:`, but see below about ambient capabilities
- For ambient capabilities (`^`, recommended), the user **must be non-root**
- Using `@root` with `caps:^...` will not work effectively, as ambient
capabilities are only added to the effective set when euid ≠ 0
- Use inheritable (`%`) or bounding (`!`) capabilities with `@root` if needed
- Services without `caps:` use standard privilege dropping:
- Services with `@user` (non-root) have no special capabilities
- Services without `@user` run as root with full capabilities
- Some very old binaries may not work correctly with ambient capabilities
- File system capabilities are not managed by Finit (use `setcap` for that)
## See Also
- [capabilities(7)](https://man7.org/linux/man-pages/man7/capabilities.7.html) - Linux capabilities overview
- [cap_iab(3)](https://man7.org/linux/man-pages/man3/cap_iab.3.html) - IAB capability API documentation
- [setcap(8)](https://man7.org/linux/man-pages/man8/setcap.8.html) - Set file capabilities
- [getcap(8)](https://man7.org/linux/man-pages/man8/getcap.8.html) - Query file capabilities
- [capsh(1)](https://man7.org/linux/man-pages/man1/capsh.1.html) - Capability shell wrapper
-215
View File
@@ -1,215 +0,0 @@
Finit provides three different cgroup directives for controlling resource allocation:
1. **Top-level cgroup definition**: `cgroup NAME settings`
- Defines a top-level cgroup (e.g., `init`, `system`, `user`) with default settings
- Space-separated syntax
- Example: `cgroup system cpu.weight:9700`
2. **Global cgroup selector**: `cgroup.NAME[,options]` (standalone directive)
- Sets the default cgroup for subsequent services in a `.conf` file
- Dot-separated with optional comma-separated options
- Example: `cgroup.maint` or `cgroup.system,delegate`
3. **Per-service cgroup option**: `cgroup.NAME[,options]` or `cgroup:options`
- Overrides the cgroup for a specific service
- Part of the service directive line
- Example: `service [...] cgroup.maint,mem.max:1G /path/to/cmd`
> [!NOTE]
> Linux cgroups and details surrounding values are not explained in the
> Finit documentation. The Linux admin-guide covers this well:
> <https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html>
Top-level Cgroup Definition
----------------------------
**Syntax:** `cgroup NAME settings`
# 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.
Global Cgroup Selector
----------------------
**Syntax:** `cgroup.NAME[,options]` (standalone directive)
To select a different top-level cgroup, e.g. `maint/`, for a group of
run/task/service directives in a `.conf` file, use the `cgroup.NAME`
directive as a standalone line:
cgroup.maint
service [...] <...> /path/to/foo args -- description
service [...] <...> /path/to/bar args -- description
Both services will run in the `maint/` cgroup.
You can also include options with the global selector:
cgroup.system,delegate
service [...] <...> /path/to/foo args -- description
Per-Service Cgroup Option
--------------------------
**Syntax:** `cgroup.NAME[,options]` or `cgroup:options` (service option)
To override the cgroup for a specific service, use the `cgroup.NAME`
option within the service directive:
service [...] <...> cgroup.maint /path/to/foo args -- description
This form also allows per-service limits. Two syntaxes are supported:
**New comma-separated syntax (recommended):**
service [...] <...> cgroup.maint,cpu.max:10000,mem.max:655360 /path/to/foo args -- description
**Old colon-separated syntax (legacy):**
service [...] <...> cgroup.maint:cpu.max:10000,mem.max:655360 /path/to/foo args -- description
You can also apply options to the current default cgroup (without changing it)
using the `cgroup:options` syntax:
service [...] <...> cgroup:cpu.max:10000,mem.max:655360 /path/to/foo args -- description
Both syntaxes work identically. The new comma-separated syntax is recommended
as it's more consistent with other option parsing in Finit.
Note 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.
### Overriding Cgroup Leaf Names
By default, the cgroup leaf directory name is derived from the service
configuration filename (without the `.conf` extension). For example, a
service defined in `system/10-hotplug.conf` would create a cgroup at
`/sys/fs/cgroup/system/10-hotplug/` by default.
To use a more descriptive name (recommended for clarity), you can specify
`name:` in the cgroup directive:
service [...] <...> cgroup.system,name:udevd /lib/systemd/systemd-udevd -- Device event daemon
This creates the cgroup at `/sys/fs/cgroup/system/udevd/` instead.
The syntax supports combining the name override with other options:
service [...] <...> cgroup.system,name:udevd,cpu.max:10000 /lib/systemd/systemd-udevd -- Device event daemon
Or with delegation:
service [2345] @podman:podman \
cgroup.containers,name:podman,delegate,mem.max:4G \
/usr/bin/podman system service -- Podman API
A daemon using `SCHED_RR` currently needs to run outside the default cgroups.
service [...] <...> cgroup.root /path/to/daemon arg -- Real-Time process
Cgroup Delegation
-----------------
For services that need to create their own child cgroups (container runtimes
like Docker, Podman, systemd-nspawn, LXC), use the `delegate` option:
service [2345] @dockerd:dockerd \
cgroup.system,delegate /usr/bin/dockerd -- Docker daemon
Or with the old colon syntax:
service [2345] @dockerd:dockerd \
cgroup.system:delegate /usr/bin/dockerd -- Docker daemon
This allows the container runtime to:
- Create child cgroups for containers
- Manage controller settings for containers
- Move processes between cgroups
When delegation is enabled, Finit:
1. Creates the service cgroup as a **domain group** (not a leaf)
2. Enables all available controllers in `cgroup.subtree_control`
3. Changes ownership of delegation files to the service user
4. Moves the service process to the cgroup root
5. Lets the container runtime manage its own subdirectories
**Requirements:**
- The service should specify `@user:group` for proper ownership
- Controllers are delegated from the parent cgroup
**Example with additional config (new syntax):**
service [2345] @podman:podman \
cgroup.containers,delegate,mem.max:4G \
/usr/bin/podman system service -- Podman API
**Or with old syntax:**
service [2345] @podman:podman \
cgroup.containers:delegate,mem.max:4G \
/usr/bin/podman system service -- Podman API
Both examples delegate the cgroup while also setting a 4GB memory limit.
**Container template example:**
Here's a real-world example from [Infix OS](https://github.com/kernelkit/infix)
for running rootful podman container instances using delegation:
sysv log:prio:local1,tag:%i kill:30 pid:!/run/container:%i.pid \
pre:0,/usr/sbin/container cleanup:0,/usr/sbin/container \
cgroup.system,delegate \
[2345] <!> :%i container -n %i -- container %i
This template uses `sysv` type with delegation, demonstrating that cgroup
delegation works with different service types, not just `service`.
**Cgroup structure with delegation:**
Initially, the service process runs directly in the cgroup root:
/sys/fs/cgroup/system/container@web/
├── cgroup.procs (service PID - owned by service user)
├── cgroup.subtree_control (+cpu +memory +io - owned by service user)
└── (container children will be created here)
Once the container runtime creates child cgroups (e.g., `libpod-*/`), cgroups v2
enforces the "no internal processes" rule. When Finit detects this (`EBUSY` error),
it automatically creates an `supervisor/` subdirectory and moves service-related
processes there:
/sys/fs/cgroup/system/container@web/
├── cgroup.procs (empty)
├── cgroup.subtree_control (+cpu +memory +io)
├── supervisor/ (service processes)
│ └── cgroup.procs (conmon PIDs, etc.)
└── libpod-$HASH/ (container processes)
└── cgroup.procs (container PIDs)
This happens automatically - no configuration needed. Without delegation, the
cgroup would be a leaf and the container runtime could not create child cgroups.
-31
View File
@@ -1,31 +0,0 @@
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 a service-local
environment is detailed in [Services Environment](service-env.md).
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.
-208
View File
@@ -1,208 +0,0 @@
Files & Layout
==============
Originally Finit was configured using a single file, `/etc/finit.conf`,
and although still possible to use a single configuration file, today
the following layout is recommended:
/
|- etc/
| |- finit.d/
| | |- available/
| | | `- my-service.conf
| : |- enabled/
| : | `- my-service.conf -> ../available/my-service.conf
| : :
| : |- static-service.conf
| : `- another-static.conf
| :
| `- finit.conf
|- lib
| `- finit/
| `- system/
| |- 10-hotplug.conf
| `- ...
`- run/
`- finit/
`- system/
|- dbus.conf
|- keventd.conf
|- runparts.conf
|- watchdogd.conf
`- ...
Configuration files in `/etc` are provided by the user, or projects like
[finit-skel](https://github.com/finit-project/finit-skel) and extended by
the user.
The files in `/lib/finit/system/*.conf` are system critical services and
setup provided by Finit, e.g. udev/mdev that must run very early at system
bootstrap. This system directory was introduced in Finit v4.4 to replace
the hard-coded services provided by plugins before. All .conf files in this
directory be either replaced by a system administrator or overridden by a
file with the same name in `/etc/finit.d/`.
The files in `/run/finit/system/*.conf` are created by plugins and Finit
bundled services like runparts, [watchdog](../watchdog.md), and
[`keventd`](../keventd.md) if they are enabled. Like
`/lib/finit/system/*.conf`, these files can be overridden by file with
the same name in `/etc/finit.d/`.
Services in the `available/` and `enabled/` sub-directories are called
dynamic services, in contrast to static services -- the only difference
being where they are installed and if the `initctl` tool can manage them
with the `enable` and `disable` commands. An administrator can always
create files and symlinks manually.
At bootstrap, and `initctl reload`, all .conf files are read, starting
with `finit.conf`, then `/lib/finit/system/*.conf`, `finit.d/*.conf`,
and finally all `finit.d/enabled/*.conf` files. Each directory is a
unique group, where files within each group are sorted alphabetically.
**Example:**
/lib/finit/system/10-hotplug.conf
/lib/finit/system/90-testserv.conf
/run/finit/system/dbus.conf
/run/finit/system/runparts.conf
/etc/finit.d/10-abc.conf
/etc/finit.d/20-abc.conf
/etc/finit.d/enabled/1-aaa.conf
/etc/finit.d/enabled/1-abc.conf
The resulting combined configuration is read line by line, each `run`,
`task`, and `service` added to an ordered list that ensures they are
started in the same order. This is important because of the blocking
properties of the `run` statement. For an example on the relation of
`service` and `run` statements, and dependency handling between them,
see [Conditional Loading](services.md#conditional-loading), below.
> [!NOTE]
> The names `finit.conf` and `finit.d/` are only defaults. They can be
> changed at compile-time with two `configure` options:
> `--with-config=/etc/foo.conf` and `--with-rcsd=/var/foo.d`.
>
> They can also be overridden from the [kernel command line](../cmdline.md)
> 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 by mounting the critical file systems `/dev`, `/proc/`, and
`/sys`, unless they are already mounted. When all plugins and other,
core Finit functions, have been set up, all relevant filesystems (where
`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.
To provide a smooth ride, file system not listed in the given `fstab`,
e.g. `/tmp` and `/run`, are automatically mounted by Finit, as listed
above, provided their respective mount point exists.
With all filesystems mounted, Finit calls `swapon`.
> [!TIP]
> To see what happens when all filesystems are mounted, have a look at
> the [`bootmisc.so` plugin](../plugins.md).
At shutdown, and after having stopped all services and other lingering
processes have been killed, filesystems are unmounted in the reverse
order, and `swapoff` is called.
[FHS]: https://refspecs.linuxfoundation.org/FHS_3.0/fhs/index.html
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 the section on
[Service Synchronization](service-sync.md) for more details.
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.
- 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
runlevels and return values from any callbacks.
For more info on the different states of a service, see the separate
document [Finit Services](../service.md).
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, usually `/etc/finit.conf`.
Including Finit Configs
------------------------
**Syntax:** `include <CONF>`
Include another configuration file. Absolute path required.
-30
View File
@@ -1,30 +0,0 @@
This section provides an overview of Finit's configuration system. For
detailed information on specific topics, see the individual sections in
the navigation menu.
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
```
The .conf files `/etc/finit.conf` and `/etc/finit.d/*` support many
directives. Some are restricted, e.g., only available at bootstrap,
runlevel `S`. Read on in [Files & Layout](files.md) for more on how
to structure your .conf files.
For details on restrictions, see [Limitations](limitations.md).
-21
View File
@@ -1,21 +0,0 @@
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.
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`.
There is, however, nothing preventing you from having all configuration
settings in `/etc/finit.conf`.
> [!IMPORTANT]
> The default `rcsd`, i.e., `/etc/finit.d`, was previously the Finit
> [runparts](runparts.md) directory. Finit >=v4.0 no longer has a
> default `runparts` directory, make sure to update your setup, or the
> finit configuration, accordingly.
-63
View File
@@ -1,63 +0,0 @@
General Logging
===============
**Syntax:** `log size:200k count:5`
Log rotation for run/task/services using the `log` sub-option with
redirection to a log file. Global setting, applies to all services.
The size can be given as bytes, without a specifier, or in `k`, `M`,
or `G`, e.g. `size:10M`, or `size:3G`. A value of `size:0` disables
log rotation. The default is `200k`.
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.
Redirecting Output
------------------
The `run`, `task`, and `service` stanzas also allow the keyword `log` to
redirect `stderr` and `stdout` of the application to a file or syslog
using the native `logit` tool. This is useful for programs that do not
support syslog on their own, which is sometimes the case when running
in the foreground.
The full syntax is:
log:/path/to/file
log:prio:facility.level,tag:ident
log:console
log:null
log
Default `prio` is `daemon.info` and default `tag` is the basename of the
service or run/task command.
Log rotation is controlled using the global `log` setting.
**Example:**
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
Output Buffering
----------------
When using the `log` directive, Finit redirects the service's stdout and
stderr to a pipe connected to a logger process. Programs detect this as
non-interactive output (i.e., `isatty()` returns false) and typically
switch from line-buffered to fully-buffered mode.
Most well-behaved daemons explicitly flush their output or use syslog
directly, so this is rarely an issue. However, if a service's log
messages appear delayed or batched, you can force line-buffered output
by wrapping the command with `stdbuf`:
service log /usr/bin/stdbuf -oL /path/to/command -- My service
The `-oL` option forces line-buffered output, and `-o0` forces unbuffered
output. See `stdbuf(1)` for details.
> [!NOTE]
> Using `stdbuf` is rarely necessary. Only use it if you observe actual
> buffering issues with a specific service.
-62
View File
@@ -1,62 +0,0 @@
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.
This rescue mode can be disabled at configure time using:
configure --without-rescue
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 system `sulogin` program from util-linux, or BusyBox. If
that is not found in `$PATH`, the bundled `/libexec/finit/sulogin`
program is used instead. If a successful login is made, or if the user
exits (Ctrl-D), the rescue mode is ended and the system boots up
normally.
> [!WARNING]
> The bundled sulogin in Finit can at configure time be given another
> user than the default (root). If the sulogin user does not have a
> password, or __the account is locked__, the user is presented with a
> prompt: `"Press enter to enter maintenance mode."`, which will open
> up a root shell *without prompting for password*!
Fallback
--------
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.
-187
View File
@@ -1,187 +0,0 @@
Runlevels
=========
Finit supports runlevels, but unlike other init systems runlevels are
declared per service/run/task/sysv command. When booting up a system
Finit pass through three phases:
1. Setting up the console, parsing any command line options, and other
housekeeping tasks like mounting all filesystems, and calling `fsck`
2. Starting all run/task/services in runlevel S, then waiting for all
services to have started, and all run/tasks to have completed
3. Go to runlevel 2, or whatever the user has set in the configuration
Available runlevels:
- ` S`: bootStrap
- ` 1`: Single user mode
- `2-5`: traditional multi-user mode
- ` 6`: reboot
- `7-9`: multi-user mode (extra)
- ` 0`: shutdown
Runlevel S (bootStrap), is for tasks supposed to run once at boot, and
services like `syslogd`, which need to start early and run throughout
the lifetime of your system.
Example:
task [S] /lib/console-setup/console-setup.sh
service [S12345] env:-/etc/default/rsyslog rsyslogd -n $RSYSLOGD_ARGS
When bootstrap has completed, Finit moves to runlevel 2. This can be
changed in `/etc/finit.conf` using the `runlevel N` directive, or by a
script running in runlevel S that calls, e.g., `initctl runlevel 9`.
The latter is useful if startup scripts detect problems outside of
Finit's control, e.g., critical services/devices missing or hardware
problems.
Each runlevel must be allowed to "complete". Meaning, all services in
runlevel S must have started and all run/tasks have been started and
collected (exited). Finit waits 120 seconds for all run/tasks in S to
complete before proceeding to 2.
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.
Runlevel Configuration
----------------------
**Syntax:** `runlevel <N>`
The system runlevel to go to after bootstrap (S) has completed. `N` is
the runlevel number 0-9, where 6 is reserved for reboot and 0 for halt.
Completed in this context means all services have been started and all
run/tasks have been started and collected.
It is recommended to keep runlevel 1 as single-user mode, because
Finit disables networking in this mode.
*Default:* 2
> [!NOTE]
> Only read and executed in runlevel S (bootstrap).
Networking
----------
**Syntax:** `network <PATH>`
Script or program to bring up networking, with optional arguments.
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).
System Hostname
---------------
**Syntax:** `host <NAME>`, or `hostname <NAME>`
Set system hostname to NAME, unless `/etc/hostname` exists in which case
the contents of that file is used.
Deprecated. We recommend using `/etc/hostname` instead.
> [!NOTE]
> Only read and executed in runlevel S (bootstrap).
Kernel Modules
--------------
**Syntax:** `module <MODULE> [ARGS]`
Load a kernel module, with optional arguments. Similar to `insmod`
command line tool.
Deprecated, there is both a `modules-load.so` and a `modprobe.so` plugin
that can handle module loading better. The former supports loading from
`/etc/modules-load.d/`, the latter uses kernel modinfo to automatically
load (or coldplug) every required module. For hotplug we recommend the
BusyBox mdev tool, add to `/etc/mdev.conf`:
$MODALIAS=.* root:root 0660 @modprobe -b "$MODALIAS"
> [!NOTE]
> Only read and executed in runlevel S (bootstrap).
Resource Limits
---------------
**Syntax:** `rlimit [hard|soft] RESOURCE <LIMIT|unlimited>`
Set the hard or soft limit for a resource, or both if that argument is
omitted. `RESOURCE` is the lower-case `RLIMIT_` string constants from
`setrlimit(2)`, without prefix. E.g. to set `RLIMIT_CPU`, use `cpu`.
LIMIT is an integer that depends on the resource being modified, see
[setrlimit(2)](https://man7.org/linux/man-pages/man2/setrlimit.2.html),
or the kernel `/proc/PID/limits` file, for details. Finit versions
before v3.1 used `infinity` for `unlimited`, which is still supported,
albeit deprecated.
# 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
`rlimit` can be set globally, in `/etc/finit.conf`, or locally per
each `/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.
Miscellaneous 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.
**Syntax:** `reboot-watchdog <on|off|true|false|1|0>`
Controls whether the system should reboot via the watchdog timer (WDT)
or directly via the SoC/kernel. When enabled, Finit will:
1. Send `SIGPWR` to the registered watchdog daemon before shutdown
2. Send `SIGTERM` to the watchdog daemon and wait up to 10 seconds
for the watchdog to trigger a hardware reset
When disabled (default), Finit skips the watchdog reboot logic and
calls the kernel's `reboot(2)` syscall directly for a clean SoC reboot.
*Default:* off (reboot via SoC)
> [!NOTE]
> This setting only affects reboots. The watchdog daemon will still
> run and monitor the system during normal operation.
-51
View File
@@ -1,51 +0,0 @@
Run-parts Scripts
-----------------
**Syntax:** `runparts [progress] [sysv] <DIR>`
Call [run-parts(8)][] on `DIR` to run start scripts. All executable
files in the directory are called, in alphabetic order. The scripts in
this directory are executed at the very end of runlevel `S`.
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 call `initctl enable chronyd`.
**Options:**
- `progress`: display the progress of each script being executed
- `sysv`: run only SysV style scripts, i.e., `SNNfoo`, or `KNNbar`,
where `NN` is a number (0-99).
If global debug mode is enabled, the `runparts` program is also called
with the debug flag.
**Limitations:**
Scripts called from `runparts`, or hook scripts (see below), are limited
in their interaction with Finit. Like the standalone `run` stanza and
the `/etc/rc.local` shell script, Finit waits for their completion
before continuing. None of them can issue commands to start, stop, or
restart other services. Also, ensure all your services and programs
either terminate or start in the background or you will block Finit.
> [!NOTE]
> `runparts` scripts are only read and executed in runlevel S. See
> [hook scripts](../plugins.md#hooks) for other ways to run scripts at
> certain points during the complete lifetime of the system.
**Recommendations:**
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
-27
View File
@@ -1,27 +0,0 @@
Service Environment
-------------------
Finit supports sourcing environment variables from `/etc/default/*`, or
similar `--with-sysconfig=DIR`. This is a common pattern from SysV init
scripts, where the start-stop script is a generic script for the given
service, `foo`, and the options for the service are sourced from the
file `/etc/default/foo`. Like this:
* `/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
Here the service `foo` is started with `-n`, to make sure it runs in the
foreground, and the with the options found in the environment file. With
the `ps` command we can see that the process is started with:
foo -n --extra-arg=bar -s -x
> [!NOTE]
> The leading `-` in `env:` determines if Finit should treat a missing
> environment file as blocking the start of the service or not. When
> `-` is used, a missing environment file does *not* block the start.
-140
View File
@@ -1,140 +0,0 @@
Service Options
===============
The run/task/tty/service/sysv directives take modifiers, or options, to
control their behavior. This section lists them with their limitations.
All modifiers must be placed between the directive and its command.
The name of a service, shown by the `initctl` tool, defaults to the
basename of the service executable. It can be changed with the `name:`
option:
name:<service-name>
For multiple instances of a service, with the same `name`, set the
identifier `:ID` to prevent Finit from replacing previous instances:
service name:ssdp :eth1 ssdpd eth1 -- Windows discovery on eth1
service name:ssdp :eth2 ssdpd eth2 -- Windows discovery on eth2
The [`initctl`](../initctl.md) tool will list these two services as:
- ssdp:eth1
- ssdp:eth2
Conflicting services that must be prevented from starting, use the
`conflict:` option:
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
If a service should not be automatically started, it can be configured
as manual with the optional `manual` argument. The service can then be
started at any time by running `initctl start <service>`.
manual:yes
Other run/task/service options are:
* `caps:...` -- see the [Linux Capabilities](capabilities.md) section
* `cgroup.NAME[,opts]` or `cgroup:opts` -- see the [Cgroups](cgroups.md) section
* `env:[-]/path/to/env` -- see the [Service Environment](service-env.md) section
* `log:...` -- see [Redirecting Output](logging.md#redirecting-output)
* `nowarn` -- see [Conditional Loading](services.md#conditional-loading)
* `notify:...` -- see [Service Synchronization](service-sync.md)
* `if:...` -- see [Conditional Execution](services.md#conditional-execution)
* `type:forking` -- see description of the [service](services.md) directive
As mentioned previously, services are automatically started, restarted,
and stopped, depending on the configuration and conditions. Within the
confines of that the following options are available:
* `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
* `remain:yes` -- for `run` and `task` only. Prevents the task from
re-running on runlevel re-entry and ensures the `post:` script runs
when the task is explicitly stopped or leaves its valid runlevels.
Similar to systemd's `RemainAfterExit=yes`. See [Task and Run](task-and-run.md)
for more details
* `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 with exit code `crashed`, see below
* `reload:'script [args]'` -- some services do not support `SIGHUP` but
may have other ways to update the configuration of a running daemon.
When `reload:script` is defined it is preferred over `SIGHUP`. Like
systemd, Finit sets `$MAINPID` as a convenience to scripts, which in
effect also allow `reload:'kill -HUP $MAINPID'`
* `stop:'script [args]'` -- some services may require alternate methods
to be stopped. If a `stop:script` is defined it is preferred over
`SIGTERM` and `stop`, for `service` and `sysv`, respectively.
Similar to `reload:script`, Finit sets `$MAINPID`
> [!CAUTION]
> Both `reload:script` and `stop:script` are called as PID 1, without
> any timeout! Meaning, it is up to you to ensure the script is not
> blocking for seconds at a time or never terminates.
When stopping a service (run/task/sysv/service), either manually or when
moving to another runlevel, Finit starts by sending `SIGTERM`, to allow
the process to shut down gracefully (unless a `stop:'script'` is used).
However, if the process has not been collected within 3 seconds, Finit
will send `SIGKILL`. To stop the process using a different signal than
`SIGTERM`, use `halt:SIGNAL`, e.g., `halt:SIGPWR`. To change the delay
between the stop signal and KILL, use the option `kill:<1-60>`, e.g.,
`kill:10` to wait 10 seconds before sending `SIGKILL`.
Services, including the `sysv` variant, support pre/post/ready and
cleanup scripts:
* `pre:[0-3600,]script` -- called before the sysv/service is stated
* `post:[0-3600,]script` -- called after the sysv/service has stopped
* `ready:[0-3600,]script` -- called when the sysv/service is ready
* `cleanup:[0-3600,]script` -- called when run/task/sysv/service is removed
The optional number (0-3600) is the timeout before Finit kills the
script, it defaults to the kill delay value and can be disabled by
setting it to zero. These scripts run as the same `@USER:GROUP` as the
service itself, with any `env:file` sourced. The scripts are executed
from the `$HOME` of the given user. The scripts are not called with any
argument, but get a set of environment variables:
* `SERVICE_IDENT=foo:1`
* `SERVICE_NAME=foo`
* `SERVICE_ID=1`
The `post:script` is called with an additional set of environment
variables. Yes, the text is correct, the naming was an accident:
- `EXIT_CODE=[exited,signal,crashed]`: normal exit, signaled, or
crashed
- `EXIT_STATUS=[num,SIGNAME]`: set to one of exit status code from
the program, if it exited normally, or the signal name (`HUP`,
`TERM`, etc.) if it exited due to signal
When a run/task/sys/service is removed (disable + reload) it is first
stopped and then removed from the runlevel. The `post:script` always
runs when the process has stopped, and the `cleanup:script` runs when
the the stanza has been removed from the runlevel.
> [!IMPORTANT]
> These script actions are intended for setup, cleanup, and readiness
> notification. It is up to the user to ensure the scripts terminate.
-74
View File
@@ -1,74 +0,0 @@
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 style readiness
notification is available, and the native PID file mode of operation is,
as of Finit v4.6 optional, by default it is still enabled, but this can
be changed in `finit.conf`:
readiness none
This will be made the default in Finit 5.0. In this mode of operation,
every service needs to explicitly declare their readiness notification,
like this:
service notify:pid watchdogd
service notify:systemd foo
service notify:s6 bar
service notify:none qux
The `notify:none` syntax is for completeness in systems which run in
`readiness pid` mode (default). Services declared with `notify:none`
will transition to ready as soon as Finit has started them, e.g.,
`service/qux/ready`.
To synchronize two services the following condition can be used:
service notify:pid watchdogd
service <service/watchdogd/ready> stress-ng --cpu 8
For details on the syntax and options, see below.
> [!NOTE]
> On `initctl reload` conditions are set in "flux", while figuring out
> which services to stop, start or restart. Services that need to be
> restarted have their `ready` condition removed before Finit issue a
> SIGHUP (if they support that), or stop-starting them. A daemon is
> expected to reassert its readiness, e.g. systemd style daemons to
> write `READY=1\n`.
>
> However, the s6 notify mode does not support this because in s6 you
> are expected to close your notify descriptor after having written
> `\n`. This means s6 style daemons currently must be stop-started.
> (Declare the service with `<!>` in its condition statement.)
>
> For default, PID file style readiness notification, daemons are
> expected to either create their PID files, or touch it using
> `utimensat()` to reassert readiness. Triggering both the `<pid/>`
> and `<.../ready>` conditions.
-31
View File
@@ -1,31 +0,0 @@
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.
The Finit service `.conf` file can be put into `/etc/finit.d/available`,
so you can control the service using `initctl`. Then use the path to
the wrapper script in the Finit `.conf` service stanza. The following
example employs a wrapper script in `/etc/start.d`.
**Example:**
* `/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
> [!NOTE]
> The example sets `<!>` to denote that it doesn't support `SIGHUP`.
> That way Finit will stop/start the service instead of sending SIGHUP
> at restart/reload events.
-224
View File
@@ -1,224 +0,0 @@
Services
========
**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 controlling this are configurable, see the options below.
> [!TIP]
> To allow endless restarts, see the [`respawn` option](service-opts.md)
For daemons that support it, we recommend appending `--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.
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`.
**Example:**
In the case of `ospfd` (below), we omit the `-d` flag (daemonize) to
prevent it from forking to the background:
service [2345] <pid/zebra> /sbin/ospfd -- OSPF daemon
`[2345]` denote the runlevels `ospfd` is allowed to run in, they are
optional and default to level 2-5 if omitted.
`<...>` is the condition for starting `ospfd`. In this example Finit
waits for another service, `zebra`, to have created its PID file in
`/var/run/quagga/zebra.pid` before starting `ospfd`. Finit watches
*all* files in `/var/run`, for each file named `*.pid`, or `*/pid`,
Finit opens it and find the matching `NAME:ID` using the PID.
The condition can be prefixed with `!` and/or `~`:
- `<!pid/zebra>` -- `ospfd` does not support `SIGHUP` (noreload)
- `<~pid/zebra>` -- propagate reload from `zebra` to `ospfd`
- `<!~pid/zebra>` -- both: noreload and propagate reload
For details, see the [Finit Conditions](../conditions.md) document.
Some services do not maintain a PID file and rather than patching each
application Finit provides a workaround. A `pid` 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 `/var/run`
directory using the `basename(1)` of the service. The default can be
modified with an optional `pid:`-argument:
pid[:[/path/to/]filename[.pid]]
For example, by adding `pid:/run/bar.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.
> For a detailed description of conditions, and how to debug them,
> see the [Finit Conditions](../conditions.md) document.
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[,SUPP,...]]`, where group and supplementary groups are
optional, like this:
run [2345] @joe:users logger "Hello world"
Finit reads the user's supplementary group membership from `/etc/group`
automatically. Any groups the user belongs to will be inherited by
the service.
To specify additional supplementary groups beyond those in `/etc/group`,
append them after the primary group, separated by commas:
service @caddy:caddy,ssl-cert /usr/bin/caddy run
This runs the `caddy` service as user `caddy`, with primary group
`caddy`, inheriting any groups `caddy` is a member of in `/etc/group`,
plus the additional `ssl-cert` group. This is useful when a service
needs access to resources owned by groups not listed in `/etc/group`.
For multiple instances of the same command, e.g. a DHCP client or
multiple web servers, add `:ID` somewhere between the `run`, `task`,
`service` keyword and the command, like this:
service :80 [2345] httpd -f -h /http -p 80 -- Web server
service :8080[2345] httpd -f -h /http -p 8080 -- Old web server
Without the `:ID` to the service the latter will overwrite the former
and only the old web server would be started and supervised.
Conditional Loading
-------------------
Finit support conditional loading of stanzas. The following example is
take from the `system/hotplug.conf` file in the Finit distribution.
Here we only show a simplified subset.
Starting with the `nowarn` option.
service nowarn name:udevd pid:udevd /lib/systemd/systemd-udevd
service nowarn name:udevd pid:udevd udevd
When loading the .conf file Finit looks for `/lib/systemd/systemd-udevd`
if that is not found Finit automatically logs a warning. The `nowarn`
option disables this warning so that the second line can be evaluated,
which also provides a service named `udevd`.
run nowarn if:udevd <pid/udevd> :1 udevadm settle -t 0
This line is only loaded if we know of a service named `udevd`. Again,
we do not warn if `udevadm` is not found, execution will also stop here
until the PID condition is asserted, i.e., Finit detecting udevd has
started.
run nowarn conflict:udevd [S] mdev -s -- Populating device tree
If `udevd` is not available, we try to run `mdev`, but if that is not
found, again we do not warn.
Conditional loading statements can also be negated, so the previous stanza
can also be written as:
run nowarn if:!udevd [S] mdev -s -- Populating device tree
The reason for using `conflict` in this example is that a conflict can be
resolved. Stanzas marked with `conflict:foo` are rechecked at runtime.
Conditional Execution
---------------------
Similar to conditional loading of stanzas there is conditional runtime
execution. This can be confusing at first, since Finit already has a
condition subsystem, but this is more akin to the qualification to a
runlevel. E.g., a `task [123]` is qualified to run only in runlevel 1,
2, and 3. It is not considered for other runlevels.
Conditional execution qualify a run/task/service based on a condition.
Consider this (simplified) example from the Infix operating system:
run [S] name:startup <pid/sysrepo> confd -b --load startup-config
run [S] if:<usr/fail-startup> name:failure <pid/sysrepo> confd --load failure-config
The two run statements reside in the same .conf file so Finit runs them
in true sequence. If loading the file `startup-config` fails confd sets
the condition `usr/fail-startup`, thus allowing the next run statement
to load `failure-config`.
Notice the critical difference between the `<pid/sysrepo>` condition and
`if:<usr/fail-startup>`. The former is a condition for starting and the
latter is a condition to check if a run/task/service is qualified to
even be considered.
Conditional execution statements can also be negated, so provided the
file loaded did the opposite, i.e., set a condition on success, the
previous stanza can also be written as:
run [S] if:<!usr/startup-ok> name:failure <pid/sysrepo> confd ...
-94
View File
@@ -1,94 +0,0 @@
SysV Init Compatibility
=======================
It is not possible to run unmodified SysV init systems with Finit. This
was never the intention and is not the strength of Finit. However, it
comes with a few SysV Init compatibility features to ease the transition
from a serialized boot process.
SysV Init Scripts
-----------------
**Syntax:** `sysv [LVLS] <COND> /path/to/init-script -- Optional description`
> `<COND>` is described in the [Services](services.md) section.
Similar to `task` is the `sysv` stanza, which can be used to call SysV
style scripts. The primary intention for this command is to be able to
reuse much of existing setup and init scripts in Linux distributions.
When entering an allowed runlevel, Finit calls `init-script start`, when
entering a disallowed runlevel, Finit calls `init-script stop`, and if
the Finit .conf, where `sysv` stanza is declared, is modified, Finit
calls `init-script restart` on `initctl reload`. Similar to how
`service` stanzas work.
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`.
> [!TIP]
> See also [SysV Init Compatibility](#sysv-init-compatibility).
`runparts DIRECTORY`
--------------------
For a directory with traditional start/stop scripts that should run, in
order, at bootstrap, Finit provides the `runparts` directive. It runs
in runlevel S, at the very end of it (before calling `/etc/rc.local`)
making it perfect for most scenarios.
For syntax details, see the [Run-parts Scripts](runparts.md) section.
Here is an example take from a Debian installation:
runparts /etc/rc2.d
Files in these directories are usually named `SNNfoo` and `KNNfoo`,
which Finit knows about and automatically appends the correct argument:
/bin/sh -c /etc/rc2.d/S01openbsd-inetd start
or
/bin/sh -c /etc/rc0.d/K01openbsd-inetd stop
Files that do not match this pattern are started similarly but without
the extra command line argument.
Start/Stop Scripts
------------------
For syntax details, see [SysV Init Scripts](#sysv-init-scripts), above.
Here follows an example taken from a Debian installation:
sysv [2345] <pid/syslogd> /etc/init.d/openbsd-inetd -- OpenBSD inet daemon
The init script header could be parsed to extract `Default-Start:` and
other parameters for the `sysv` command to Finit. There is currently no
way to detail a generic syslogd dependency in Finit, so `Should-Start:`
in the header must be mapped to the condition system in Finit using an
absolute reference, here we depend on the sysklogd project's syslogd.
`/etc/rc.local`
---------------
One often requested feature, early on, was a way to run a site specific
script to set up, e.g., static routes or firewall rules. A user can add
a `task` or `run` command in the Finit configuration for this, but for
compatibility reasons the more widely know `/etc/rc.local` is used if
it exists, and is executable. It is called very late in the boot process
when the system has left runlevel S, stopped all old and started all new
services in the target runlevel (default 2).
> In Finit releases before v4.5 this script blocked Finit execution and
> made it as good as impossible to call `initctl` during that time.
`init q`
--------
When `/sbin/finit` is installed as `/sbin/init`, it is possible to use
`init q` to reload the configuration. This is the same as calling
`initctl reload`.
-87
View File
@@ -1,87 +0,0 @@
run (sequence)
--------------
**Syntax:** `run [LVLS] <COND> /path/to/cmd ARGS -- Optional description`
> `<COND>` is described in the [Services](services.md) section.
One-shot command to run in sequence when entering a runlevel, with
optional arguments and description. `run` commands are guaranteed to be
completed before running the next command. Useful when serialization is
required.
> [!WARNING]
> Try to avoid the `run` command. It blocks much of the functionality
> in Finit, like (re)starting other (perhaps crashing) services while a
> `run` task is executing. Use other synchronization mechanisms
> instead, like conditions.
Incomplete list of unsupported `initctl` commands in `run` tasks:
- `initctl runlevel N`, setting runlevel
- `initctl reboot`
- `initctl halt`
- `initctl poweroff`
- `initctl suspend`
To prevent `initctl` from calling Finit when enabling and disabling
services from inside a `run` task, use the `--force` option. See
also the `--quiet` and `--batch` options.
task (parallel)
---------------
**Syntax:** `task [LVLS] <COND> /path/to/cmd ARGS -- Optional description`
> `<COND>` is described in the [Services](services.md) section.
One-shot like 'run', but starts in parallel with the next command.
Both `run` and `task` commands are run in a shell, so basic pipes and
redirects can be used:
task [s] echo "foo" | cat >/tmp/bar
Please note, `;`, `&&`, `||`, and similar are *not supported*. Any
non-trivial constructs are better placed in a separate shell script.
remain:yes
----------
By default, a `run` or `task` will re-run each time its runlevel is
entered, and its `post:` script does not run on completion.
With `remain:yes`, the task runs once and does not re-run on runlevel
re-entry:
task [2345] remain:yes /usr/sbin/setup-firewall -- Firewall setup
This has the following effects:
* The task does not re-run on runlevel re-entry
* The `post:` script runs when:
- The task is explicitly stopped (`initctl stop NAME`)
- The task leaves its valid runlevels (e.g., runlevel change)
This is useful for tasks that set up persistent state where:
* Cleanup should only happen on explicit stop or when leaving valid runlevels
* The setup should not be re-run on every runlevel entry
**Example:** Setting up firewall rules with cleanup on shutdown:
```
task [2345] remain:yes \
post:/usr/sbin/teardown-firewall \
/usr/sbin/setup-firewall -- Firewall setup
```
The firewall rules are created once. The `post:` script runs when
entering runlevel 0 (halt) or 6 (reboot), or on explicit stop.
> [!NOTE]
> The `remain:yes` option is not supported for bootstrap-only tasks
> (tasks with only runlevel S). Bootstrap tasks are deleted immediately
> after completion, and their `post:` scripts never run. A warning is
> logged if `remain:yes` is used on such tasks.
-39
View File
@@ -1,39 +0,0 @@
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
instance of `%i` will in the instantiated directive be replaced with
`eth0`. Inspect the resulting instantiated template with `initctl show
avahi-autoipd:eth0` and check the status of a running instance with:
```
$ initctl status avahi-autoipd:eth0
Status : running
Identity : avahi-autoipd:eth0
Description : ZeroConf for eth0
Origin : /etc/finit.d/enabled/avahi-autoipd@eth0.conf
Environment : -/etc/default/avahi-autoipd-eth0
Command : avahi-autoipd $AVAHI_AUTOIPD_ARGS eth0
PID file : /run/avahi-autoipd.eth0.pid
PID : 4190
User : root
Group : root
Uptime : 24 sec
Restarts : 0 (0/10)
Runlevels : [---2345-789]
Memory : 20.0k
CGroup : /system/avahi-autoipd@eth0 cpu 0 [100, max] mem [0, max]
└─ 4190 avahi-autoipd: [eth0] bound 169.254.1.9
Jul 8 11:51:42 infix-c0-ff-ee finit[1]: Starting avahi-autoipd:eth0[4190]
```
-86
View File
@@ -1,86 +0,0 @@
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]`
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.
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.md) section.
By default, the first two syntax variants *clear* the TTY and *wait* for
the user to press enter before starting getty.
**Example:**
tty [12345] /sbin/getty -L 115200 /dev/ttyAMA0 vt100
tty [12345] /sbin/agetty -L ttyAMA0 115200 vt100 nowait
The `noclear` option disables clearing the TTY after each session.
Clearing the TTY when a user logs out is usually preferable.
The `nowait` option disables the `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.
The `nologin` option disables getty and `/bin/login`, and gives the
user a root (login) shell on the given TTY `<DEV>` immediately.
Needless to say, this is a rather insecure option, but can be very
useful for developer builds, during board bringup, or similar.
Notice the ordering, the `TERM` option to the built-in getty must be
the last argument.
Embedded systems may want to enable automatic `DEV` by supplying the
special `@console` device. This works regardless weather the system
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
may give a user root access without having to log in. However, for
board bringup and system debugging it can come in handy.
One can also use the `service` stanza to start a stand-alone shell:
service [12345] /bin/sh -l
+45 -105
View File
@@ -1,139 +1,79 @@
Distro Recommendations Distro Recommendations
====================== ======================
Finit supports two directory layouts for managing service configurations: By default Finit uses the following directories for configuration files:
1. **Simple layout** - all configuration files directly in `/etc/finit.d/`
2. **Distro layout** - separate `available/` and `enabled/` directories
The distro layout is recommended for distributions that need clear
separation between installed and enabled services, and want to use the
`initctl enable/disable` commands for service management.
## Simple Layout
Finit supports using a flat directory structure:
``` ```
/etc/ /etc/
|-- finit.d/ -- All enabled services |-- finit.d/ -- Regular (enabled) services
| |-- lighttpd.conf | |-- lighttpd.conf
| `- *.conf | `- *.conf
|-- finit.conf -- Bootstrap tasks and services |-- finit.conf -- Bootstrap tasks and services
: :
``` ```
In this layout, you enable a service by placing its `.conf` file in To enable a service one simply drops a small configuration file in the
`/etc/finit.d/` and disable it by removing the file. This works well for `/etc/finit.d/` directory. This practice works with systems that
embedded systems or custom setups where services are managed by other tools keep disabled services elsewhere, or generates them as needed from some
or generated dynamically. other tool.
> [!NOTE] No tooling support Distributions, however, may want a clearer separation of enabled and
> The `initctl enable/disable` commands **do not work** with this layout. available (installed but not enabled) services. They may even want to
> You must manually manage files in `/etc/finit.d/`. customize the directories used, for brand labeling or uniformity.
## Distro Layout To that end Finit allows for a sub-directory `/etc/finit.d/available/`
where installed but disabled services can reside. Adding a symlink to a
configuration in this sub-directory enables the service, but it will not
be started.
Distributions typically want clearer separation between available (installed) To change the default configuration directory and configuration file
and enabled services. Finit supports this through the `available/` and names the Finit `configure` script offers the following two options at
`enabled/` subdirectories: build time:
```
/etc/
|-- finit.d/
| |-- available/ -- Installed but disabled services
| | |-- httpd.conf
| | |-- ntpd.conf
| | `-- sshd.conf
| |-- enabled/ -- Enabled services (symlinks)
| | `- sshd.conf -- Symlink to ../available/sshd.conf
|-- finit.conf -- Bootstrap tasks and services
:
```
In this layout:
- **available/** contains all installed service configurations
- **enabled/** contains symlinks to configurations that should start at boot
- Services are enabled/disabled by creating/removing symlinks
> [!IMPORTANT] Recommended
> This is the recommended layout. In fact, the `initctl enable/disable`
> commands **require** this layout with both `available/` and `enabled/`
> directories and will not work without it.
## Managing Services with initctl
When using the distro layout, the `initctl` tool provides convenient commands
for managing service configurations:
```
list List all .conf in /etc/finit.d/
enable <CONF> Enable .conf by creating symlink in enabled/
disable <CONF> Disable .conf by removing symlink from enabled/
reload Reload *.conf in /etc/finit.d/ (activate changes)
```
Example usage:
```bash
# Enable sshd (creates enabled/sshd.conf -> ../available/sshd.conf)
initctl enable sshd
# Disable httpd (removes enabled/httpd.conf symlink)
initctl disable httpd
# Apply changes (reload configuration and start/stop services)
initctl reload
```
The `.conf` suffix is optional - `initctl` adds it automatically if missing.
> [!NOTE] Remember `initctl reload`
> Changes made with `enable`/`disable` take effect only after running
> `initctl reload`, unless Finit was built with `--enable-auto-reload`
> which automatically detects and applies configuration changes.
### Service Overrides
The `initctl` tool only operates on symlinks in the `enabled/` directory.
If you place a regular (non-symlink) `.conf` file directly in the parent
directory (e.g., `/etc/finit.d/`), `initctl` will ignore it. This allows
you to create system-level overrides that cannot be accidentally disabled
by package management tools.
## Customizing Directory Paths
Distributions can customize the directory names and locations at build time
using the Finit `configure` script:
```sh ```sh
./configure --with-rcsd=/etc/init.d --with-config=/etc/init.d/init.conf ./configure --with-rcsd=/etc/init.d --with-config=/etc/init.d/init.conf
``` ```
This changes the default `/etc/finit.d/` to `/etc/init.d/` and moves the > **Note:** remember `--prefix` et al as well, the default is likely
bootstrap configuration file accordingly. > *not* what you want. See the [build docs][1] for details.
> [!IMPORTANT] Remember to set `--prefix` The resulting directory structure is depicted below. Please notice how
> Remember to set `--prefix` and related options appropriately. The default `/etc/finit.conf` now resides in the same sub-directory as a non-symlink
> prefix is `/usr/local`, which is likely not what you want for a system `/etc/init.d/init.conf`:
> init. See the [build documentation][1] for details.
Example with custom paths:
``` ```
/etc/ /etc/
|-- init.d/ |-- init.d/
| |-- available/ -- Installed services | |-- available/ -- Regular (disabled) services
| | |-- httpd.conf | | |-- httpd.conf
| | |-- ntpd.conf | | |-- ntpd.conf
| | `-- sshd.conf | | `-- sshd.conf
| |-- enabled/ -- Enabled services (symlinks) | |-- sshd.conf -- Symlink to available/sshd.conf
| | `- sshd.conf -- Symlink to ../available/sshd.conf
| `- init.conf -- Bootstrap tasks and services | `- init.conf -- Bootstrap tasks and services
: :
``` ```
Notice how both the service directory and bootstrap configuration file now To facilitate the task of managing configurations, be it a service,
use the custom `/etc/init.d/` path specified at build time. task, run, or other stanza, the `initctl` tool has a a few built-in
commands:
```
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/]
reload Reload *.conf in /etc/finit.d/ (activates changes)
```
To enable a service like `sshd.conf`, above, use
initctl enable sshd
The `.conf` suffix is not needed, `initctl` adds it implicitly if it is
missing. The `disable` command works in a similar fashion.
Note, however, that `initctl` only operates on symlinks and it always
requires the `available/` sub-directory. Any non-symlink in the parent
directory, here `/etc/init.d/`, will be considered a system override by
`initctl`.
[1]: build.md#configure [1]: build.md#configure
-137
View File
@@ -1,137 +0,0 @@
Configuration 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](initctl.md) tool.
See the [contrib/][contrib] directory on GitHub for examples, or take a
peek at systems using Finit, like [Infix OS][infix] and [myLinux][].
> [!TIP]
> As of Finit v4.4, `.conf` lines can be broken up using the standard UNIX
> continuation character (`\`), trailing comments are also supported. The
> latter means you must escape any hashes used in directives and descriptions
> (`\#`). For more on this and examples, see the [finit.conf(5)][] manual or
> the [Configuration](config/index.md) section.
```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
# 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)
# 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
# log file is rotated with the above settings. The condition declares
# a dependency on a system default route (gateway) to be set. A single
# <!> at the beginning means ntpd does not respect SIGHUP for restart.
service [2345] log:/var/log/ntpd.log <!net/route/default> ntpd -n -l -I eth0 -- NTP daemon
# For multiple instances of the same service, add :ID somewhere between
# the service/run/task keyword and the command.
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 --
# 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
# Use built-in getty for serial port and USB serial
#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
```
The `service` stanza, as well as `task`, `run` and others are described in
full in the [Services Syntax](config/services.md) section.
Here's a quick overview of some of the most common components needed to start
a UNIX daemon:
```
service [LVLS] <COND> log env:[-]/etc/default/daemon daemon ARGS -- Example daemon
^ ^ ^ ^ ^ ^ ^ ^
| | | | | | | `---------- Optional description
| | | | | | `------------------ Daemon arguments
| | | | | `------------------------- Path to daemon
| | | | `---------------------------------------------------- Optional env. file
| | | `-------------------------------------------------------- Redirect output to log
| | `--------------------------------------------------------------- Optional conditions
| `---------------------------------------------------------------------- Optional Runlevels
`------------------------------------------------------------------------------ Supervised program (daemon)
```
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
Dependencies are handled using [conditions](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
Here is another example where we instruct Finit to not start BusyBox
`ntpd` until `syslogd` has started properly. Finit waits for `syslogd`
to create its PID file, by default `/var/run/syslogd.pid`.
service [2345] log <!pid/syslogd> ntpd -n -N -p pool.ntp.org
service [S12345] syslogd -n -- Syslog daemon
Notice the `log` keyword, BusyBox `ntpd` uses `stderr` for logging when
run in the foreground. With `log` Finit redirects `stdout` + `stderr`
to the system log daemon using the command line `logger(1)` tool.
A service, or task, can have multiple dependencies listed. Here we wait
for *both* `syslogd` to have started and basic networking to be up:
service [2345] log <pid/syslogd,net/route/default> ntpd -n -N -p pool.ntp.org
If either condition fails, e.g. loss of networking, `ntpd` is stopped
and as soon as it comes back up again `ntpd` is restarted automatically.
> [!NOTE]
> Make sure daemons do *not* fork and detach themselves from the controlling
> TTY, usually an `-n` or `-f` flag, or `-D` as in the case of OpenSSH above.
> If it detaches itself, Finit cannot monitor it and will instead try to
> restart it.
[finit.conf(5)]: https://man.troglobit.com/man5/finit.conf.5.html
[infix]: https://kernelkit.github.io
[myLinux]: https://github.com/troglobit/myLinux/
[contrib]: https://github.com/finit-project/finit/tree/master/contrib
-11
View File
@@ -1,11 +0,0 @@
.md-header__topic:first-child {
font-weight: 500;
font-style: italic;
}
.md-header__title {
font-size: 1.1rem;
font-style: italic;
font-weight: 500;
line-height: 2.6rem;
}
-314
View File
@@ -1,314 +0,0 @@
Finit Features
==============
This page highlights some of Finit's key features with examples and usage
scenarios. For complete documentation, configuration syntax, and advanced
options, see the [Configuration](config/index.md) section.
**Process Supervision**
Start, monitor and restart services should they fail.
**Getty**
Finit supports external getty but also comes with a limited built-in
Getty, useful for really small systems. A getty sets up the TTY and
waits for user input before handing over to `/bin/login`, which is
responsible for handling the actual authentication.
```conf
tty [12345] /dev/tty1 nowait linux
tty [12345] /dev/ttyAMA0 noclear vt100
tty [12345] /sbin/getty -L /dev/ttyAMA0 vt100
```
Users of embedded systems may want to enable automatic serial console
with the special `@console` device. This works regardless whether the
system uses `ttyS0`, `ttyAMA0`, `ttyMXC0`, or anything else. Finit
figures it out by querying sysfs: `/sys/class/tty/console/active`.
```conf
tty [12345] @console linux noclear
```
Notice the optional `noclear`, `nowait`, and `nologin` flags. The
latter is for skipping the login process entirely. For more information,
see the [TTY and Consoles](config/tty.md) section.
**Runlevels**
Support for SysV init-style [runlevels][5] is available, in the same
minimal style as everything else in Finit. The `[2345]` syntax can be
applied to service, task, run, and TTY stanzas.
Reserved runlevels are 0 and 6, halt and reboot, respectively just like
SysV init. Runlevel 1 can be configured freely, but is recommended to
be kept as the system single-user runlevel since Finit will not start
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
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
[`initctl`](initctl.md) tool.
**Conditions**
As mentioned previously, Finit has an advanced dependency system to
handle synchronization, called [conditions](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
```
> [!TIP]
> 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
different stages of the boot process and at runtime. Plugins are
written in C and compiled into a dynamic library loaded automatically by
finit at boot. A basic set of plugins are bundled in the `plugins/`
directory.
Capabilities:
- **Hooks**
Hook into the boot at predefined points to extend Finit
- **I/O**
Listen to external events and control Finit behavior/services
Extensions and functionality not purely related to what an `/sbin/init`
needs to start a system are available as a set of plugins that either
hook into the boot process or respond to various I/O.
For more information, see the [Plugins](plugins.md) section.
**Automatic Reload**
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.
For some use-cases the extra step of calling `initctl reload` creates an
unnecessary overhead, which can be removed at build-time using:
configure --enable-auto-reload
**Linux Capabilities**
Finit supports Linux capabilities, allowing services to run with minimal
required privileges instead of running as root. This improves security by
following the principle of least privilege.
```conf
service [2345] name:nginx \
www-data:www-data \
caps:^cap_net_bind_service \
/usr/sbin/nginx -g 'daemon off;'
```
In this example, nginx runs as the unprivileged `www-data` user but retains
the ability to bind to privileged ports (80, 443) through the
`cap_net_bind_service` capability.
The `caps:` directive uses the IAB (Inheritable, Ambient, Bounding) format:
- `^` = Ambient (recommended) - capabilities survive exec()
- `%` = Inheritable only - requires file capabilities
- `!` = Bounding - block from acquiring capability
Multiple capabilities can be specified as comma-separated:
```conf
caps:^cap_net_raw,^cap_net_admin,!cap_sys_admin
```
See the [Linux Capabilities](config/capabilities.md) section for detailed
information, examples, and security best practices.
**Supplementary Groups**
Finit supports supplementary groups for services, allowing them to access
resources owned by multiple groups without running as root. This complements
capabilities for fine-grained privilege control.
```conf
service @caddy:caddy,ssl-cert /usr/bin/caddy run
```
In this example, the Caddy web server runs as user `caddy` with primary group
`caddy`, but also has access to resources owned by the `ssl-cert` group (such
as TLS certificates).
Finit automatically reads the user's supplementary group membership from
`/etc/group`. Additional groups can be specified explicitly using the syntax
`@user:group,sup1,sup2,...`.
See the [Non-privileged Services](config/services.md#non-privileged-services)
section for more information.
**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 the [Cgroups](config/cgroups.md) section 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.
**Service Management**
Finit includes the `initctl` tool for managing services and system state at
runtime. Key capabilities include:
- **Enable/Disable services**: Manage which services start at boot by moving
configuration files between `/etc/finit.d/available` and
`/etc/finit.d/enabled`
- **Start/Stop/Restart**: Control individual services without requiring a
full system reboot
- **Status monitoring**: View service state, PID, uptime, and resource usage
- **Condition management**: Set and clear user-defined conditions to control
service dependencies
- **Cgroup monitoring**: Real-time process and resource monitoring with
`initctl top`, similar to the traditional `top` command but cgroup-aware
Example commands:
```bash
initctl enable myservice # Enable service for next boot
initctl start myservice # Start service now
initctl status # Show all services
initctl top # Interactive resource monitor
initctl cond set usr/custom # Set custom condition
```
See the [Commands & Status](initctl.md) section for complete documentation.
**Rescue Mode**
Finit provides a built-in rescue mode for system recovery and maintenance.
When booting with the `rescue` kernel parameter, the system enters a
protected maintenance shell.
If the bundled `sulogin` program is available (from Finit, util-linux, or
BusyBox), you'll be prompted for the root password before accessing the
maintenance shell. This provides secure access for system recovery.
If `sulogin` is not available, Finit falls back to reading
`/lib/finit/rescue.conf` and boots the system in a limited maintenance mode.
```
# Kernel command line
linux /vmlinuz root=/dev/sda1 rescue
```
In rescue mode, `initctl` will not work. After fixing the problem, use
`reboot -f` to force reboot.
Rescue mode can be disabled at build time with `configure --without-rescue`.
See the [Rescue Mode](config/rescue.md) section for more information.
**Switch Root**
Finit supports switching from an initramfs to a real root filesystem using
the built-in `initctl switch-root` command. This allows Finit to serve as
the init system in an initramfs for early boot tasks (LUKS unlock, LVM
activation, network boot) before transitioning to the real root.
```bash
# In initramfs, after mounting the real root:
initctl switch-root /mnt/root
```
The switch-root operation:
1. Runs the `HOOK_SWITCH_ROOT` hook for cleanup
2. Stops all services gracefully
3. Moves virtual filesystems (`/dev`, `/proc`, `/sys`, `/run`) to the new root
4. Deletes initramfs contents to free memory
5. Pivots to the new root and execs the new init
See the [Switch Root](switchroot.md) section for complete documentation.
[5]: https://en.wikipedia.org/wiki/Runlevel
Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 320 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 814 KiB

-82
View File
@@ -1,82 +0,0 @@
Introduction
============
![Alpine screenshot](img/alpine-screenshot2.png){ align=right width=40% }
> Reverse engineered from the [EeePC fastinit][]
> "gaps filled with frog DNA …"
> — [Claudio Matsuoka][]
Finit is a process starter and [supervisor][1] designed to run as PID 1
on Linux systems. It consists of a set of [plugins](plugins.md) and can
be set up using [configuration files](config/files.md). Plugins start
at [hook points](plugins.md#hooks) and can run various set up tasks
and/or install event handlers that later provide runtime services, e.g.,
PID file monitoring, or [conditions](conditions.md).
Features
--------
* [Runlevels](config/runlevels.md), defined per service
* [One-shot tasks](config/task-and-run.md), [services](config/services.md) (daemons), or [SysV init][4] start/stop scripts
* [Runparts](config/runparts.md) and `/etc/rc.local` support
* Process supervision similar to [systemd][]
* Fine-grained privilege control:
- [Linux capabilities](config/capabilities.md) for minimal required privileges
- [Supplementary groups](config/services.md#non-privileged-services) for multi-group resource access
* [Sourcing environment files](config/service-env.md)
* [Conditions](conditions.md) for network/process/custom dependencies
* [Readiness notification](config/service-sync.md); 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](config/service-wrappers.md)
* Rudimentary [templating support](config/templating.md)
* [Tooling](initctl.md) to enable/disable services
* [Automatic reload](features.md#automatic-reload) of modified configuration files (optional)
* [Built-in getty](config/tty.md)
* Built-in watchdog, with support for hand-over to [watchdogd][]
* Built-in support for Debian/BusyBox [`/etc/network/interfaces`][3]
* [Cgroups v2](config/cgroups.md), both configuration and monitoring in [`initctl top`](initctl.md)
* [Plugin support](plugins.md) for customization
* Proper [rescue mode](config/rescue.md) with bundled `sulogin` for protected maintenance shell
* [Switch root](switchroot.md) support for initramfs-to-real-root transitions
* Integration with [watchdogd][] for full system supervision
* [Logging](config/logging.md) 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`
For a more thorough overview, see the [Features](features.md) section.
> [!TIP]
> See [SysV Init Compatibility](config/sysv.md) for help to
> quickly get going with an existing SysV or BusyBox init setup.
Origin
------
This project is based on the [original finit][] by [Claudio Matsuoka][]
which was reverse engineered from syscalls of the [EeePC fastinit][].
Finit is developed and maintained by [Joachim Wiberg][] at [GitHub][6].
Please file bug reports, clone it, or send pull requests for bug fixes
and proposed extensions.
[1]: https://en.wikipedia.org/wiki/Process_supervision
[3]: https://manpages.debian.org/unstable/ifupdown2/interfaces.5.en.html
[4]: https://en.wikipedia.org/wiki/Init
[5]: https://en.wikipedia.org/wiki/Runlevel
[6]: https://github.com/finit-project/finit
[dinit]: https://davmac.org/projects/dinit/
[systemd]: https://www.freedesktop.org/wiki/Software/systemd/
[sd_notify()]: https://www.freedesktop.org/software/systemd/man/sd_notify.html
[s6 style]: https://skarnet.org/software/s6/notifywhenup.html
[tmpfiles.d(5)]: https://www.freedesktop.org/software/systemd/man/tmpfiles.d.html
[EeePC fastinit]: https://web.archive.org/web/20071208212450/http://wiki.eeeuser.com/boot_process:the_boot_process
[original finit]: http://helllabs.org/finit/
[Claudio Matsuoka]: https://github.com/cmatsuoka
[Joachim Wiberg]: https://troglobit.com
[watchdogd]: https://troglobit.com/watchdogd.html
[sysklogd]: https://github.com/troglobit/sysklogd/
-167
View File
@@ -1,167 +0,0 @@
Commands & Status
=================
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.
```
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
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
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
kill <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
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
switch-root NEWROOT [INIT] Switch to new root filesystem (initramfs only)
utmp show Raw dump of UTMP/WTMP db
```
For services *not* supporting `SIGHUP` the `<!>` notation in the .conf
file must be used to tell Finit to stop and start it on `reload` and
`runlevel` changes. If `<>` holds more [conditions](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.
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
```
Switch Root
-----------
The `switch-root` command is used when running Finit in an initramfs to
transition to the real root filesystem. This is similar to the standalone
`switch_root(8)` utility but integrated into Finit.
```
initctl switch-root /mnt/root [/sbin/init]
```
Requirements:
- Must be run during runlevel S (bootstrap) or runlevel 1
- The new root must be a mount point (different device than /)
- Can only be used when Finit is running as PID 1 in an initramfs
For complete documentation and usage examples, see the dedicated
[Switch Root](switchroot.md) section.
-14
View File
@@ -1,14 +0,0 @@
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 `./configure --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.
+35 -169
View File
@@ -1,9 +1,14 @@
Hooks & Plugins Hooks & Plugins
=============== ===============
* [Plugins](#plugins)
* [Hooks](#hooks)
* [Bootstrap Hooks](#bootstrap-hooks)
* [Runtime Hooks](#runtime-hooks)
* [Shutdown Hooks](#shutdown-hooks)
Finit can be extended to add general functionality in the form of I/O 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 monitors, or hook plugins.
hook points, see below.
The following sections detail existing plugins and hook points. For The following sections detail existing plugins and hook points. For
more information, see the plugins listed below. more information, see the plugins listed below.
@@ -22,95 +27,33 @@ For your convenience a set of *optional* plugins are available:
system and runs at `HOOK_BASEFS_UP`. The `/var`, `/run`, and `/dev` system and runs at `HOOK_BASEFS_UP`. The `/var`, `/run`, and `/dev`
file systems must be writable for this plugin to work. file systems must be writable for this plugin to work.
This plugin is a wrapper for the [tmpfiles.d(5)][] implementation that Note: On an embedded system both `/var` and `/run` can be `tmpfs` RAM
Finit has. Capable but limited: no aging, attributes, or subvolumes. disks and `/dev` is usually a `devtmpfs`. This must be defined in the
`/etc/fstab` file and in the Linux kernel config.
By default, `/lib/finit/tmpfiles.d` carries all the default .conf
files distributed with Finit. It is read first but can be overridden
by any of the standard tmpfiles.d directories, e.g. `/etc/tmpfiles.d`.
> [!NOTE]
> On an embedded system both `/var` and `/run` can be `tmpfs` RAM
> disks and `/dev` is usually a `devtmpfs`. This must be defined in
> the `/etc/fstab` file and in the Linux kernel config.
* *dbus.so*: Setup and start system message bus, D-Bus, at boot. * *dbus.so*: Setup and start system message bus, D-Bus, at boot.
_Optional plugin._ _Optional plugin._
* *hook-scripts.so*: Trigger the execution of scripts from plugin hook * *hotplug.so*: Setup and start either udev or mdev hotplug daemon, if
points (see [Hooks](#hooks)). _Optional plugin._ available.
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*: Replaced with `/lib/finit/system/10-hotplug.conf`, which
checks for `udevd` and `mdev` at boot. This file can be overridden by a
file in `/etc/finit.d/10-hotplug.conf`.
Enabled by default.
> [!TIP]
> See the [Services](config/services.md) section in the configuration
> guide for an example how to run `mdevd`, alternative to plain mdev.
* *rtc.so*: Restore and save system clock from/to RTC on boot/halt. * *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 * *modules-load.so*: Scans /etc/modules-load.d for modules to modprobe.
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
Since these tasks run in the background, they return `[ OK ]` at boot,
unless the modprobe tool does not exist. Check syslog for warnings
and the actual status of the operation using `initctl`.
> [!IMPORTANT]
> Unlike the traditional .conf `module` directive, which load any listed
> module immediately, this plugin creates a background `task` which load
> the module(s) in the background. The program is modprobe,
> `/sbin/modprobe`, which you can override per .conf file:
>
> set modprobe /path/to/maybe-a-modprobe-wrapper
* *netlink.so*: Listens to Linux kernel Netlink events for gateway and * *netlink.so*: Listens to Linux kernel Netlink events for gateway and
interfaces. These events are then sent to the Finit service monitor 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 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. * *resolvconf.so*: Setup necessary files for `resolvconf` at startup.
_Optional plugin._ _Optional plugin._
* *tty.so*: Watches `/dev`, using inotify, for new device nodes (TTY's) * *tty.so*: Watches `/dev`, using inotify, for new device nodes (TTY's)
to start/stop getty consoles on them on demand. Useful when plugging to start/stop getty consoles on them on demand. Useful when plugging
in a usb2serial converter to login to your embedded device. Enabled in a usb2serial converter to login to your embedded device.
by default.
* *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._ * *x11-common.so*: Setup necessary files for X-Window. _Optional plugin._
@@ -124,117 +67,40 @@ state, etc. Available hook points are:
Hooks 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/runparts.md) 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/down/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/down/foo.sh
> [!IMPORTANT]
> To use hook scripts, even for pre-bootstrap and pre-shutdown tasks,
> you must build with `configure --enable-hook-scripts-plugin`.
### Bootstrap Hooks ### Bootstrap Hooks
* `HOOK_BANNER`, `hook/sys/banner`: The very first point at which a * `HOOK_ROOTFS_UP`: When `finit.conf` has been read and `/` has is
plugin can run. Intended to be used as a banner replacement. mounted — very early
Essentially this runs just before entering runlevel S. Assume nothing
is available, so be prepared to use absolute paths, etc.
* `HOOK_ROOTFS_UP`, `hook/mount/root`: When `finit.conf` has been read * `HOOK_BASEFS_UP`: All of `/etc/fstab` is mounted, swap is available
and `/` has is mounted — very early 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, * `HOOK_SYSTEM_UP`: All services *and* everything in `/etc/finit.d`
swap is available and default init signals are setup has been launched
* `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
### Runtime Hooks ### Runtime Hooks
* `HOOK_SVC_RECONF`, N/A: Called when the user has changed something in * `HOOK_SVC_RECONF`: Called when the user has changed something in the
the `/etc/finit.d` directory and issued `SIGHUP`. The hook is called `/etc/finit.d` directory and issued `SIGHUP`. The hook is called when
when all modified/removed services have been stopped. When the hook all modified/removed services have been stopped. When the hook has
has completed, Finit continues to start all modified and new services. completed, Finit continues to start all modified and new services.
* `HOOK_RUNLEVEL_CHANGE`, N/A: Called when the user has issued a * `HOOK_RUNLEVEL_CHANGE`: Called when the user has issued a runlevel
runlevel change. The hook is called when services not matching the change. The hook is called when services not matching the new
new runlevel have been been stopped. When the hook has completed, runlevel have been been stopped. When the hook has completed, Finit
Finit continues to start all services in the new runlevel. continues to start all services in the new runlevel.
### Switch Root Hooks
* `HOOK_SWITCH_ROOT`, `hook/sys/switchroot`: Called when
`initctl switch-root` is issued, before the transition begins. Use
this hook to save state, unmount initramfs-only filesystems, or perform
cleanup before switching to the new root. Only runs when Finit is
operating as PID 1 in an initramfs.
See the [Switch Root](switchroot.md) section for more information.
### Shutdown Hooks ### Shutdown Hooks
* `HOOK_NETWORK_DN`, `hook/net/down`: Called right after having changed * `HOOK_SHUTDOWN`: Called at shutdown/reboot, right before all
to runlevel 6, or 0, when all services have received their 'stop' signal. services are sent `SIGTERM`
* `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!
Plugins like `tty.so` extend finit by acting on events, they are called 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()` I/O plugins and are called from the finit main loop when `poll()`
detects an event. See the source code for `plugins/*.c` for more help detects an event. See the source code for `plugins/*.c` for more help
and ideas. and ideas.
[tmpfiles.d(5)]: https://www.freedesktop.org/software/systemd/man/tmpfiles.d.html
-25
View File
@@ -1,25 +0,0 @@
Requirements
============
Finit is capable of running on both desktop/server systems with udev and
embedded systems that usually come with BusyBox mdev. Some systems have
systemd-udev or eudev today instead of the original udev, Finit probes
for all of them at runtime and expects `/dev/` to be a writable file
system using `devtmpfs`. It is also possible to run on a statically set
up `/dev` if needed. It is however not a good idea to have both udev
and mdev installed at the same time, this will lead to unpredictable
results.
At boot Finit calls either `mdev` or `udevd` to populate `/dev`, this is
done slightly differently and on systems with udev you might want to add
the following one-shot task early in your `/etc/finit.conf`:
```conf
run [S] udevadm settle --timeout=120 -- Waiting for udev
```
Finit has a built-in Getty for TTYs, but requires a working `/bin/login`
or `/bin/sh`, if no TTYs are configured in `/etc/finit.conf`.
For a fully operational system `/var`, `/run` and `/tmp` must be set up
properly in `/etc/fstab` -- which is iterated over at boot.
-64
View File
@@ -1,64 +0,0 @@
Runlevel Support
================
Basic support for [runlevels][5] is included in Finit from v1.8. By
default all services, tasks, run commands and TTYs listed without a set
of runlevels get a default set `[234]` assigned. The default runlevel
after boot is 2.
Finit supports runlevels 0-9, and S, with 0 reserved for halt, 6 reboot
and S for services that only run at bootstrap. Runlevel 1 is the single
user level, where usually no networking is enabled. In Finit this is
more of a policy for the user to define. Normally only runlevels 1-6
are used, and even more commonly, only the default runlevel is used.
To specify an allowed set of runlevels for a `service`, `run` command,
`task`, or `tty`, add `[NNN]` to your `/etc/finit.conf`, like this:
```
service [S12345] syslogd -n -x -- System log daemon
run [S] /etc/init.d/acpid start -- Starting ACPI Daemon
task [S] /etc/init.d/kbd start -- Preparing console
service [S12345] <pid/syslogd> klogd -n -x -- Kernel log daemon
tty [12345] /dev/tty1
tty [2] /dev/tty2
tty [2] /dev/tty3
tty [2] /dev/tty4
tty [2] /dev/tty5
tty [2] /dev/tty6
```
In this example syslogd is first started, in parallel, and then acpid is
called using a conventional SysV init script. It is called with the run
command, meaning the following task command to start the kbd script is
not called until the acpid init script has fully completed. Then the
keyboard setup script is called in parallel with klogd as a monitored
service.
Again, tasks and services are started in parallel, while run commands
are called in the order listed and subsequent commands are not started
until a run command has completed. Also, task and run commands are run
in a shell, so pipes and redirects can be used.
The following examples illustrate this. Bootstrap task and run commands
are also removed when they have completed, `initctl show` will not list
them.
```
task [S] echo "foo" | cat >/tmp/bar
run [S] echo "$HOME" >/tmp/secret
```
Switching between runlevels can be done by calling init with a single
argument, e.g. <kbd>init 5</kbd>, or using `initctl runlevel 5`, both
switch to runlevel 5. When changing runlevels Finit also automatically
reloads all `.conf` files in the `/etc/finit.d/` directory. So if you
want to set a new system config, switch to runlevel 1, change all config
files in the system, and touch all `.conf` files in `/etc/finit.d`
before switching back to the previous runlevel again — that way Finit
can both stop old services and start any new ones for you, without
rebooting the system.
[5]: https://en.wikipedia.org/wiki/Runlevel
-49
View File
@@ -1,49 +0,0 @@
Runparts & `/etc/rc.local`
==========================
At the end of the boot, when all bootstrap (`S`) tasks and services have
started, but not networking, Finit calls its built-in [run-parts(8)][]
command on any configured `runparts <DIR>` directory. This happens just
before changing to the configured runlevel (default 2). (Networking is
enabled just prior to changing from single user mode.)
```shell
runparts /etc/rc.d/
```
Right after the runlevel change when all services have started properly,
`/etc/rc.local` is called.
No configuration stanza in `/etc/finit.conf` is required for `rc.local`.
If it exists and is an executable shell script Finit calls it at the very
end of the boot, before calling the `HOOK_SYSTEM_UP`. See more in the
[Hook Scripts](plugins.md#hooks) section.
### 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:
- `initctl cond`: only operate on 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
> [!TIP]
> you can set a `usr/` condition in `/etc/rc.local` and have a
> service/task in runlevel 2 depend on it to execute.
[run-parts(8)]: https://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
+44 -24
View File
@@ -1,13 +1,15 @@
Finit Services
==============
Starting & Monitoring Starting & Monitoring
===================== ---------------------
Finit can start and monitor the following types of daemons: Finit can start and monitor the following types of daemons:
* Forks to background, creates a PID file * Forks to background, creates a PID file
* Runs in foreground and signals ready by: * Runs in foreground:
- creating a PID file - creates a PID file
- does not create a PID file -- Finit can create it for you (optional) - does not create a PID file -- Finit can create it for you (optional)
- [other mechanism][1] (systemd, s6)
Finit can *not* start and monitor a daemon that: Finit can *not* start and monitor a daemon that:
@@ -20,38 +22,56 @@ Finit can *not* start and monitor a daemon that:
| ✔ | No | No | Yes, optionally | | ✔ | No | No | Yes, optionally |
| ✘ | Yes | No | No | | ✘ | Yes | No | No |
> [!NOTE] > **Note:** PID files is one mechanism used to assert conditions to
> PID files is one mechanism used to assert conditions to synchronize > synchronize the start and stop of other, dependent, services.
> the start and stop of other, dependent, services. Other mechanisms
> are described in the [Service Synchronization][1] section.
### Forks to bg w/ PID file ### Forks to Background w/ PID File
There are two syntax variants, type 1 and type 2. The former is the service pid:!/run/serv.pid serv -- Forking service
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 ### Runs in Foreground w/ PID File
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 fg w/ PID file
service serv -n -p -- Foreground service w/ PID file service serv -n -p -- Foreground service w/ PID file
### Runs in fg w/o PID file ### Runs in Foreground w/o PID File
Same as previous, but we tell Finit to create the PID file, because we Same as previous, but we tell Finit to create the PID file, because we
need it to synchronize start/stop of a dependent service. need it to synchronize start/stop of a dependent service.
service pid:/run/serv.pid serv -n -- Foreground service w/o PID file service pid:/run/serv.pid serv -n -- Foreground service w/o PID file
### Runs in fg w/ custom 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 service pid:/run/servy.pid serv -n -p -P /run/servy.pid -- Foreground service w/ custom PID file
[1]: config/service-sync.md
State Machine
-------------
A service is bound to a state machine that is in one of six (6) states.
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 service state machine](svc-machine.png "The service state machine")
The current state depends on the two following conditions:
* `E`: Service enabled. In order for `E` to be satisfied, the service
must be allowed to run in the current runlevel and not be stopped.
A service may be stopped, or blocked, for several reasons:
- The user has manually stopped the service using `initctl stop NAME`
- 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
* `C`: Service conditions are satisfied:
- `on` (+): The condition is asserted.
- `off` (-): The condition is deasserted.
- `flux` (~): The condition state is unknown.
For a detailed description of conditions, and how to debug them,
see the [Finit Conditions](conditions.md) document.
-30
View File
@@ -1,30 +0,0 @@
State Machine
=============
A service is bound to a state machine that is in one of ten states. For
run/tasks there is an additional end state called `DONE`. All processes
managed by Finit start in the `HALTED` state. The image shows how both
conditions and commands drive the machine.
![The service state machine](img/svc-machine.png "The service state machine")
The current state depends on the two following conditions:
* `E`: Service enabled. In order for `E` to be satisfied, the service
must be allowed to run in the current runlevel and not be stopped.
A service may be stopped, or blocked, for several reasons:
- The user has manually stopped the service using `initctl stop NAME`
- 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
* `C`: Service conditions are satisfied:
- `on` (+): The condition is asserted.
- `off` (-): The condition is deasserted.
- `flux` (~): The condition state is unknown.
For a detailed description of conditions, and how to debug them,
see the [Finit Conditions](conditions.md) document.
Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

-148
View File
@@ -1,148 +0,0 @@
Switch Root
===========
Finit supports switching from an initramfs to a real root filesystem
using the `initctl switch-root` command. This is useful for systems
that use an initramfs for early boot (LUKS, LVM, network boot, etc.)
and need to transition to the real root before starting services.
Usage
-----
```sh
initctl switch-root NEWROOT [INIT]
```
- `NEWROOT`: Path to the mounted new root filesystem (e.g., `/mnt/root`)
- `INIT`: Optional path to init on the new root (default: `/sbin/init`)
Requirements
------------
1. Must be run during runlevel S (bootstrap) or runlevel 1
2. `NEWROOT` must be a mount point (different device than /)
3. `INIT` must exist and be executable on the new root
4. Finit must be running as PID 1 (in initramfs)
How It Works
------------
1. Runs `HOOK_SWITCH_ROOT` for any cleanup scripts/plugins
2. Runs `HOOK_SHUTDOWN` to notify plugins
3. Stops all services and kills remaining processes
4. Exits all plugins gracefully
5. Moves `/dev`, `/proc`, `/sys`, `/run` to new root
6. Deletes initramfs contents (if on tmpfs/ramfs) to free memory
7. Moves new root mount to `/`
8. Chroots to new root
9. Reopens `/dev/console` for stdin/stdout/stderr
10. Execs new init as PID 1
Example: Initramfs finit.conf
-----------------------------
Configuration file `/etc/finit.conf` in the initramfs:
```
# /etc/finit.conf in initramfs
# Mount the real root filesystem
run [S] name:mount-root /bin/mount /dev/sda1 /mnt/root -- Mounting root filesystem
# Switch to real root after mount completes
run [S] name:switch-root /sbin/initctl switch-root /mnt/root -- Switching to real root
```
For more complex setups (LUKS, LVM, etc.):
```
# Unlock LUKS volume
run [S] name:cryptsetup /sbin/cryptsetup open /dev/sda2 cryptroot -- Unlocking encrypted root
# Activate LVM
run [S] name:lvm /sbin/lvm vgchange -ay -- Activating LVM volumes
# Mount root
run [S] name:mount-root /bin/mount /dev/vg0/root /mnt/root -- Mounting root
# Switch root
run [S] name:switch-root /sbin/initctl switch-root /mnt/root -- Switching to real root
```
Example: Using Runlevel 1 for Switch Root
-----------------------------------------
For more complex initramfs setups where ordering of tasks becomes
difficult in runlevel S, you can perform the switch-root in runlevel 1:
```
# /etc/finit.conf in initramfs
# Start mdevd for device handling
service [S] name:mdevd notify:s6 /sbin/mdevd -D %n -- Device event daemon
run [S] name:coldplug <service/mdevd/ready> /sbin/mdevd-coldplug -- Coldplug devices
# Mount the real root filesystem (after devices are ready)
run [S] name:mount-root <run/coldplug/success> /bin/mount /dev/sda1 /mnt/root -- Mounting root
# Transition to runlevel 1 after all S tasks complete
# The switch-root runs cleanly in runlevel 1
run [1] name:switch-root /sbin/initctl switch-root /mnt/root -- Switching to real root
```
This approach separates the initramfs setup (runlevel S) from the
switch-root operation (runlevel 1), making task ordering simpler.
Hooks
-----
The `HOOK_SWITCH_ROOT` hook runs before the switch begins. Use it for:
- Saving state to the new root
- Unmounting initramfs-only mounts
- Cleanup tasks
Plugins can register for `HOOK_SWITCH_ROOT` just like other hooks:
```c
static void my_switch_root_hook(void *arg)
{
/* Cleanup before switch_root */
}
static plugin_t plugin = {
.name = "my-plugin",
.hook[HOOK_SWITCH_ROOT] = {
.cb = my_switch_root_hook
}
};
PLUGIN_INIT(plugin_init)
{
plugin_register(&plugin);
}
```
Conditions
----------
After switch_root, the new finit instance starts fresh. No conditions
or state are preserved across the switch. The new finit will:
1. Re-read `/etc/finit.conf` from the new root
2. Re-initialize all conditions
3. Start services according to the new configuration
See Also
--------
- [switch_root(8)](https://man7.org/linux/man-pages/man8/switch_root.8.html) - util-linux switch_root utility
- [Kernel initramfs documentation](https://docs.kernel.org/filesystems/ramfs-rootfs-initramfs.html)
-38
View File
@@ -1,38 +0,0 @@
Bundled Watchdog Daemon
=======================
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. 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.
> [!NOTE]
> The watchdog reboot delegation can be enabled with the `reboot-watchdog`
> configuration option in `/etc/finit.conf`. By default this is disabled
> and the system reboots directly via the SoC using the kernel's `reboot(2)`
> syscall. See [Runlevels](config/runlevels.md) for details.
The delegation is performed at the very last steps of system shutdown,
if reboot has been selected, `reboot-watchdog` is enabled, 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.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View File

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

-7
View File
@@ -1,7 +0,0 @@
.deps/*
.libs/*
.dirstamp
*.lo
libsystemd.*
Makefile
Makefile.in
-14
View File
@@ -1,14 +0,0 @@
# libsystemd replacement library
lib_LTLIBRARIES = libsystemd.la
libsystemd_la_SOURCES = sd-daemon.c sd-daemon.h
libsystemd_la_LDFLAGS = -version-info 0:0:0
libsystemd_la_CFLAGS = $(lite_CFLAGS)
libsystemd_la_LIBADD = $(lite_LIBS)
# pkg-config support
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libsystemd.pc
# Install header to systemd/ subdirectory
systemddir = $(includedir)/systemd
systemd_HEADERS = sd-daemon.h
-10
View File
@@ -1,10 +0,0 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libsystemd
Description: Finit replacement for systemd notification library
Version: @PACKAGE_VERSION@
Libs: -L${libdir} -lsystemd
Cflags: -I${includedir}
-221
View File
@@ -1,221 +0,0 @@
/* SPDX-License-Identifier: MIT-0 */
/*
* systemd notify protocol, supporting readiness notification on startup
* and reloading, according to the protocol defined at:
* https://www.freedesktop.org/software/systemd/man/latest/sd_notify.html
*
* This protocol is guaranteed to be stable as per:
* https://systemd.io/PORTABILITY_AND_STABILITY/
*/
#define _GNU_SOURCE 1
#include <errno.h>
#include <inttypes.h>
#include <signal.h>
#include <stdbool.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <time.h>
#include <unistd.h>
#ifdef _LIBITE_LITE
# include <libite/lite.h>
#else
# include <lite/lite.h>
#endif
#include "sd-daemon.h"
/*
* NOTE: As per spec., this function does not return POSIX OK(0) but
* rather "a positive value", i.e., 1.
*/
int sd_notify(int unset_environment, const char *state)
{
struct sockaddr_un sun = {
.sun_family = AF_UNIX,
};
size_t len, sun_len;
const char *path;
ssize_t written;
int sd;
if (!state)
return -EINVAL;
len = strlen(state);
if (len == 0)
return -EINVAL;
/* If the variable is not set, the protocol is a noop */
path = getenv("NOTIFY_SOCKET");
if (!path)
return 0; /* Not set? Nothing to do */
/* Only AF_UNIX is supported, with path or abstract sockets */
if (path[0] != '/' && path[0] != '@')
return -EAFNOSUPPORT;
/* Ensure there is room for NUL byte */
sun_len = strlen(path);
if (sun_len >= sizeof(sun.sun_path))
return -E2BIG;
strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
if (sun.sun_path[0] == '@')
sun.sun_path[0] = 0;
sd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sd == -1)
return -errno;
if (connect(sd, (struct sockaddr *)&sun, offsetof(struct sockaddr_un, sun_path) + sun_len) == -1) {
close(sd);
return -errno;
}
if (unset_environment)
unsetenv("NOTIFY_SOCKET");
written = write(sd, state, len);
close(sd);
if (written != (ssize_t) len)
return written < 0 ? -errno : -EPROTO;
return 1;
}
/*
* Printf-style notification function
*/
int sd_notifyf(int unset_environment, const char *format, ...)
{
va_list ap;
char *state;
int ret;
if (!format)
return -EINVAL;
va_start(ap, format);
ret = vasprintf(&state, format, ap);
va_end(ap);
if (ret < 0)
return -ENOMEM;
ret = sd_notify(unset_environment, state);
free(state);
return ret;
}
/*
* PID-specific notification function
*/
int sd_pid_notify(pid_t pid, int unset_environment, const char *state)
{
char path[256], *env;
size_t len;
int ret;
if (!state)
return -EINVAL;
len = strlen(state);
if (len == 0)
return -EINVAL;
if (pid == 0)
pid = getpid();
env = getenv("NOTIFY_SOCKET");
if (env) {
env = strdup(env);
if (!env)
return -errno;
}
snprintf(path, sizeof(path), "@run/finit/notify/%d", pid);
setenv("NOTIFY_SOCKET", path, 1);
ret = sd_notify(unset_environment, state);
if (env) {
setenv("NOTIFY_SOCKET", env, 1);
free(env);
}
return ret;
}
/*
* PID-specific printf-style notification function
*/
int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...)
{
va_list ap;
char *state;
int ret;
if (!format)
return -EINVAL;
va_start(ap, format);
ret = vasprintf(&state, format, ap);
va_end(ap);
if (ret < 0)
return -ENOMEM;
ret = sd_pid_notify(pid, unset_environment, state);
free(state);
return ret;
}
/*
* Socket activation stub - Finit doesn't support socket activation yet
* Returns 0 (no file descriptors passed)
*/
int sd_listen_fds(int unset_environment)
{
if (unset_environment) {
unsetenv("LISTEN_PID");
unsetenv("LISTEN_FDS");
unsetenv("LISTEN_FDNAMES");
}
return 0;
}
/*
* Watchdog stub - Finit doesn't support watchdog yet
* Returns 0 (no watchdog enabled)
*/
int sd_watchdog_enabled(int unset_environment, uint64_t *usec)
{
if (unset_environment) {
unsetenv("WATCHDOG_PID");
unsetenv("WATCHDOG_USEC");
}
if (usec)
*usec = 0;
return 0;
}
/*
* System detection function
* Returns 1 to indicate systemd compatibility (trick applications)
*/
int sd_booted(void)
{
return 1;
}
-38
View File
@@ -1,38 +0,0 @@
#ifndef SD_DAEMON_H_
#define SD_DAEMON_H_
#include <stdint.h>
#include <sys/types.h>
#define SD_LISTEN_FDS_START 3
/* systemd logging defines for stderr parsing by Finit */
#define SD_EMERG "<0>" /* system is unusable */
#define SD_ALERT "<1>" /* action must be taken immediately */
#define SD_CRIT "<2>" /* critical conditions */
#define SD_ERR "<3>" /* error conditions */
#define SD_WARNING "<4>" /* warning conditions */
#define SD_NOTICE "<5>" /* normal but significant condition */
#define SD_INFO "<6>" /* informational */
#define SD_DEBUG "<7>" /* debug-level messages */
/* Basic notification function */
int sd_notify(int unset_environment, const char *state);
/* Printf-style notification functions */
int sd_notifyf(int unset_environment, const char *format, ...);
/* PID-specific notification functions */
int sd_pid_notify(pid_t pid, int unset_environment, const char *state);
int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...);
/* Socket activation stubs */
int sd_listen_fds(int unset_environment);
/* Watchdog stub */
int sd_watchdog_enabled(int unset_environment, uint64_t *usec);
/* System detection */
int sd_booted(void);
#endif /* SD_DAEMON_H_ */
+23 -19
View File
@@ -1,6 +1,8 @@
# From https://github.com/collectd/collectd/blob/master/configure.ac # From https://github.com/collectd/collectd/blob/master/configure.ac
# Dependency handling currently unused # Dependency handling currently unused
define([toupper], [translit([$1], [a-z], [A-Z])])
define([sanitize], [translit([$1], [-], [_])])
define([enadis], [ifelse([$1], [yes], [disable], [enable])]) define([enadis], [ifelse([$1], [yes], [disable], [enable])])
# AC_PLUGIN(name, default, info) # AC_PLUGIN(name, default, info)
@@ -8,25 +10,27 @@ define([enadis], [ifelse([$1], [yes], [disable], [enable])])
AC_DEFUN([AC_PLUGIN],[ AC_DEFUN([AC_PLUGIN],[
m4_divert_once([HELP_ENABLE], [ m4_divert_once([HELP_ENABLE], [
Optional Plugins:]) 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" enable_plugin="no"
fi], [ define(pluggy, sanitize($1))
if test "x$enable_all_plugins" = "xauto"; then define(PLUGGY, toupper(pluggy))
if test "x$2" = "xyes"; then AC_ARG_ENABLE([$1-plugin], AS_HELP_STRING([--enadis($2)-$1-plugin], [$3]), [
enable_plugin="yes" if test "x$enableval" = "xyes"; then
enable_plugin="yes"
else 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 fi
else AM_CONDITIONAL([BUILD_]PLUGGY[_PLUGIN], test "x$enable_plugin" = "xyes")
enable_plugin="$enable_all_plugins" enable_pluggy="$enable_plugin"])
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")])
+9 -236
View File
@@ -2,7 +2,7 @@
.\" First parameter, NAME, should be all caps .\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1) .\" other parameters are allowed: see man(7), man(1)
.Dd Jul 9, 2025 .Dd June 6, 2021
.\" Please adjust this date whenever revising the manpage. .\" Please adjust this date whenever revising the manpage.
.Dt FINIT 8 SMM .Dt FINIT 8 SMM
.Os Linux .Os Linux
@@ -10,66 +10,22 @@
.Nm finit .Nm finit
.Nd Fast init for Linux systems .Nd Fast init for Linux systems
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm /sbin/finit -- .Nm /sbin/finit
.Op debug .Op finit.status_style=classic
.Op quiet .Op finit.show_status=[on,off]
.Op finit.debug
.Op rescue | recover .Op rescue | recover
.Op single | S .Op single | S
.Op panic=SEC
.Op loglevel=<0-7>
.Op fsck.mode=[auto,skip,force]
.Op fsck.repair=[no,yes,preen]
.Op finit.debug=<true,false>
.Op finit.fstab=/path/to/fstab
.Op finit.cond=foo[,bar[,baz]]
.Op finit.config=/path/to/finit.conf
.Op finit.status_style=<classic,modern>
.Op finit.status=<on,off>
.Nm /sbin/telinit .Nm /sbin/telinit
.Op Fl hv .Op Fl hv
.Op q | Q | s | S | 0-9 .Op q | Q | 0-9
.Sh DESCRIPTION .Sh DESCRIPTION
Fast init for Linux systems. Reverse engineered from the EeePC Fast init for Linux systems. Reverse engineered from the EeePC
fastinit, 10+ years ago by Claudio Matsuoka, "gaps filled with frog fastinit, 10+ years ago by Claudio Matsuoka, "gaps filled with frog
DNA ...". Focus is on small and embedded systems, although Finit is DNA ...". Focus is on small and embedded systems, although Finit is
fully usable on server and desktop systems as well. fully usable on server and desktop systems as well.
.Sh OPTIONS
When
.Sy not
started as PID 1,
.Nm
behaves like
.Nm telinit ,
following classic UNIX command line syntax. The options are:
.Pp .Pp
.Bl -tag -width Ds -compact -offset indent Features include:
.It Fl h
Show built-in help text.
.It Fl v
Show program version.
.El
.Pp
More options are implemented for SysV init support, but are ignored.
.Sh ARGUMENTS
When
.Sy not
started as PID 1,
.Nm ,
or
.Nm telinit ,
take these arguments:
.Pp
.Bl -tag -width Ds -compact -offset indent
.It q | Q
Reload configuration, same as
.Cm initctl reload .
.It 0 - 9
Go to runlevel N, same as
.Cm initctl reload N .
.It s | S
Go to single user mode, runlevel 1.
.El
.Sh FEATURES
.Bl -bullet -width 1n -compact .Bl -bullet -width 1n -compact
.It .It
Runlevels, defined per service Runlevels, defined per service
@@ -87,15 +43,6 @@ Sourcing environment files
.It .It
Conditions for network/process/custom dependencies Conditions for network/process/custom dependencies
.It .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 Pre/Post script actions
.It .It
Tooling to enable/disable services Tooling to enable/disable services
@@ -114,177 +61,12 @@ Plugin support for customization
.It .It
Proper rescue mode with bundled `sulogin` for protected maintenance shell Proper rescue mode with bundled `sulogin` for protected maintenance shell
.El .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 fsck.mode=<auto,force,skip>
Defaults to
.Cm auto ,
unless Finit is built with
.Cm configure --enable-fastboot ,
in which case the default is
.Cm skip .
.It Cm fsck.repair=<preen,yes,no>
Defaults to
.Cm preen ,
unless Finit is built with
.Cm configure --enable-fsckfix ,
in which case the default is
.Cm yes .
This configure option also sets
.Cm fsck.mode=force ,
unless fastboot is also enabled. I.e.,
.Cm configure --enable-fastboot
build option overrides the
.Cm fsck.mode
default value.
.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 .Sh BOOTING
.Pp .Pp
Before laucnhing services, the system needs to be bootstrapped. This Before laucnhing services, the system needs to be bootstrapped. This
involves mounting all filesystems (not already mounted by an initramfs) involves mounting all filesystems (not already mounted by an initramfs)
in in
.Pa /etc/fstab , .Pa /etc/fstab ,
or any alternate
.Pa fstab
file provided on the Finit command line using
.Cm finit.fstab ,
ensuring that necessary filesystems like: ensuring that necessary filesystems like:
.Pa /dev , .Pa /dev ,
.Pa /proc , .Pa /proc ,
@@ -327,22 +109,14 @@ file removed, service B is also stopped.
.Pp .Pp
The following condition families are available today: The following condition families are available today:
.Pp .Pp
.Bl -tag -width service -offset indent .Bl -tag -width pid -offset indent
.It Cm net .It Cm net
Linux netlink events, e.g. net/route/default, net/eth0/up, and Linux netlink events, e.g. net/route/default, net/eth0/up, and
net/et0/running net/et0/running
.It Cm pid .It Cm pid
PID files based on the service declaration PID files basd on the service declaration
.Cm name:id , .Cm name:id ,
gives the condition pid/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 .It Cm sys
System conditions, e.g. sys/key/ctrlaltdel and sys/pwr/fail System conditions, e.g. sys/key/ctrlaltdel and sys/pwr/fail
.It Cm usr .It Cm usr
@@ -398,7 +172,6 @@ Runtime files, including the condition subsystem
.Sh SEE ALSO .Sh SEE ALSO
.Xr finit.conf 5 .Xr finit.conf 5
.Xr initctl 8 .Xr initctl 8
.Xr tmpfiles.d 5
.Sh AUTHORS .Sh AUTHORS
.Nm .Nm
was conceived and reverse engineered by Claudio Matsuoka. Since v1.0, was conceived and reverse engineered by Claudio Matsuoka. Since v1.0,
+83 -368
View File
@@ -2,7 +2,7 @@
.\" First parameter, NAME, should be all caps .\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1) .\" other parameters are allowed: see man(7), man(1)
.Dd July 10, 2025 .Dd Oct 17, 2020
.Dt FINIT.CONF 5 SMM .Dt FINIT.CONF 5 SMM
.Os Linux .Os Linux
.Sh NAME .Sh NAME
@@ -12,79 +12,48 @@
.Nm /etc/finit.conf .Nm /etc/finit.conf
.Nm /etc/finit.d/*.conf .Nm /etc/finit.d/*.conf
.Nm /etc/finit.d/available/*.conf .Nm /etc/finit.d/available/*.conf
.Nm /etc/finit.d/enabled/*.conf
.Sh DESCRIPTION .Sh DESCRIPTION
.Nm Finit .Nm finit
based systems can be set up with a single file: can be configured using only the original
.Pa /etc/finit.conf . .Pa /etc/finit.conf
This is the traditional way of doing it which can be ideal for some file or in combination with
setups since it gives a great overview of the system configuration. .Pa /etc/finit.d/*.conf .
Useful for package-based Linux distributions \(em each package can
provide its own "script" file.
.Pp .Pp
More comprehensive setups, however, require more careful planning. .Bl -tag -width /etc/finit.d/*.conf -offset indent -compact
The recommendation is per-package .It Pa /etc/finit.conf
.Cm *.conf Main configuration file
files in .It Pa /etc/finit.d/*.conf
.Pa /etc/finit.d/available/ . Snippets, usually one service per file
This allows end users to enable and disable parts of the system .El
configuration at runtime. Finit tracks which tasks and services belong
to a given file, so that when the user calls
.Cm initctl reload
to activate the changes they have made, only the affected tasks and
services are stopped, started, or restarted. Hence, this approach is
useful for modern package-based Linux distributions.
.Pp .Pp
The following sections describe the more of this in detail, starting Not all configuration directives are available in
with files, the file format, and available directives. Remember to .Pa /etc/finit.d/*.conf
also visit the other manual pages (references at the bottom). and some directives are only available at bootstrap, runlevel
.Cm S ,
see the section
.Sx Limitations
below for details.
.Sh FILES .Sh FILES
.Bl -tag -width /etc/finit.d/available/*.conf -compact .Bl -tag -width /etc/finit.d/available/*.conf -compact
.It Pa /etc/finit.conf .It Pa /etc/finit.conf
Main configuration file, optional Main configuration file
.It Pa /etc/finit.d/*.conf .It Pa /etc/finit.d/*.conf
Static (system) service definitions Static service definitions
.It Pa /etc/finit.d/available/*.conf .It Pa /etc/finit.d/available/*.conf
Available (installed) services Available services
.It Pa /etc/finit.d/enabled/*.conf .It Pa /etc/finit.d/enabled/*.conf
Enabled services (symlink back) Enabled services, symlinks from available
.El .El
.Pp
Static services,
.Cm .conf
files in
.Pa /etc/finit.d/ ,
cannot be enabled or disabled using
.Cm initctl [enable | disable] service[.conf] .
An enabled service is a symlink back to the corresponding
.Cm ../available/
service
.Cm .conf
file. Please use the
.Cm initctl
tool to manage these symlinks to ensure proper operation.
.Pp
.Sy NOTE:
Previous versions of
.Nm Finit
created symlinks in
.Pa /etc/finit.d/
if
.Pa /etc/finit.d/enabled/
was missing, this is as of v4.4 not supported.
.Sh FILE FORMAT .Sh FILE FORMAT
The file format is line based, empty lines and comments, lines starting Lines starting with `#' are ignored. Note that end-of-line comments are
with `#', are ignored. A configuration directive starts with a keyword NOT supported, comments must be on a line of their own.
followed by a space and the rest of the line is treated as the value.
.Pp .Pp
As of Finit v4.4, configuration directives can be broken up in multiple A configuration stanza must be on a single (long) line and
lines using the continuation character `\\', and trailing comments are .Em cannot
also allowed. Example: be broken up in multiple lines by use of a backslash as the last
.Bd -unfilled -offset indent character.
# 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 .Sh DIRECTIVES
This section lists all supported configuration directives. There also exist This section lists all supported configuration directives. There also exist
deprecated directives, see the Markdown documentation for details on these. deprecated directives, see the Markdown documentation for details on these.
@@ -139,10 +108,6 @@ 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. halt. All other can be used by operating system administrators.
Default: 2 Default: 2
.Pp .Pp
It s recommended to keep runlevel 1 as single-user mode, because
.Nm
disables networking in this mode.
.Pp
.Sy Note: .Sy Note:
only read and executed in runlevel S (bootstrap). 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 .It Cm run Oo LVLS Oc Ao COND Ac Ar /path/to/cmd ARGS Op -- Optional description
@@ -175,13 +140,13 @@ task [s] echo "foo" | cat >/tmp/bar
.Ed .Ed
.It Cm sysv Oo LVLS Oc Ao COND Ac Ar /path/to/script ARGS Op -- Optional description .It Cm sysv Oo LVLS Oc Ao COND Ac Ar /path/to/script ARGS Op -- Optional description
Similar to Similar to
.Cm service .Cm task
is the is the
.Cm sysv .Cm sysv
directive, which can be used to call SysV style start/stop scripts. The 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 traditional primary intention for this command is to be able to re-use much of
SysV init scripts in Linux distributions. existing setup and init scripts in Linux distributions.
.Pp .Pp
When entering an allowed runlevel, Finit calls When entering an allowed runlevel, Finit calls
.Cm init-script start , .Cm init-script start ,
when entering a disallowed runlevel, Finit calls when entering a disallowed runlevel, Finit calls
@@ -194,7 +159,7 @@ on
.Cm initctl reload . .Cm initctl reload .
Similar to how Similar to how
.Cm service .Cm service
directives work. stanzas work.
.Pp .Pp
Forking services started with Forking services started with
.Cm sysv .Cm sysv
@@ -216,12 +181,6 @@ After which they have to be restarted manually using
.Cm initctl restart NAME . .Cm initctl restart NAME .
The number of restarts, the delay between each restart, and more is The number of restarts, the delay between each restart, and more is
configurable, see the options below. configurable, see the options below.
.Pp
.Bd -filled -offset indent
.Sy Tip:
to allow endless restarts, see below option
.Cm respawn
.Ed
.Pp .Pp
For daemons that support it, we recommend appending For daemons that support it, we recommend appending
.Cm --foreground , --no-background , -n , -F , .Cm --foreground , --no-background , -n , -F ,
@@ -235,21 +194,7 @@ services and are supported using the same syntax as forking
.Cm sysv .Cm sysv
services, using the services, using the
.Cm pid:!/path/to/pidfile.pid .Cm pid:!/path/to/pidfile.pid
command modifier syntax. There is an alternative syntax that may be command modifier syntax.
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 .Pp
.Sy Example: in the case of .Sy Example: in the case of
.Cm ospfd .Cm ospfd
@@ -310,51 +255,6 @@ can depend on the
.Cm <pid/bar> .Cm <pid/bar>
condition. condition.
.Pp .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 If a service should not be automatically started, it can be configured
as manual with the as manual with the
.Cm manual:yes .Cm manual:yes
@@ -384,76 +284,17 @@ number of seconds before Finit tries to restart
a crashing service, default: 2 seconds for the first five retries, a crashing service, default: 2 seconds for the first five retries,
then back-off to 5 seconds. The maximum of this configured value then back-off to 5 seconds. The maximum of this configured value
and the above (2 and 5) will be used 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 .It Cm norestart
dont restart on failures, same as dont restart on failures, same as
.Cm restart:0 .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 remain:yes
for
.Cm run
and
.Cm task
only. Prevents the task from re-running on runlevel re-entry and
ensures the
.Cm post:
script runs when the task is explicitly stopped or leaves its valid
runlevels. Similar to systemd's
.Cm RemainAfterExit=yes .
.Pp
.Sy Note:
not supported for bootstrap-only tasks (runlevels [S] only).
.It Cm oncrash:reboot .It Cm oncrash:reboot
when all retries have failed, and the service when all retries have failed, and the service
has has
.Em crashed , .Em crashed ,
if this option is set the system is rebooted. if this option is set the system is rebooted. Note, future releases
.It Cm oncrash:script may include other
Similar to .Cm oncrash:
.Cm oncrash:reboot , actions.
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"
.It Cm reload:'script [args]'
some services do not support SIGHUP but may have other ways to update
the configuration of a running daemon. When
.Cm reload:script
is defined it is preferred over SIGHUP. Like systemd,
.Nm finit
sets
.Cm $MAINPID
as a convenience to scripts, which in effect also allow
.Cm reload:'kill -HUP $MAINPID'
.It Cm stop:'script [args]'
Some services may require alternate methods to be stopped. When
.Cm stop:script
is defined it is preferred over SIGTERM and stop, for
.Cm service
and
.Cm sysv
directives, respectively.
Similar to
.Cm reload:script ,
.Nm finit
sets
.Cm $MAINPID .
.El .El
.Pp .Pp
When stopping a service (run/task/sysv/service), either manually or when When stopping a service (run/task/sysv/service), either manually or when
@@ -471,61 +312,52 @@ e.g.,
.Cm kill:10 .Cm kill:10
to wait 10 seconds before sending SIGKILL. to wait 10 seconds before sending SIGKILL.
.Pp .Pp
Services, including the Services support the
.Cm sysv .Cm pre:script
variant, support pre/post/ready and cleanup scripts: and
.Bl -tag -width 1n .Cm post:script
.It Cm pre:[0-3600,]script command actions as well. These run as the same
called before the sysv/service is stated
.It Cm post:[0-3600,]script
called after the sysv/service has stopped
.It Cm ready:[0-3600,]script
called when the sysv/service is ready
.It Cm cleanup:[0-3600,]script
called when run/task/sysv/service is removed
.El
.Pp
The optional number (0-3600) is the timeout before Finit kills the
script, it defaults to the kill delay value and can be disabled by
setting it to zero. These scripts run as the same
.Cm @USER:GROUP .Cm @USER:GROUP
as the service itself, with any as the service itself, with any
.Cm env:file .Cm env:file
sourced. The scripts must use an absolute path, but are executed from sourced. The scripts must use an absolute path, but are executed from
the the
.Cm $HOME .Cm $HOME
of the given user. The scripts are not called with any argument, but of the given user. The scripts are not called with any argument
both get a set of environment variables: (currently), but both get the
.Pp .Cm SERVICE_IDENT=foo
.Bl -tag -width 1n -compact environment variable set. Here
.It Cm SERVICE_IDENT=foo:1 .Cm foo
.It Cm SERVICE_NAME=foo denotes the identity of the service, which if there are multiple
.It Cm SERVICE_ID=1 services named
.El .Cm foo ,
.Pp may be
The .Cm foo:1 ,
or any unique identifier specified in the .conf file. The
.Cm post:script .Cm post:script
is called with an additional set of environment variables, and yes the is called with an additional set of environment variables:
naming looks like it should be swapped:
.Bl -tag -offset indent -width 1n .Bl -tag -offset indent -width 1n
.It Cm EXIT_CODE=[exited,signal,crashed] .It Cm EXIT_CODE=[exited,signal]
set to one of set to one of
.Cm exited , .Cm exited
.Cm signal ,
or or
.Cm crashed .Cm signal
(see above).
.It Cm EXIT_STATUS=[num,SIGNAME] .It Cm EXIT_STATUS=[num,SIGNAME]
set to one of exit status code from the program, if it exited normally, 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 or the signal name (HUP, TERM, etc.) if it exited due to signal
.El .El
.Pp .Pp
When a run/task/sys/service is removed (disable + reload) it is first The scripts have a default execution time of 3 seconds before they are
stopped and then removed from the runlevel. The SIGKILLed, this can be adjusted using the
.Cm post:script .Cm kill:SEC
always runs when the process has stopped, and the modifier syntax.
.Cm cleanup:script .Pp
runs when the the stanza has been removed from the runlevel. .Sy Note:
the
.Cm pre:script
.Em must
be idempotent, because a service can transition between READY and HALTED
states any number of times before going to RUNNING.
.It Cm runparts Aq DIR .It Cm runparts Aq DIR
Call Call
.Xr run-parts 8 .Xr run-parts 8
@@ -572,7 +404,7 @@ 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 .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 This form of the
.Cm tty .Cm tty
directive uses the built-in getty on the given TTY device stanza uses the built-in getty on the given TTY device
.Ar DEV , .Ar DEV ,
in the given runlevels. in the given runlevels.
.Ar DEV may be the special keyword .Ar DEV may be the special keyword
@@ -582,8 +414,8 @@ useful on embedded systems.
.Pp .Pp
The default baud rate is 0, i.e., keep kernel default. The default baud rate is 0, i.e., keep kernel default.
.Pp .Pp
The `tty` directive inherits runlevel, condition (and other feature) The `tty` stanza inherits runlevel, condition (and other feature)
parsing from the `service` directive. So TTYs can run in one or many parsing from the `service` stanza. So TTYs can run in one or many
runlevels and depend on any condition supported by Finit. This is runlevels and depend on any condition supported by Finit. This is
useful e.g. to depend on `<pid/elogind>` before starting a TTY. useful e.g. to depend on `<pid/elogind>` before starting a TTY.
.Bd -unfilled -offset indent .Bd -unfilled -offset indent
@@ -592,7 +424,7 @@ tty [12345] /dev/ttyAMA0 115200 noclear vt220
.It Cm tty Oo LVLS Oc Ao COND Ac Ar CMD DEV Oo noclear Oc Oo nowait Oc .It Cm tty Oo LVLS Oc Ao COND Ac Ar CMD DEV Oo noclear Oc Oo nowait Oc
This form of the This form of the
.Cm tty .Cm tty
directive is for using an external getty, like agetty or the BusyBox getty. stanza is for using an external getty, like agetty or the BusyBox getty.
.Pp .Pp
By default, these first two syntax variants By default, these first two syntax variants
.Em clear .Em clear
@@ -662,7 +494,7 @@ board bringup and system debugging it can come in handy.
.Pp .Pp
One can also use the One can also use the
.Cm service .Cm service
directive to start a stand-alone shell: stanza to start a stand-alone shell:
.Bd -unfilled -offset indent .Bd -unfilled -offset indent
service [12345] /bin/sh -l service [12345] /bin/sh -l
.Ed .Ed
@@ -687,9 +519,9 @@ 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. (uid:0, gid:0) user does not have a password set, no rescue is possible.
.El .El
.Sh COMMAND MODIFIERS .Sh COMMAND MODIFIERS
The run/task/tty/service/sysv directives take modifiers, or options, to The run/task/tty/service/sysv stanzas take modifiers, or options, to
control their behavior. This section lists them with their limitations. control their behavior. This section lists them with their limitations.
All modifiers must be placed between the directive and its command. All modifiers must be placed between the stanza and its command.
.Bl -tag -width 1n .Bl -tag -width 1n
.It Cm @user:group .It Cm @user:group
Every Every
@@ -894,31 +726,6 @@ the example sets
to denote that it doesn't support SIGHUP. That way Finit will to denote that it doesn't support SIGHUP. That way Finit will
stop/start the service instead of sending SIGHUP at restart/reload stop/start the service instead of sending SIGHUP at restart/reload
events. 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 .Sh CGROUPS
There are three major cgroup configuration directives: There are three major cgroup configuration directives:
.Pp .Pp
@@ -983,10 +790,9 @@ or
service [...] <...> cgroup.maint /path/to/foo args -- description service [...] <...> cgroup.maint /path/to/foo args -- description
.Ed .Ed
.Pp .Pp
The latter form also allows per-stanza limits on the form (notice the The latter form also allows per-stanza limits on the form:
single quotes for arguments that contain spaces):
.Bd -unfilled -offset indent .Bd -unfilled -offset indent
service [...] <...> cgroup.maint:cpu.max:'200000 100000',mem.max:655360 /path/to/foo args -- description service [...] <...> cgroup.maint:cpu.max:10000,mem.max:655360 /path/to/foo args -- description
.Ed .Ed
.Pp .Pp
Notice the comma separation and the Notice the comma separation and the
@@ -1006,97 +812,6 @@ available in your Linux kernel, or the name is misspelled.
Linux cgroups and details surrounding values are not explained in the Linux cgroups and details surrounding values are not explained in the
Finit documentation. The Linux admin-guide cover this well: Finit documentation. The Linux admin-guide cover this well:
.Lk https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html .Lk https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html
.Sh CONDITIONAL LOADING
Finit support conditional loading of stanzas. The following example is
take from the
.Pa system/hotplug.conf
file in the Finit distribution. Here we only show a simplified subset.
.Pp
Starting with the
.Cm nowarn
option.
.Bd -unfilled -offset indent
service nowarn name:udevd pid:udevd /lib/systemd/systemd-udevd
service nowarn name:udevd pid:udevd udevd
.Ed
.Pp
When loading the .conf file Finit looks for
.Pa /lib/systemd/systemd-udevd
if that is not found Finit automatically logs a warning. The
.Cm nowarn
option disables this warning so that the second line can be evaluated,
which also provides a service named
.Cm udevd .
.Bd -unfilled -offset indent
run nowarn if:udevd <pid/udevd> :1 udevadm settle -t 0
.Ed
.Pp
This line is only loaded if we know of a service named
.Cm udevd .
Again, we do not warn if
.Cm udevadm
is not found, execution will also stop here until the PID condition is
asserted, i.e., Finit detecting udevd has started.
.Bd -unfilled -offset indent
run nowarn conflict:udevd [S] mdev -s -- Populating device tree
.Ed
.Pp
If
.Cm udevd
is not available, we try to run
.Cm mdev ,
but if that is not found, again we do not warn.
.Pp
Conditional loading statements can also be negated, so the previous stanza
can also be written as:
.Bd -unfilled -offset indent
run nowarn if:!udevd [S] mdev -s -- Populating device tree
.Ed
.Pp
The reason for using
.Cm conflict
in this example is that a conflict can be resolved. Stanzas marked with
.C, conflict:foo
are rechecked at runtime.
.Sh CONDITIONAL EXECUTION
Similar to conditional loading of stanzas there is conditional runtime
execution. This can be confusing at first, since Finit already has a
condition subsystem, but this is more akin to the qualification to a
runlevel. E.g., a
.Cm task [123]
is qualified to run only in runlevel 1, 2, and 3. It is not considered
for other runlevels.
.Pp
Conditional execution qualify a run/task/service based on a condition.
Consider this (simplified) example from the Infix operating system:
.Bd -unfilled -offset indent
run [S] name:startup <pid/sysrepo> confd -b --load startup-config
run [S] if:<usr/fail-startup> name:failure <pid/sysrepo> confd --load failure-config
.Ed
.Pp
The two run statements reside in the same .conf file so Finit runs them
in true sequence. If loading the file
.Cm startup-config
fails
.Cm confd
sets the condition
.Cm usr/fail-startup ,
thus allowing the next run statement to load
.Cm failure-config .
.Pp
Notice the critical difference between the
.Cm <pid/sysrepo>
condition and
.Cm if:<usr/fail-startup> .
The former is a condition for starting and the latter is a condition to
check if a run/task/service is qualified to even be considered.
.Pp
Conditional execution statements can also be negated, so provided the
file loaded did the opposite, i.e., set a condition on success, the
previous stanza can also be written as:
.Bd -unfilled -offset indent
run [S] if:<!usr/startup-ok> name:failure <pid/sysrepo> confd ...
.Ed
.Sh LIMITATIONS .Sh LIMITATIONS
As of Finit v4 there are no limitations to where As of Finit v4 there are no limitations to where
.Cm .conf .Cm .conf
@@ -1127,6 +842,6 @@ settings in
.Xr finit 8 , .Xr finit 8 ,
.Xr initctl 8 .Xr initctl 8
.Sh AUTHORS .Sh AUTHORS
.Nm Finit .Nm finit
was conceived and reverse engineered by Claudio Matsuoka. Since v1.0, was conceived and reverse engineered by Claudio Matsuoka. Since v1.0,
maintained by Joachim Wiberg, with contributions by many others. maintained by Joachim Wiberg, with contributions by many others.
+34 -120
View File
@@ -2,7 +2,7 @@
.\" First parameter, NAME, should be all caps .\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1) .\" other parameters are allowed: see man(7), man(1)
.Dd July 10, 2025 .Dd June 6, 2021
.\" Please adjust this date whenever revising the manpage. .\" Please adjust this date whenever revising the manpage.
.Dt INITCTL 8 SMM .Dt INITCTL 8 SMM
.Os Linux .Os Linux
@@ -11,7 +11,7 @@
.Nd Control tool for Finit .Nd Control tool for Finit
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm /sbin/initctl .Nm /sbin/initctl
.Op Fl bcfhjlpqtvV .Op Fl bcfhlpqtvV
.Op COMMAND .Op COMMAND
.Sh DESCRIPTION .Sh DESCRIPTION
.Nm .Nm
@@ -24,39 +24,25 @@ This program follows the usual UNIX command line syntax, with long
options starting with two dashes (`-'). The options are as follows: options starting with two dashes (`-'). The options are as follows:
.Bl -tag -width Ds .Bl -tag -width Ds
.It Fl b, -batch .It Fl b, -batch
Batch mode, no screen size probing. Useful for scripting Batch mode, no screen size probing.
.It Fl c, -create .It Fl c, -create
Create missing paths (and files) as needed. Useful with the Create missing paths (and files) as needed. Useful with the edit command.
.Cm edit
command
.It Fl f, -force .It Fl f, -force
Ignore missing files and arguments, never prompt Ignore missing files and arguments, never prompt.
.It Fl h, -help .It Fl h, -help
Show built-in help text 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 .It Fl 1, -once
Only one lap in commands like top Only one lap in commands like top.
.It Fl p, -plain .It Fl p, -plain
Use plain table headings, no ANSI control characters Use plain table headings, no ANSI control characters.
.It Fl q, -quiet .It Fl q, -quiet
Silent, only return status of command Silent, only return status of command.
.It Fl t, -no-heading .It Fl t, -no-heading
Skip table headings Skip table headings.
.It Fl v, -verbose .It Fl v, -verbose
Verbose output, where applicable Verbose output, where applicable.
.It Fl V, -version .It Fl V, -version
Show program version Show program version.
.El .El
.Sh COMMANDS .Sh COMMANDS
.Bl -tag -width Ds .Bl -tag -width Ds
@@ -78,16 +64,7 @@ files in
Create Create
.Cm .conf .Cm .conf
in in
.Pa /etc/finit.d/available . .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 .It Nm Ar delete Ar CONF
Delete Delete
.Cm .conf .Cm .conf
@@ -112,10 +89,9 @@ like
.Ar edit .Ar edit
this tells this tells
.Nm finit .Nm finit
that a configuration has been changed and is a candidate to be reloaded that a configuration has been changed and is a candidate to be restarted
(SIGHUP'ed or restarted) on (or SIGHUP'ed) on
.Cm initctl reload .Cm initctl reload
in dependency order
.It Nm Ar enable Ar CONF .It Nm Ar enable Ar CONF
Enable Enable
.Cm .conf .Cm .conf
@@ -130,40 +106,22 @@ in
.Pa /etc/finit.d/enabled , .Pa /etc/finit.d/enabled ,
i.e., removes symlink i.e., removes symlink
.It Nm Ar reload .It Nm Ar reload
Reload all (touched) Reload
.Cm *.conf in .Cm *.conf in
.Pa /etc/finit.d .Pa /etc/finit.d ,
and activate changes i.e., activates changes
.It Nm Ar cond set Ar COND Op COND ... .It Nm Ar cond set Ar COND
Set (assert) user-defined condition, Set (assert) user-defined condition,
.Cm +usr/COND .Cm +usr/COND
.It Nm Ar cond get Ar COND .It Nm Ar cond clr | clear 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, Clear (deassert) user-defined condition,
.Cm -usr/COND .Cm -usr/COND
.It Nm Ar cond status .It Nm Ar cond status
Show condition status, default Show condition status, default
.Cm cond .Cm cond
command. Also supports the command.
.Fl j .It Nm Ar cond dump
option for detailed JSON output Dump all conditions and their status
.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 .It Nm Ar ident Op Cm NAME
Display indentities of all run/task/services, or only instances Display indentities of all run/task/services, or only instances
matching matching
@@ -181,93 +139,49 @@ Start service by name, with optional ID, e.g.,
.It Nm Ar stop Cm NAME[:ID] .It Nm Ar stop Cm NAME[:ID]
Stop/Pause a running service by name Stop/Pause a running service by name
.It Nm Ar reload Cm NAME[:ID] .It Nm Ar reload Cm NAME[:ID]
Reload service as if its configuration had changed. Internally, Reload service by name (SIGHUP or restart)
.Nm finit .It Nm Ar signal Cm NAME:[ID] S
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 (or has a
.Cm reload:script )
it is signaled instead of stop-started, and
.It
it allows restarting run/task in the same runlevel -- which is otherwise
restricted
.El
.It Nm Ar <kill | signal> Cm NAME:[ID] S
Send signal S to service, by name. Send signal S to service, by name.
.Cm S .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) 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] .It Nm Ar restart Cm NAME[:ID]
Restart (stop/start) service by name Restart (stop/start) service by name
.It Nm Ar status Cm NAME[:ID] .It Nm Ar status Cm NAME[:ID]
Show service status, by name. If only Show service status, by name. If only
.Cm NAME .Cm NAME
is given and multiple instances exits, a summary of all matching is given and multiple instances exits, a summary of all matching
instances are shown. Only an exact match displays detailed status instances are shown. Only an exact match displays the detailed status
for a given instance. for a particular 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 .It Nm Ar status
Show status of all services, default command. Also supports the Show status of all services, default command
.Fl j
option for detailed JSON output
.It Nm Ar cgroup .It Nm Ar cgroup
List cgroup config overview List cgroup config overview
.It Nm Ar ps .It Nm Ar ps
List processes based on cgroups List processes based on cgroups
.It Nm Ar top .It Nm Ar top
Show top-like listing based on cgroups Show top-like listing based on cgroups
.It Nm Ar plugins
List installed plugins
.It Nm Ar runlevel Op Ar 0-9 .It Nm Ar runlevel Op Ar 0-9
Show or set runlevel: 0 halt, 6 reboot. Show or set runlevel: 0 halt, 6 reboot
.Pp
If called at boot (runlevel S) to set the runlevel, Finit only schedules
the change, effectively overriding the configured runlevel from
.Pa /etc/finit.conf .
Useful to trigger a fail-safe mode, or similar
.It Nm Ar reboot .It Nm Ar reboot
Reboot system, default if Reboot system, default if
.Cm reboot .Cm reboot
is symlinked to is symlinked to
.Nm .Nm
.It Nm Ar halt .It Nm Ar halt
Halt system, default if Halt system, default if
.Cm halt .Cm halt
is symlinked to is symlinked to
.Nm .Nm
.It Nm Ar poweroff .It Nm Ar poweroff
Power-off system, default if Power-off system, default if
.Cm poweroff .Cm poweroff
is symlinked to is symlinked to
.Nm .Nm
.It Nm Ar suspend .It Nm Ar suspend
Suspend system, default if Suspend system, default if
.Cm suspend .Cm suspend
is symlinked to is symlinked to
.Nm .Nm
.It Nm Ar utmp show .It Nm Ar utmp show
Raw dump of UTMP/WTMP db Raw dump of UTMP/WTMP db
.El .El
-122
View File
@@ -1,122 +0,0 @@
site_name: ""
site_description: Fast Init for Linux Systems
site_url: http://finit-project.github.io
repo_url: https://github.com/finit-project/finit
repo_name: Finit Project
copyright: Copyright &copy; 2008-2025 Joachim Wiberg
docs_dir: doc/
edit_uri: edit/master/doc/
extra_css:
- extra.css
exclude_docs: |
TODO.md
ChangeLog.md
theme:
logo: img/logo.png
name: material
features:
- toc.follow
- toc.integrate
- navigation.path
- navigation.instant
- navigation.instant.progress
- navigation.tracking
- navigation.tabs
# - navigation.sections
# - navigation.expand
# - navigation.top
- navigation.footer
- search.highlight
- search.share
# - content.action.edit
- content.code.copy
- content.code.annotate
palette:
- media: "(prefers-color-scheme: light)"
scheme: default
primary: orange
accent: orange
toggle:
icon: material/weather-night
name: Switch to dark mode
- media: "(prefers-color-scheme: dark)"
scheme: slate
primary: black
accent: black
toggle:
icon: material/weather-sunny
name: Switch to light mode
nav:
- Getting Started:
- Introduction: index.md
- Features: features.md
- Quick Example: example.md
- Building: build.md
- Configuration:
- Overview: config/index.md
- Files & Layout: config/files.md
- Conditions: conditions.md
- Runlevels: config/runlevels.md
- One-shot Tasks: config/task-and-run.md
- Services:
- Syntax: config/services.md
- Options: config/service-opts.md
- Environment: config/service-env.md
- Synchronization: config/service-sync.md
- Wrapper Scripts: config/service-wrappers.md
- Run-parts Scripts: config/runparts.md
- TTY & Console: config/tty.md
- Environment Variables: config/env.md
- Logging: config/logging.md
- Cgroups: config/cgroups.md
- Capabilities: config/capabilities.md
- Templating: config/templating.md
- SysV Compatibility: config/sysv.md
- Rescue Mode: config/rescue.md
- Limitations: config/limitations.md
- Usage:
- Commands & Status: initctl.md
- Switch Root: switchroot.md
- Rebooting & Halting: commands.md
- Command Line Options: cmdline.md
- Managing Services: service.md
- Signals: signals.md
- Reference:
- Runlevels Overview: runlevels.md
- Runparts & rc.local: runparts.md
- Plugins: plugins.md
- Watchdog: watchdog.md
- keventd: keventd.md
- Service State Machine: state-machine.md
- Distributions: distro.md
- Requirements: requirements.md
markdown_extensions:
- admonition
- attr_list
- pymdownx.details
- pymdownx.superfences
- pymdownx.highlight:
anchor_linenums: true
- pymdownx.inlinehilite
- pymdownx.snippets
- pymdownx.tabbed:
alternate_style: true
- tables
- toc:
permalink: true
plugins:
- search
- callouts
- glightbox
extra:
homepage: https://finit-project.github.io/
social:
- icon: fontawesome/brands/github
link: https://github.com/finit-project/finit
name: Finit on GitHub
+8 -4
View File
@@ -1,9 +1,9 @@
pkglibdir = $(plugin_path) pkglibdir = $(plugin_path)
AM_LDFLAGS = -module -avoid-version -shared AM_LDFLAGS = -module -avoid-version -shared
AM_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99 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_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
AM_CPPFLAGS += -D__FINIT__ $(lite_CFLAGS) $(uev_CFLAGS) AM_CPPFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
if STATIC if STATIC
noinst_LTLIBRARIES = libplug.la noinst_LTLIBRARIES = libplug.la
@@ -17,6 +17,10 @@ if BUILD_DBUS_PLUGIN
libplug_la_SOURCES += dbus.c libplug_la_SOURCES += dbus.c
endif endif
if BUILD_HOTPLUG_PLUGIN
libplug_la_SOURCES += hotplug.c
endif
if BUILD_MODULES_LOAD_PLUGIN if BUILD_MODULES_LOAD_PLUGIN
libplug_la_SOURCES += modules-load.c libplug_la_SOURCES += modules-load.c
endif endif
@@ -60,8 +64,8 @@ if BUILD_DBUS_PLUGIN
pkglib_LTLIBRARIES += dbus.la pkglib_LTLIBRARIES += dbus.la
endif endif
if BUILD_HOOK_SCRIPTS_PLUGIN if BUILD_HOTPLUG_PLUGIN
pkglib_LTLIBRARIES += hook-scripts.la pkglib_LTLIBRARIES += hotplug.la
endif endif
if BUILD_MODULES_LOAD_PLUGIN if BUILD_MODULES_LOAD_PLUGIN
+8 -10
View File
@@ -1,6 +1,6 @@
/* Save and restore ALSA sound settings using alsactl /* Save and restore ALSA sound settings using alsactl
* *
* Copyright (c) 2012-2025 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -27,23 +27,21 @@
# include <lite/lite.h> # include <lite/lite.h>
#endif #endif
#include "conf.h"
#include "finit.h" #include "finit.h"
#include "helpers.h" #include "helpers.h"
#include "plugin.h" #include "plugin.h"
#include "log.h"
#define ALSACTL "alsactl" #define ALSACTL "alsactl"
static void save(void *arg) static void save(void *arg)
{ {
if (rescue) { if (rescue) {
dbg("Skipping %s plugin in rescue mode.", "alsa-utils"); _d("Skipping %s plugin in rescue mode.", __FILE__);
return; return;
} }
if (whichp(ALSACTL)) { if (whichp(ALSACTL)) {
dbg("Saving sound settings ..."); _d("Saving sound settings ...");
run_interactive(ALSACTL " -g store", "Saving sound settings"); run_interactive(ALSACTL " -g store", "Saving sound settings");
} }
} }
@@ -51,28 +49,28 @@ static void save(void *arg)
static void restore(void *arg) static void restore(void *arg)
{ {
if (rescue) { if (rescue) {
dbg("Skipping %s plugin in rescue mode.", "alsa-utils"); _d("Skipping %s plugin in rescue mode.", __FILE__);
return; return;
} }
if (whichp(ALSACTL)) { if (whichp(ALSACTL)) {
dbg("Restoring sound settings ..."); _d("Restoring sound settings ...");
run_interactive(ALSACTL " -g restore", "Restoring sound settings"); run_interactive(ALSACTL " -g restore", "Restoring sound settings");
} }
} }
static plugin_t plugin = { static plugin_t plugin = {
.name = "alsa-utils", .name = __FILE__,
.hook[HOOK_BASEFS_UP] = { .cb = restore }, .hook[HOOK_BASEFS_UP] = { .cb = restore },
.hook[HOOK_SHUTDOWN] = { .cb = save } .hook[HOOK_SHUTDOWN] = { .cb = save }
}; };
PLUGIN_INIT(__init) PLUGIN_INIT(plugin_init)
{ {
plugin_register(&plugin); plugin_register(&plugin);
} }
PLUGIN_EXIT(__exit) PLUGIN_EXIT(plugin_exit)
{ {
plugin_unregister(&plugin); plugin_unregister(&plugin);
} }
+86 -54
View File
@@ -1,6 +1,6 @@
/* Setup necessary system files for, e.g. UTMP (tracking logins) /* Setup necessary system files for, e.g. UTMP (tracking logins)
* *
* Copyright (c) 2012-2025 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -21,12 +21,8 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "config.h" /* Generated by configure script */
#include <ftw.h> #include <ftw.h>
#ifdef HAVE_MNTENT_H
#include <mntent.h> #include <mntent.h>
#endif
#include <string.h> #include <string.h>
#ifdef _LIBITE_LITE #ifdef _LIBITE_LITE
# include <libite/lite.h> # include <libite/lite.h>
@@ -40,16 +36,13 @@
#include "plugin.h" #include "plugin.h"
#include "util.h" #include "util.h"
#include "utmp-api.h" #include "utmp-api.h"
#include "log.h"
static int is_tmpfs(char *path) static int is_tmpfs(char *path)
{ {
struct mntent mount;
struct mntent *mnt;
char buf[256];
int tmpfs = 0; int tmpfs = 0;
FILE *fp; FILE *fp;
char *dir; char *dir;
struct mntent *mnt;
/* If path is a symlink, check what it resolves to */ /* If path is a symlink, check what it resolves to */
dir = realpath(path, NULL); dir = realpath(path, NULL);
@@ -62,7 +55,7 @@ static int is_tmpfs(char *path)
return 0; /* Dunno, maybe not */ return 0; /* Dunno, maybe not */
} }
while ((mnt = getmntent_r(fp, &mount, buf, sizeof(buf)))) { while ((mnt = getmntent(fp))) {
if (!strcmp(dir, mnt->mnt_dir)) if (!strcmp(dir, mnt->mnt_dir))
break; break;
} }
@@ -81,7 +74,7 @@ static int bootclean(const char *fpath, const struct stat *sb, int tflag, struct
if (ftw->level == 0) if (ftw->level == 0)
return 1; return 1;
dbg("Removing %s ...", fpath); _d("Removing %s ...", fpath);
(void)remove(fpath); (void)remove(fpath);
return 0; return 0;
@@ -111,43 +104,10 @@ static void clean(void *arg)
} }
} }
/* Kernel defines the following compulsory and recommended links static void ln(const char *target, const char *linkpath)
* https://github.com/torvalds/linux/blob/v5.18/Documentation/admin-guide/devices.rst#compulsory-links
*/
static void kernel_links(void)
{ {
struct { if (symlink(target, linkpath) && errno != EEXIST)
char *tgt, *lnk; _pe("Failed creating %s -> %s symlink", target, linkpath);
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);
}
} }
/* /*
@@ -159,31 +119,103 @@ static void setup(void *arg)
prev = umask(0); prev = umask(0);
/* Kernel symlinks, e.g. /proc/self/fd -> /dev/fd */ _d("Setting up FHS structure in /var ...");
kernel_links(); 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 ...");
if (!fisdir("/run/lock"))
makedir("/run/lock", 1777);
ln("/run/lock", "/var/lock");
ln("/dev/shm", "/run/shm");
/* Create all system tmpfiles.d(5) */ /* compat only, should really be set up by OS/dist */
run_interactive(_PATH_TMPFILES " --create", "Creating required directories and files"); ln("../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);
/*
* UTMP actually needs multiple db files
*/
if (has_utmp()) {
int gid;
/*
* If /etc/group or "utmp" group is missing, default to
* "root", or "wheel", group.
*/
_d("Setting up necessary UTMP files ...");
gid = getgroup("utmp");
if (gid < 0)
gid = 0;
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 */ /* Set BOOT_TIME UTMP entry */
utmp_set_boot(); utmp_set_boot();
#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 */
mksubsys("/var/run/quagga", 0755, "quagga", "quagga");
mksubsys("/var/log/quagga", 0755, "quagga", "quagga");
mksubsys("/var/run/frr", 0755, "frr", "frr");
mksubsys("/var/log/frr", 0755, "frr", "frr");
makedir("/var/run/sshd", 01755); /* OpenSSH */
if (!fexist("/etc/mtab"))
ln("../proc/self/mounts", "/etc/mtab");
/* Void Linux has a uuidd that runs as uuid:uuid and needs /run/uuid */
mksubsys("/var/run/uuidd", 0755, "uuidd", "uuidd");
/* Debian has /run/sudo, ensure correct perms and SELinux label */
mksubsys("/var/run/sudo", 0711, "root", "root");
mksubsys("/var/run/sudo/ts", 0700, "root", "root");
if (whichp("restorecon"))
run("restorecon /var/run/sudo /var/run/sudo/ts", "restorecon");
umask(prev); umask(prev);
} }
static plugin_t plugin = { static plugin_t plugin = {
.name = "bootmisc", .name = __FILE__,
.hook[HOOK_MOUNT_POST] = { .cb = clean }, .hook[HOOK_MOUNT_POST] = { .cb = clean },
.hook[HOOK_BASEFS_UP] = { .cb = setup }, .hook[HOOK_BASEFS_UP] = { .cb = setup },
.depends = { "pidfile" }, .depends = { "pidfile" },
}; };
PLUGIN_INIT(__init) PLUGIN_INIT(plugin_init)
{ {
plugin_register(&plugin); plugin_register(&plugin);
} }
PLUGIN_EXIT(__exit) PLUGIN_EXIT(plugin_exit)
{ {
plugin_unregister(&plugin); plugin_unregister(&plugin);
} }
+30 -107
View File
@@ -1,6 +1,6 @@
/* Setup and start system message bus, D-Bus /* Setup and start system message bus, D-Bus
* *
* Copyright (c) 2012-2025 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -33,147 +33,70 @@
#include "helpers.h" #include "helpers.h"
#include "plugin.h" #include "plugin.h"
#include "service.h" #include "service.h"
#include "util.h"
#include "conf.h" #include "conf.h"
#include "log.h"
#define DBUS_DAEMON "dbus-daemon" #define DAEMON "dbus-daemon"
#define DBUS_ARGS "--nofork --system --syslog-only" #define ARGS "--nofork --system --syslog-only"
#define DBUS_DESC "D-Bus message bus daemon" #define DESC "D-Bus message bus daemon"
#ifndef DBUS_DAEMONUSER #ifndef DAEMONUSER
#define DBUS_DAEMONUSER "messagebus" #define DAEMONUSER "messagebus"
#endif #endif
#ifndef DBUS_DAEMONGROUP #ifndef DAEMONPIDFILE
#define DBUS_DAEMONGROUP "messagebus" #define DAEMONPIDFILE "/var/run/dbus/pid"
#endif #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;
break;
}
fclose(fp);
if (fn)
return strdup(fn);
}
return NULL;
}
static void setup(void *arg) static void setup(void *arg)
{ {
char *group = DBUS_DAEMONGROUP;
char *user = DBUS_DAEMONUSER;
char line[256]; char line[256];
char *pidfn;
mode_t prev; mode_t prev;
char *cmd; char *cmd;
if (rescue) { if (rescue) {
dbg("Skipping %s plugin in rescue mode.", "dbus"); _d("Skipping %s plugin in rescue mode.", __FILE__);
return; return;
} }
cmd = which(DBUS_DAEMON); cmd = which(DAEMON);
if (!cmd) { if (!cmd) {
dbg("Skipping plugin, %s is not installed.", DBUS_DAEMON); _d("Skipping plugin, %s is not installed.", DAEMON);
return; return;
} }
if (getuser(user, NULL) == -1) { prev =umask(0);
if (getuser("dbus", NULL) == -1)
user = "root"; /* fallback */
else
user = "dbus"; /* e.g., Buildroot */
}
if (getgroup(group) == -1) { mksubsys("/var/run/dbus", 0755, DAEMONUSER, DAEMONUSER);
if (getgroup("dbus") == -1) if (whichp("dbus-uuidgen"))
group = "root"; /* fallback */ run_interactive("dbus-uuidgen --ensure", "Creating machine UUID for D-Bus");
else
group = "dbus"; /* e.g., Buildroot */
}
/* Clean up from any previous pre-bootstrap run */ /* Clean up from any previous pre-bootstrap run */
pidfn = dbus_pidfn(); remove(DAEMONPIDFILE);
if (pidfn)
remove(pidfn);
dbg("Creating D-Bus Required Directories ..."); /* Register service with Finit */
prev = umask(0); snprintf(line, sizeof(line), "[S12345789] cgroup.system pid:!%s @%s:%s %s %s -- %s",
mksubsys("/var/run/dbus", 0755, user, group); DAEMONPIDFILE, DAEMONUSER, DAEMONUSER, cmd, ARGS, DESC);
mksubsys("/var/run/lock/subsys", 0755, user, group); if (service_register(SVC_TYPE_SERVICE, line, global_rlimit, NULL))
mksubsys("/var/lib/dbus", 0755, user, group); _pe("Failed registering %s", DAEMON);
mksubsys("/tmp/dbus", 0755, user, group);
umask(prev);
/* Generate machine id for dbus */
if (whichp("dbus-uuidgen"))
run_interactive("dbus-uuidgen --ensure", "Verifying D-Bus machine UUID");
/*
* Register service with Finit
* Note: dbus drops privs after starting up.
*/
if (pidfn) {
snprintf(line, sizeof(line), "[S123456789] cgroup.system notify:none name:dbus pid:!%s %s %s -- %s",
pidfn, cmd, DBUS_ARGS, DBUS_DESC);
free(pidfn);
} else
snprintf(line, sizeof(line), "[S123456789] cgroup.system notify:none name:dbus %s %s -- %s",
cmd, DBUS_ARGS, DBUS_DESC);
conf_save_service(SVC_TYPE_SERVICE, line, "dbus.conf");
free(cmd); free(cmd);
umask(prev);
} }
static plugin_t plugin = { static plugin_t plugin = {
.name = "dbus", .name = __FILE__,
.hook[HOOK_SVC_PLUGIN] = { .cb = setup }, .hook[HOOK_BASEFS_UP] = {
.cb = setup
},
.depends = { "bootmisc", },
}; };
PLUGIN_INIT(__init) PLUGIN_INIT(plugin_init)
{ {
plugin_register(&plugin); plugin_register(&plugin);
} }
PLUGIN_EXIT(__exit) PLUGIN_EXIT(plugin_exit)
{ {
plugin_unregister(&plugin); plugin_unregister(&plugin);
} }
-117
View File
@@ -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 = "hook-scripts",
.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(__init)
{
plugin_register(&plugin);
}
PLUGIN_EXIT(__exit)
{
plugin_unregister(&plugin);
}
/**
* 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