mirror of
https://github.com/troglobit/finit.git
synced 2026-10-12 10:12:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
530d6703f1 | ||
|
|
cec76f18a3 | ||
|
|
ee6d4a1dae | ||
|
|
0548485be1 | ||
|
|
1b10c3746e | ||
|
|
24911ebbc2 | ||
|
|
88a9e6575b | ||
|
|
9bfbdc6bac | ||
|
|
c016965371 | ||
|
|
263ea929fd | ||
|
|
cc5e0c5175 | ||
|
|
417abf9000 | ||
|
|
61b0e0f3e6 | ||
|
|
bad7c5c99a | ||
|
|
4c16190831 | ||
|
|
a274677f05 | ||
|
|
f51aee1ec5 | ||
|
|
cdf2337346 | ||
|
|
847f4db974 | ||
|
|
969f9a112c | ||
|
|
2b812101be | ||
|
|
7644874b42 | ||
|
|
c512d57df4 | ||
|
|
59945b87f7 | ||
|
|
d23a9b8a16 | ||
|
|
e5040385f5 | ||
|
|
e9efec8694 | ||
|
|
7110ae4427 | ||
|
|
a7ee24662f | ||
|
|
48e85efb88 | ||
|
|
e8391864d7 | ||
|
|
2a2f7cda63 | ||
|
|
ad02b343f2 | ||
|
|
7263641953 | ||
|
|
42840f0f36 | ||
|
|
1a2cc950f0 | ||
|
|
7eb32bc543 | ||
|
|
558c0f8c3b | ||
|
|
230c65a080 | ||
|
|
292e87c0d1 | ||
|
|
6e60b8183a | ||
|
|
289c1e0de6 | ||
|
|
1bb7d508a4 | ||
|
|
2b861ea0af | ||
|
|
a814e85356 | ||
|
|
39d21ca0bd | ||
|
|
480f9c6a9d | ||
|
|
8f1cd35f1c | ||
|
|
b743d15e35 | ||
|
|
9d4cc8e933 | ||
|
|
3efa9d6f41 | ||
|
|
62b55d5b43 | ||
|
|
8b61aaea1a | ||
|
|
2af83ea632 | ||
|
|
b53c7e6879 | ||
|
|
8114508bbb | ||
|
|
8138b402a0 | ||
|
|
864a13460c | ||
|
|
b3a206a28c | ||
|
|
81cb90804e | ||
|
|
5a3972714a | ||
|
|
c1c68054ea | ||
|
|
f3461ce2ba | ||
|
|
e4d9193f06 | ||
|
|
9d5e646e46 | ||
|
|
0111dc2178 | ||
|
|
153a1de043 | ||
|
|
4e914dd8a9 | ||
|
|
67d61a8282 | ||
|
|
dda0d5c763 | ||
|
|
48f677c3a0 | ||
|
|
db5567b5d1 | ||
|
|
8e91bb4297 | ||
|
|
71628471bc | ||
|
|
425256ff3d | ||
|
|
155d21cee7 | ||
|
|
120c8e6002 | ||
|
|
8cf98a7bfd | ||
|
|
8ea299f39d | ||
|
|
f3b013bc0a | ||
|
|
8e2492fc87 | ||
|
|
3231ade38a | ||
|
|
e62b463852 | ||
|
|
c28acf21a1 | ||
|
|
5cc41b3ba4 | ||
|
|
f3c73f1192 | ||
|
|
bb43b5670c | ||
|
|
853e226812 | ||
|
|
a1969efac1 | ||
|
|
44e7da6d56 | ||
|
|
127049d925 | ||
|
|
2e0b1d6f8b | ||
|
|
9875e76419 | ||
|
|
1e508f9168 | ||
|
|
63aabaa6df | ||
|
|
d710a23513 | ||
|
|
c71ccce742 | ||
|
|
abab0e0fd4 | ||
|
|
3499a5eb76 | ||
|
|
b55dada80b | ||
|
|
6310d9e760 | ||
|
|
ebc0ef62e6 | ||
|
|
dd1390a6c2 | ||
|
|
0a269f3298 | ||
|
|
ae9a24f44f | ||
|
|
1843c24cda | ||
|
|
a35ed8f72e | ||
|
|
d2781ef655 | ||
|
|
287a385e63 | ||
|
|
6b77a16f8b | ||
|
|
96c5b4b031 | ||
|
|
ffb1db7d2d | ||
|
|
22fbb408eb | ||
|
|
4299ce8839 | ||
|
|
cfae4a0e10 | ||
|
|
516ee41494 | ||
|
|
c3c41f113e | ||
|
|
1099d663ab | ||
|
|
2c6547635a | ||
|
|
9360c8e9b9 | ||
|
|
5aa7daf708 | ||
|
|
057ded451f | ||
|
|
3062f49370 | ||
|
|
301992b8d8 | ||
|
|
cdf8ec932a | ||
|
|
c6802b5ab3 | ||
|
|
652479d8fa | ||
|
|
153f719e33 | ||
|
|
6b03a1ec8f | ||
|
|
f0d7257374 | ||
|
|
7f8a64dd39 | ||
|
|
6615a248ee | ||
|
|
be28436c2d | ||
|
|
c584795202 | ||
|
|
ddda905487 | ||
|
|
00794d41bc | ||
|
|
b44a5ff2f8 | ||
|
|
b9ad9bcb21 | ||
|
|
ecac1e58e3 | ||
|
|
ddaef0600f | ||
|
|
13d58ace9f | ||
|
|
f48f8aacec | ||
|
|
8a541acd36 | ||
|
|
8a3d55b416 | ||
|
|
53cb2b7bdb | ||
|
|
2a5190ecff | ||
|
|
0721b0fec2 | ||
|
|
f1393ff8a1 | ||
|
|
47a18140c1 | ||
|
|
c20d64587c | ||
|
|
3b866c95e0 | ||
|
|
fc74f87986 | ||
|
|
ee5038e7af | ||
|
|
ad750a13c3 | ||
|
|
b56ffc155e | ||
|
|
4596e27eb0 | ||
|
|
a3eac3a85e | ||
|
|
7d09e34b80 | ||
|
|
3febc7d513 | ||
|
|
309ad1bea7 | ||
|
|
30f2ca3b2e | ||
|
|
4a53f610cd | ||
|
|
e74dff96ba | ||
|
|
9ed4407b20 | ||
|
|
eb913e8bf2 | ||
|
|
17d04779fb | ||
|
|
ab661423ba | ||
|
|
8e77ea68b2 | ||
|
|
b0e672bc9a | ||
|
|
ad76e15949 | ||
|
|
b8735cc893 | ||
|
|
c058b3f9ce | ||
|
|
8f6c61606a | ||
|
|
96f944b816 | ||
|
|
a81530754b | ||
|
|
1518eb9466 | ||
|
|
50b9e46e19 | ||
|
|
c01faef99b | ||
|
|
4867b7268b | ||
|
|
662293e194 | ||
|
|
4ce810cc1f | ||
|
|
184c079c08 | ||
|
|
17c6791c70 | ||
|
|
42f24f5af5 | ||
|
|
cef5049bf0 | ||
|
|
ec251f1ce1 | ||
|
|
98ec30d308 | ||
|
|
e1fe870aaf | ||
|
|
f04fce544d | ||
|
|
7aa9ed5982 | ||
|
|
a1a92a04bd | ||
|
|
804f655d87 | ||
|
|
2c78e7429a | ||
|
|
d77f0127b4 | ||
|
|
4253d0de25 | ||
|
|
d47181a4a7 | ||
|
|
8642007d0e | ||
|
|
96c74ed48b | ||
|
|
03a14bcaa5 | ||
|
|
4bb2c33859 | ||
|
|
ab81272083 | ||
|
|
1fbf03bc1e | ||
|
|
92a2861b1c | ||
|
|
922714780a | ||
|
|
b206c3d655 | ||
|
|
109d8826bd | ||
|
|
60478106eb | ||
|
|
0de9cfb020 | ||
|
|
0b182c063e | ||
|
|
f0914f6d32 | ||
|
|
7090321ff3 | ||
|
|
266f1132a4 | ||
|
|
5f7e8457af | ||
|
|
a215747355 | ||
|
|
dacda5ab5d | ||
|
|
39044adcf8 | ||
|
|
9396cd1d26 | ||
|
|
c9fd4418e7 | ||
|
|
7206f745a2 | ||
|
|
25bcde12d4 | ||
|
|
7459ede806 | ||
|
|
6bf35513c3 | ||
|
|
0b8d39329a | ||
|
|
84098dd8b7 | ||
|
|
c4463ec64f | ||
|
|
6f1808248e | ||
|
|
29029bb78f | ||
|
|
bbe588ac16 | ||
|
|
34bf9a7776 | ||
|
|
bb111f98fc | ||
|
|
c7faf4f9e2 | ||
|
|
18774539c0 | ||
|
|
abaad560f0 | ||
|
|
0ef325d86c | ||
|
|
2c94f4e45f | ||
|
|
da184e7922 | ||
|
|
1e93fc1671 | ||
|
|
8e7d1b7bb5 | ||
|
|
373738f3d1 | ||
|
|
e6d3eb2526 | ||
|
|
d7fd5bc902 | ||
|
|
3f98220d5d | ||
|
|
0ca509a42e | ||
|
|
d17144d16f | ||
|
|
a608c5a5c9 | ||
|
|
9b44b99480 | ||
|
|
ad225156f1 | ||
|
|
eb92a915d3 | ||
|
|
69a4f2c115 | ||
|
|
9ce95fe8c0 | ||
|
|
06889cc014 | ||
|
|
329f11b4da | ||
|
|
ce40e2b9d2 | ||
|
|
d0176612c9 | ||
|
|
21753e26dd | ||
|
|
0dc2513b32 | ||
|
|
d16bfa789b | ||
|
|
0b27778c96 | ||
|
|
3e25297e3c | ||
|
|
6560968c8b | ||
|
|
c9a3c5c885 | ||
|
|
a2d45e8f5e | ||
|
|
f6c69eb108 | ||
|
|
f0032ab6b7 | ||
|
|
53c5d0e55a | ||
|
|
7c8ab7915f | ||
|
|
12f7855a78 | ||
|
|
bcc3360b53 | ||
|
|
d3408d14a8 | ||
|
|
804060444a | ||
|
|
de544a5b36 | ||
|
|
0d48d1df49 | ||
|
|
b46592e818 | ||
|
|
22bc218c84 |
+30
-26
@@ -20,7 +20,6 @@ Please take care to ensure you follow the project coding style and the
|
||||
commit message format. If you follow these recommendations you help
|
||||
the maintainer(s) and make it easier for them to include your code.
|
||||
|
||||
|
||||
Coding Style
|
||||
------------
|
||||
|
||||
@@ -31,8 +30,7 @@ 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
|
||||
100 chars is OK.
|
||||
|
||||
The coding style itself is strictly Linux [KNF][].
|
||||
|
||||
The coding style itself is strictly [Linux coding style][KNF].
|
||||
|
||||
Commit Messages
|
||||
---------------
|
||||
@@ -41,31 +39,38 @@ Commit messages exist to track *why* a change was made. Try to be as
|
||||
clear and concise as possible in your commit messages, and always, be
|
||||
proud of your work and set up a proper GIT identity for your commits:
|
||||
|
||||
git config --global user.name "Jane Doe"
|
||||
git config --global user.email jane.doe@example.com
|
||||
```bash
|
||||
$ git config --global user.name "Jane Doe"
|
||||
$ git config --global user.email jane.doe@example.com
|
||||
```
|
||||
|
||||
Example commit message from the [Pro Git][gitbook] online book, notice
|
||||
how `git commit -s` is used to automatically add a `Signed-off-by`:
|
||||
|
||||
Brief, but clear and concise summary of changes
|
||||
|
||||
More detailed explanatory text, if necessary. Wrap it to about 72
|
||||
characters or so. In some contexts, the first line is treated as
|
||||
the subject of an email and the rest of the text as the body. The
|
||||
blank line separating the ummary from the body is critical (unless
|
||||
you omit the body entirely); tools like rebase can get confused if
|
||||
you run the two together.
|
||||
|
||||
Further paragraphs come after blank lines.
|
||||
|
||||
- Bullet points are okay, too
|
||||
|
||||
- Typically a hyphen or asterisk is used for the bullet, preceded
|
||||
by a single space, with blank lines in between, but conventions
|
||||
vary here
|
||||
|
||||
Signed-off-by: Jane Doe <jane.doe@example.com>
|
||||
```
|
||||
Brief, but clear and concise summary of changes
|
||||
|
||||
More detailed explanatory text, if necessary. Remember, a future
|
||||
reader has the diff and can see what it does, the commit message in
|
||||
itself should usually talk about the *why* of a change and/or any
|
||||
technical limitations and future work.
|
||||
|
||||
Wrap the text to about 72 characters or so. In some contexts, the
|
||||
first line is treated as the subject of an email and the rest of the
|
||||
text as the body. The blank line separating the summary from the body
|
||||
is critical (unless you omit the body entirely); tools like rebase can
|
||||
get confused if you run the two together.
|
||||
|
||||
Further paragraphs come after blank lines.
|
||||
|
||||
- Bullet points are okay, too
|
||||
|
||||
- Typically a hyphen or asterisk is used for the bullet, preceded
|
||||
by a single space, with blank lines in between, but conventions
|
||||
vary here
|
||||
|
||||
Signed-off-by: Jane Doe <jane.doe@example.com>
|
||||
```
|
||||
|
||||
Code of Conduct
|
||||
---------------
|
||||
@@ -73,7 +78,6 @@ Code of Conduct
|
||||
It is expected of everyone engaging in the project to, in the words of
|
||||
Bill & Ted; [be excellent to each other][conduct].
|
||||
|
||||
|
||||
[KNF]: https://en.wikipedia.org/wiki/Kernel_Normal_Form
|
||||
[gitbook]: https://git-scm.com/book/ch5-2.html
|
||||
[KNF]: https://www.kernel.org/doc/html/v5.8/process/coding-style.html
|
||||
[gitbook]: https://git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project#_commit_guidelines
|
||||
[conduct]: CODE-OF-CONDUCT.md
|
||||
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Extract the topmost release entry from doc/ChangeLog.md and unwrap
|
||||
# its paragraphs, so the GitHub releases page can wrap them to the
|
||||
# browser width instead of showing the hard 72-column breaks.
|
||||
#
|
||||
# Usage: .github/scripts/extract-changelog.sh < doc/ChangeLog.md > release.md
|
||||
#
|
||||
set -e
|
||||
|
||||
# The entry sits between the first two underlines, minus the blank
|
||||
# line separating it from the next heading.
|
||||
awk '/^-----*$/{if (x == 1) exit; x=1;next}x' | head -n -1 |
|
||||
|
||||
# Blank lines, headings, blockquotes, tables, and list items (at any
|
||||
# indent) start a new block, everything else continues the current one.
|
||||
awk '
|
||||
function flush() { if (buf) print buf; buf = "" }
|
||||
{
|
||||
if (/^$/) { flush(); print; blank = 1; next }
|
||||
if (/^ *([-*] |[0-9]+\. |[>#|])/ || blank || !buf || brk)
|
||||
{ flush(); buf = $0 }
|
||||
else
|
||||
{ sub(/^ +/, ""); buf = buf " " $0 }
|
||||
blank = 0
|
||||
brk = / $/
|
||||
}
|
||||
END { flush() }
|
||||
'
|
||||
+115
-12
@@ -18,6 +18,71 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
fuzz:
|
||||
name: fuzz
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name != 'push' || github.ref == 'refs/heads/master'
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y install pkg-config libconfuse-dev clang libblkid-dev
|
||||
# clang picks the newest gcc tree it finds and needs the
|
||||
# matching libstdc++ headers to link the fuzzer runtime
|
||||
sudo apt-get -y install libstdc++-14-dev || true
|
||||
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@v7
|
||||
- name: Configure
|
||||
run: |
|
||||
./autogen.sh
|
||||
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var
|
||||
- name: Build fuzz target
|
||||
run: |
|
||||
clang -fsanitize=fuzzer,address -DLINK_FUZZ_LIBFUZZER -D_GNU_SOURCE \
|
||||
-I libink -I . -o fuzz-msg-parse \
|
||||
test/src/fuzz-msg-parse.c libink/*.c
|
||||
# Restores the newest corpus and saves a fresh one, since a cache
|
||||
# entry is immutable once written. Caches made on a branch are
|
||||
# private to it, so the corpus that accumulates on master is what
|
||||
# pull requests start from, rather than nothing.
|
||||
- name: Restore corpus
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: .fuzz-corpus
|
||||
key: fuzz-corpus-${{ github.run_id }}
|
||||
restore-keys: fuzz-corpus-
|
||||
- name: Fuzz
|
||||
run: |
|
||||
mkdir -p .fuzz-corpus
|
||||
./fuzz-msg-parse .fuzz-corpus -max_total_time=120 -max_len=4096 \
|
||||
-print_final_stats=1
|
||||
# Without this the corpus only ever grows, and most of what it
|
||||
# accumulates reaches code some earlier input already reached.
|
||||
- name: Minimise corpus
|
||||
if: always()
|
||||
run: |
|
||||
mkdir -p .fuzz-corpus-min
|
||||
./fuzz-msg-parse -merge=1 .fuzz-corpus-min .fuzz-corpus
|
||||
rm -rf .fuzz-corpus
|
||||
mv .fuzz-corpus-min .fuzz-corpus
|
||||
echo "corpus: $(ls .fuzz-corpus | wc -l) inputs"
|
||||
- name: Upload crashers
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fuzz-crashers
|
||||
path: |
|
||||
crash-*
|
||||
leak-*
|
||||
timeout-*
|
||||
if-no-files-found: ignore
|
||||
|
||||
build:
|
||||
# Verify we can build on latest Ubuntu with both gcc and clang
|
||||
name: ${{ matrix.compiler }}
|
||||
@@ -34,29 +99,27 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
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 tree jq libcap-dev libconfuse-dev libblkid-dev libpam0g-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 --prefix=/usr && make && sudo make install-strip)
|
||||
(cd libite-2.6.2 && ./configure --prefix=/usr && make && sudo make install-strip)
|
||||
(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
|
||||
- uses: actions/checkout@v7
|
||||
- name: Static Finit
|
||||
run: |
|
||||
./autogen.sh
|
||||
./configure --prefix= --enable-static
|
||||
make -j3 V=1
|
||||
make -j9 V=1
|
||||
- name: Regular Finit
|
||||
run: |
|
||||
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
|
||||
--enable-x11-common-plugin --enable-testserv-plugin --with-watchdog \
|
||||
--with-keventd --with-libsystemd \
|
||||
--enable-x11-common-plugin --enable-testserv-plugin \
|
||||
CFLAGS="-fsanitize=address -ggdb"
|
||||
make -j3 clean
|
||||
make -j3 V=1
|
||||
make -j9 clean
|
||||
make -j9 V=1
|
||||
- name: Install to /tmp
|
||||
run: |
|
||||
DESTDIR=/tmp make install-strip
|
||||
@@ -78,9 +141,49 @@ jobs:
|
||||
sudo sysctl kernel.apparmor_restrict_unprivileged_userns=0
|
||||
- name: Run Unit Tests
|
||||
run: |
|
||||
make check || (cat test/test-suite.log; false)
|
||||
make -j1 check || (cat test/test-suite.log; false)
|
||||
- name: Upload Test Results
|
||||
uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: finit-test-${{ matrix.compiler }}
|
||||
path: test/*.log
|
||||
|
||||
no-dbus:
|
||||
# The D-Bus support is default-enabled, so the HAVE_DBUS paths in
|
||||
# initctl and finit only bit-rot silently without this leg.
|
||||
name: no-dbus
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name != 'push' || github.ref == 'refs/heads/master'
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y install pkg-config tree jq libcap-dev libconfuse-dev libblkid-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@v7
|
||||
- name: Build without D-Bus
|
||||
run: |
|
||||
./autogen.sh
|
||||
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
|
||||
--disable-dbus --enable-testserv-plugin
|
||||
make -j9 V=1
|
||||
- name: Verify no bus artifacts
|
||||
run: |
|
||||
DESTDIR=/tmp make install-strip
|
||||
! strings /tmp/sbin/initctl | grep -q finit/bus
|
||||
! strings /tmp/sbin/finit | grep -q org.finit
|
||||
- name: Enable unprivileged userns (unshare)
|
||||
run: |
|
||||
sudo sysctl kernel.apparmor_restrict_unprivileged_userns=0
|
||||
- name: Smoke test
|
||||
run: |
|
||||
make -C test setup-chroot
|
||||
make -j1 -C test check TESTS='start-stop-serv.sh' \
|
||||
|| (cat test/test-suite.log; false)
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
coverity:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
- name: Fetch latest Coverity Scan MD5
|
||||
id: var
|
||||
env:
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
--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
|
||||
- uses: actions/cache@v6
|
||||
id: cache
|
||||
with:
|
||||
path: coverity-latest.tar.gz
|
||||
@@ -55,19 +55,18 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y install pkg-config libcap-dev
|
||||
sudo apt-get -y install pkg-config libcap-dev libconfuse-dev libblkid-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 --prefix=/usr && make && sudo make install-strip)
|
||||
(cd libite-2.6.2 && ./configure --prefix=/usr && make && sudo make install-strip)
|
||||
(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
|
||||
- name: Configure
|
||||
run: |
|
||||
./autogen.sh
|
||||
./configure --prefix= --enable-x11-common-plugin --with-watchdog \
|
||||
--with-keventd --with-libsystemd
|
||||
./configure --prefix= --enable-x11-common-plugin
|
||||
- name: Build
|
||||
run: |
|
||||
export PATH=`pwd`/coverity/bin:$PATH
|
||||
@@ -86,7 +85,7 @@ jobs:
|
||||
--form description="${PROJECT_NAME} $(git rev-parse HEAD)" \
|
||||
https://scan.coverity.com/builds?project=${COVERITY_PROJ}
|
||||
- name: Upload build.log
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: coverity-build.log
|
||||
path: cov-int/build-log.txt
|
||||
|
||||
+113
-18
@@ -4,10 +4,12 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- 4.x
|
||||
paths:
|
||||
- 'doc/**'
|
||||
- 'README.md'
|
||||
- 'mkdocs.yml'
|
||||
- 'configure.ac'
|
||||
- '.github/workflows/docs.yml'
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled]
|
||||
@@ -15,28 +17,32 @@ on:
|
||||
- 'doc/**'
|
||||
- 'README.md'
|
||||
- 'mkdocs.yml'
|
||||
- 'configure.ac'
|
||||
- '.github/workflows/docs.yml'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
version: ${{ steps.version.outputs.version }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0 # Needed for git-revision-date-localized plugin
|
||||
|
||||
- name: Determine docs version
|
||||
id: version
|
||||
run: |
|
||||
version=$(sed -n 's/^AC_INIT(\[Finit\], *\[\([0-9]*\)\..*/\1.x/p' configure.ac)
|
||||
test -n "$version"
|
||||
echo "version=$version" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v7
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
@@ -46,23 +52,112 @@ jobs:
|
||||
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
|
||||
run: mkdocs build --clean
|
||||
|
||||
- name: Upload Pages artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
- name: Upload site artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: site
|
||||
path: site/
|
||||
|
||||
deploy:
|
||||
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
|
||||
if: github.event_name == 'push'
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
env:
|
||||
VERSION: ${{ needs.build.outputs.version }}
|
||||
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
- name: Download site artifact
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: site
|
||||
path: site/
|
||||
|
||||
- name: Checkout pages repo
|
||||
uses: actions/checkout@v7
|
||||
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 site/ "pages/$VERSION/"
|
||||
|
||||
- name: Update version index and redirects
|
||||
run: |
|
||||
cd pages/
|
||||
|
||||
# The root holds only version directories and the files
|
||||
# generated below, drop anything else (pre-versioned site)
|
||||
find . -maxdepth 1 ! -name . ! -name .git ! -name CNAME \
|
||||
! -name '[0-9]*.x' -exec rm -rf {} +
|
||||
|
||||
latest=$(ls -d [0-9]*.x | sort -rV | head -1)
|
||||
|
||||
sep=
|
||||
printf '[' > versions.json
|
||||
for v in $(ls -d [0-9]*.x | sort -rV); do
|
||||
printf '%s{"version": "%s", "title": "%s", "aliases": []}' \
|
||||
"$sep" "$v" "$v" >> versions.json
|
||||
sep=', '
|
||||
done
|
||||
printf ']\n' >> versions.json
|
||||
|
||||
cat > index.html <<EOF
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=$latest/">
|
||||
<link rel="canonical" href="https://finit-project.github.io/$latest/">
|
||||
</head>
|
||||
</html>
|
||||
EOF
|
||||
|
||||
cat > 404.html <<EOF
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Finit — page not found</title>
|
||||
<script>
|
||||
var path = window.location.pathname;
|
||||
if (!/^\/[0-9]+\.x(\/|$)/.test(path))
|
||||
window.location.replace("/$latest" + path);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p>Page not found. Try the <a href="/$latest/">latest User Guide</a>.</p>
|
||||
</body>
|
||||
</html>
|
||||
EOF
|
||||
|
||||
- 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
|
||||
|
||||
@@ -13,20 +13,19 @@ jobs:
|
||||
name: Build and upload release tarball
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
MAKEFLAGS: -j3
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
- name: Installing dependencies ...
|
||||
run: |
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y install pkg-config jq libcap-dev
|
||||
sudo apt-get -y install pkg-config jq libcap-dev libconfuse-dev libblkid-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 --prefix=/usr && make && sudo make install-strip)
|
||||
(cd libite-2.6.2 && ./configure --prefix=/usr && make && sudo make install-strip)
|
||||
(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
|
||||
- name: Setting release variables ...
|
||||
id: build
|
||||
run: |
|
||||
@@ -47,21 +46,30 @@ jobs:
|
||||
./autogen.sh
|
||||
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc \
|
||||
--localstatedir=/var --enable-x11-common-plugin \
|
||||
--enable-testserv-plugin --with-watchdog \
|
||||
--with-keventd --with-libsystemd
|
||||
--enable-testserv-plugin
|
||||
- name: Enable unprivileged userns (unshare)
|
||||
run: |
|
||||
sudo sysctl kernel.apparmor_restrict_unprivileged_userns=0
|
||||
- name: Build release ...
|
||||
run: |
|
||||
make release || (cat test/test-suite.log; false)
|
||||
# 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 ../
|
||||
mkdir -p artifacts/
|
||||
mv ../*.tar.* artifacts/
|
||||
mv ../*.tar.gz artifacts/
|
||||
- name: Upload Test Results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: finit-release-test-logs
|
||||
path: finit-*/_build/sub/test/*.log
|
||||
- name: Extract ChangeLog entry ...
|
||||
run: |
|
||||
awk '/-----*/{if (x == 1) exit; x=1;next}x' doc/ChangeLog.md \
|
||||
|head -n -1 > release.md
|
||||
.github/scripts/extract-changelog.sh < doc/ChangeLog.md > release.md
|
||||
cat release.md
|
||||
- uses: ncipollo/release-action@v1
|
||||
with:
|
||||
|
||||
@@ -14,14 +14,14 @@ jobs:
|
||||
schedule:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
run: ${{ steps.check.outputs.run }}
|
||||
run: ${{ steps.schedule.outputs.run }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
- name: Check for any commits since last week
|
||||
id: schedule
|
||||
run: |
|
||||
commits="$(git log --format=%H --since='1 week ago')"
|
||||
if [ -n "$commits" ]; then
|
||||
if [ -z "$commits" ]; then
|
||||
echo "run=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "run=false" >> $GITHUB_OUTPUT
|
||||
@@ -34,14 +34,15 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y install pkg-config jq libcap-dev
|
||||
sudo apt-get -y install pkg-config jq libcap-dev libconfuse-dev libblkid-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 --prefix=/usr && make && sudo make install-strip)
|
||||
(cd libite-2.6.2 && ./configure --prefix=/usr && make && sudo make install-strip)
|
||||
- uses: actions/checkout@v4
|
||||
(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@v7
|
||||
- name: Base run
|
||||
run: |
|
||||
./autogen.sh
|
||||
@@ -58,3 +59,9 @@ jobs:
|
||||
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@v7
|
||||
with:
|
||||
name: finit-weekly-test-logs
|
||||
path: finit-*/_build/sub/test/*.log
|
||||
|
||||
@@ -52,3 +52,8 @@ GTAGS
|
||||
|
||||
# VS Code user settings
|
||||
.vscode
|
||||
|
||||
# Fuzzing: the target is built by hand with clang, see doc/build.md,
|
||||
# and the corpus it grows is a local artefact, not something to ship
|
||||
/fuzz-msg-parse
|
||||
/.fuzz-corpus/
|
||||
|
||||
+29
-16
@@ -1,5 +1,21 @@
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
SUBDIRS = man plugins src system tmpfiles.d
|
||||
|
||||
# libink must precede src in SUBDIRS because finit links against
|
||||
# libink at build time. Automake recurses subdirs strictly in
|
||||
# declaration order, so the typical "explicit dependency" pattern
|
||||
# (foo: bar) doesn't help here — ordering is the only thing that
|
||||
# does. libsystemd is consumed by test/serv only, so its position
|
||||
# after src is fine.
|
||||
SUBDIRS = man plugins
|
||||
if DBUS
|
||||
SUBDIRS += libink dbus-1
|
||||
endif
|
||||
SUBDIRS += src system tmpfiles.d
|
||||
|
||||
if KEVENTD
|
||||
SUBDIRS += keventd
|
||||
endif
|
||||
|
||||
dist_doc_DATA = README.md LICENSE contrib/finit.conf
|
||||
|
||||
if CONTRIB
|
||||
@@ -24,23 +40,20 @@ endif
|
||||
install-dev:
|
||||
@make -C src install-pkgincludeHEADERS
|
||||
|
||||
# The fuzz target is built by hand with clang (doc/build.md), so it is
|
||||
# not in any _PROGRAMS and nothing else would clear it or the corpus
|
||||
# it grows.
|
||||
distclean-local:
|
||||
-rm -f $(top_builddir)/fuzz-msg-parse
|
||||
-rm -rf $(top_builddir)/.fuzz-corpus
|
||||
|
||||
# Target to run when building a release
|
||||
release: distcheck
|
||||
@for file in $(DIST_ARCHIVES); do \
|
||||
md5sum $$file > ../$$file.md5; \
|
||||
sha256sum $$file > ../$$file.sha256; \
|
||||
done
|
||||
@mv $(DIST_ARCHIVES) ../
|
||||
@echo
|
||||
@echo "Resulting release files:"
|
||||
@echo "================================================================="
|
||||
@for file in $(DIST_ARCHIVES); do \
|
||||
printf "$$file \tDistribution tarball\n"; \
|
||||
printf "$$file.md5\t"; cat ../$$file.md5 | cut -f1 -d' '; \
|
||||
printf "$$file.sha256\t"; cat ../$$file.sha256 | cut -f1 -d' '; \
|
||||
done
|
||||
@echo "Resulting release tarball(s): $(DIST_ARCHIVES)"
|
||||
|
||||
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
|
||||
DISTCHECK_CONFIGURE_FLAGS = --prefix=/usr --sysconfdir=/etc --localstatedir=/var \
|
||||
--enable-testserv-plugin --enable-x11-common-plugin \
|
||||
--with-fstab=/etc/fstab --with-libsystemd \
|
||||
--with-bash-completion-dir=no
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
[![License Badge][]][License] [![Release Badge][]][Release] [![GitHub Status][]][GitHub] [![Coverity Status][]][Coverity Scan]
|
||||
<img align="right" src="doc/img/finit3.png" alt="Finit: Fast Init">
|
||||
|
||||
Finit is an alternative to [SysV init](https://en.wikipedia.org/wiki/Init)
|
||||
and [systemd](https://www.freedesktop.org/wiki/Software/systemd/), focused
|
||||
on small and embedded Linux systems, although fully usable on server and
|
||||
[desktop systems][finix].
|
||||
Finit is a fast, simple alternative to [SysV init](https://en.wikipedia.org/wiki/Init)
|
||||
and [systemd](https://systemd.io), designed for small and embedded Linux systems.
|
||||
It can also run on desktop and server systems, like [finix][].
|
||||
|
||||
> Reverse engineered from the [EeePC fastinit][]
|
||||
> "gaps filled with frog DNA …"
|
||||
> — [Claudio Matsuoka][]
|
||||
|
||||
For detailed information, explore our extensive documentation
|
||||
:books: **<http://finit-project.github.io/finit/>**
|
||||
:books: **<http://finit-project.github.io>**
|
||||
|
||||
<div align="center">
|
||||
<img src="doc/img/alpine-screenshot2.png" alt="Alpine screenshot"><br/>
|
||||
@@ -26,14 +25,14 @@ tutorials:
|
||||
* :milky_way: [Void Linux](contrib/void/)
|
||||
|
||||
> [!NOTE]
|
||||
> Support for various Linux distributions does not mean Finit installs
|
||||
> easily on all architectures. Bundled install scripts are examples for
|
||||
> standard installations, tested on amd64 (x86_64) systems. Custom
|
||||
> setups, e.g., for embedded systems, can be found in the following
|
||||
> [Buildroot][] based examples: [myLinux][], [Infix][], or the plain
|
||||
> [br2-finit-demo](https://github.com/finit-project/br2-finit-demo).
|
||||
> Finit can run on various Linux distributions, but the bundled install
|
||||
> scripts are examples only. They have been tested on amd64 (x86_64) systems
|
||||
> with standard configurations.
|
||||
>
|
||||
> For embedded systems, see these [Buildroot][]-based examples:
|
||||
> [myLinux][], [Infix][], or [br2-finit-demo][].
|
||||
|
||||
[finix]: https://github.com/aanderse/finix
|
||||
[finix]: https://github.com/finix-community/finix
|
||||
[Buildroot]: https://buildroot.org
|
||||
[Infix]: https://kernelkit.github.io
|
||||
[myLinux]: https://github.com/troglobit/myLinux/
|
||||
@@ -48,3 +47,4 @@ tutorials:
|
||||
[GitHub Status]: https://github.com/finit-project/finit/actions/workflows/build.yml/badge.svg
|
||||
[Coverity Scan]: https://scan.coverity.com/projects/3545
|
||||
[Coverity Status]: https://scan.coverity.com/projects/3545/badge.svg
|
||||
[br2-finit-demo]: https://github.com/finit-project/br2-finit-demo
|
||||
|
||||
+68
-13
@@ -1,4 +1,4 @@
|
||||
AC_INIT([Finit], [4.15-rc1], [https://github.com/finit-project/finit/issues],
|
||||
AC_INIT([Finit], [5.0-rc1], [https://github.com/finit-project/finit/issues],
|
||||
[finit], [https://http://finit-project.github.io/])
|
||||
AC_CONFIG_AUX_DIR(aux)
|
||||
AM_INIT_AUTOMAKE([1.11 foreign subdir-objects])
|
||||
@@ -12,10 +12,13 @@ AC_CONFIG_FILES([Makefile
|
||||
contrib/debian/Makefile contrib/debian/finit.d/Makefile contrib/debian/finit.d/available/Makefile
|
||||
contrib/void/Makefile contrib/void/finit.d/Makefile contrib/void/finit.d/available/Makefile
|
||||
doc/Makefile doc/config/Makefile
|
||||
dbus-1/Makefile
|
||||
libink/Makefile
|
||||
libsystemd/Makefile libsystemd/libsystemd.pc
|
||||
man/Makefile
|
||||
plugins/Makefile
|
||||
src/Makefile
|
||||
keventd/Makefile
|
||||
system/Makefile system/10-hotplug.conf
|
||||
test/test.env test/Makefile
|
||||
test/lib/Makefile test/src/Makefile
|
||||
@@ -37,7 +40,7 @@ AC_PROG_MKDIR_P
|
||||
|
||||
# Configuration.
|
||||
AC_CHECK_HEADERS([termios.h sys/ioctl.h mntent.h sys/sysmacros.h])
|
||||
AC_CHECK_FUNCS([strstr getopt getmntent getmntent_r])
|
||||
AC_CHECK_FUNCS([strstr getopt getmntent getmntent_r close_range])
|
||||
|
||||
# Check for uint[8,16,32]_t
|
||||
AC_TYPE_UINT8_T
|
||||
@@ -50,6 +53,12 @@ PKG_PROG_PKG_CONFIG
|
||||
# Check for required libraries
|
||||
PKG_CHECK_MODULES([uev], [libuev >= 2.4.1])
|
||||
PKG_CHECK_MODULES([lite], [libite >= 2.6.1])
|
||||
# 3.3 is the floor: CFGF_KEYSTRVAL, which environment {} and the
|
||||
# free-form cgroup keys are built on, does not exist before it. 3.3
|
||||
# parses both correctly. Two workarounds hang off this number, the
|
||||
# spurious KEYSTRVAL warning and cfg_parse_buf() losing the file name
|
||||
# of a template; grep the XXX notes in src/conf.c before raising it.
|
||||
PKG_CHECK_MODULES([confuse], [libconfuse >= 3.3])
|
||||
|
||||
# Check for configured Finit features
|
||||
AC_ARG_ENABLE(auto_reload,
|
||||
@@ -76,6 +85,11 @@ AC_ARG_ENABLE(libcap,
|
||||
AS_HELP_STRING([--disable-libcap], [Disable Linux capabilities support]),,[
|
||||
enable_libcap=yes])
|
||||
|
||||
AC_ARG_ENABLE(pam,
|
||||
AS_HELP_STRING([--disable-pam], [Disable PAM session support for services]),
|
||||
[pam_explicit=yes],
|
||||
[enable_pam=yes])
|
||||
|
||||
AC_ARG_ENABLE(redirect,
|
||||
AS_HELP_STRING([--disable-redirect], [Disable redirection of service output to /dev/null]),,[
|
||||
enable_redirect=yes])
|
||||
@@ -88,6 +102,10 @@ AC_ARG_ENABLE(logrotate,
|
||||
AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp]),,[
|
||||
enable_logrotate=yes])
|
||||
|
||||
AC_ARG_ENABLE(dbus,
|
||||
AS_HELP_STRING([--disable-dbus], [Disable D-Bus support (libink + Finit object tree)]),,[
|
||||
enable_dbus=yes])
|
||||
|
||||
AC_ARG_ENABLE(doc,
|
||||
AS_HELP_STRING([--disable-doc], [Disable build and install of doc/ section]),,[
|
||||
enable_doc=yes])
|
||||
@@ -105,17 +123,18 @@ AC_ARG_ENABLE(all_plugins,
|
||||
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([dbus], [no], [Setup and start system message bus, D-Bus])
|
||||
AC_PLUGIN([dbus], [yes], [Setup and start system message bus, D-Bus])
|
||||
AC_PLUGIN([modules-load], [no], [Scans /etc/modules-load.d for modules to load])
|
||||
AC_PLUGIN([modprobe], [no], [Coldplug modules using modalias magic])
|
||||
AC_PLUGIN([resolvconf], [no], [Setup necessary files for resolvconf])
|
||||
AC_PLUGIN([x11-common], [no], [Console setup (for X)])
|
||||
AC_PLUGIN([netlink], [yes], [Basic netlink plugin for IFUP/IFDN and GW events. Can be replaced with externally built plugin that links with libnl or similar.])
|
||||
AC_PLUGIN([hook-scripts], [no], [Trigger script execution from hook points])
|
||||
AC_PLUGIN([hotplug], [yes], [Start udevd or mdev kernel event datamon])
|
||||
AC_PLUGIN([hotplug], [no], [Start udevd or mdev kernel event datamon])
|
||||
AC_PLUGIN([rtc], [yes], [Save and restore RTC using hwclock])
|
||||
AC_PLUGIN([tty], [yes], [Automatically activate new TTYs, e.g. USB-to-serial])
|
||||
AC_PLUGIN([urandom], [yes], [Setup and save random seed at boot/shutdown])
|
||||
AC_PLUGIN([plymouth], [no], [Plymouth boot splash integration])
|
||||
AC_PLUGIN([testserv], [no], [Test plugin to start test serv daemon])
|
||||
|
||||
# Check for extra arguments or packages
|
||||
@@ -148,7 +167,7 @@ AC_ARG_WITH(sysconfig,
|
||||
[sysconfig=$withval], [sysconfig=default])
|
||||
|
||||
AC_ARG_WITH(group,
|
||||
AS_HELP_STRING([--with-group=NAME], [Group for /run/finit/socket (initctl), default: root]),
|
||||
AS_HELP_STRING([--with-group=NAME], [Group for /run/finit/socket and /run/finit/bus, default: root]),
|
||||
[group=$withval], [group=root])
|
||||
|
||||
AC_ARG_WITH(hostname,
|
||||
@@ -164,17 +183,20 @@ AC_ARG_WITH(random-seed,
|
||||
[random_seed=$withval], [random_seed=yes])
|
||||
|
||||
AC_ARG_WITH(keventd,
|
||||
AS_HELP_STRING([--with-keventd], [Enable built-in keventd, default: no]),, [with_keventd=no])
|
||||
AS_HELP_STRING([--with-keventd], [Enable built-in keventd device manager, default: yes]),, [with_keventd=yes])
|
||||
|
||||
AC_ARG_WITH(udev-rules,
|
||||
AS_HELP_STRING([--without-udev-rules], [Skip install of curated udev rules under /lib/udev/rules.d, default: yes when keventd enabled]),, [with_udev_rules=yes])
|
||||
|
||||
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])
|
||||
AS_HELP_STRING([--with-sulogin@<:@=USER@:>@], [Built-in sulogin, optional USER to request password for, default: yes (root)]),[sulogin=$withval],[with_sulogin=yes sulogin=yes])
|
||||
|
||||
AC_ARG_WITH(watchdog,
|
||||
AS_HELP_STRING([--with-watchdog@<:@=DEV@:>@], [Enable built-in watchdog, default: /dev/watchdog]),
|
||||
[watchdog=$withval], [with_watchdog=no watchdog=])
|
||||
AS_HELP_STRING([--with-watchdog@<:@=DEV@:>@], [Built-in watchdog, default: yes (/dev/watchdog)]),
|
||||
[watchdog=$withval], [with_watchdog=yes watchdog=yes])
|
||||
|
||||
AC_ARG_WITH(libsystemd,
|
||||
AS_HELP_STRING([--with-libsystemd], [Build replacement libsystemd library, default: yes]),
|
||||
AS_HELP_STRING([--with-libsystemd], [Build replacement libsystemd library, default: no]),
|
||||
[with_libsystemd=$withval], [with_libsystemd=no])
|
||||
|
||||
AC_ARG_WITH(hook-scripts-path,
|
||||
@@ -218,6 +240,26 @@ AS_IF([test "x$enable_libcap" = "xyes"], [
|
||||
])
|
||||
])
|
||||
|
||||
AS_IF([test "x$enable_pam" = "xyes"], [
|
||||
AS_IF([test "x$enable_static" = "xyes"], [
|
||||
AS_IF([test "x$pam_explicit" = "xyes"], [
|
||||
AC_MSG_ERROR([--enable-pam does not work with --enable-static, PAM dlopen()s its modules])], [
|
||||
AC_MSG_NOTICE([PAM disabled for static build, PAM dlopen()s its modules])
|
||||
enable_pam=no])])
|
||||
])
|
||||
AS_IF([test "x$enable_pam" = "xyes"], [
|
||||
AC_CHECK_HEADER([security/pam_appl.h], [], [
|
||||
AC_MSG_WARN([PAM headers not found, PAM support disabled])
|
||||
enable_pam=no])
|
||||
AS_IF([test "x$enable_pam" = "xyes"], [
|
||||
AC_CHECK_LIB([pam], [pam_start], [
|
||||
AC_DEFINE(HAVE_LIBPAM, 1, [Have Linux-PAM for per-service session support])
|
||||
LIBS="$LIBS -lpam"
|
||||
], [
|
||||
AC_MSG_WARN([libpam not found, PAM support disabled])
|
||||
enable_pam=no])])
|
||||
])
|
||||
|
||||
AS_IF([test "x$enable_fastboot" = "xyes"], [
|
||||
AC_DEFINE(FAST_BOOT, 1, [Skip fsck check on filesystems listed in /etc/fstab])])
|
||||
|
||||
@@ -236,6 +278,12 @@ AS_IF([test "x$enable_rescue" != "xno"], [
|
||||
|
||||
AM_CONDITIONAL(LOGROTATE, [test "x$enable_logrotate" = "xyes"])
|
||||
|
||||
AS_IF([test "x$enable_dbus" = "xyes"], [
|
||||
AC_DEFINE(HAVE_DBUS, 1, [Build D-Bus support via libink])])
|
||||
AM_CONDITIONAL(DBUS, [test "x$enable_dbus" = "xyes"])
|
||||
|
||||
AM_CONDITIONAL(PAM, [test "x$enable_pam" = "xyes"])
|
||||
|
||||
### With features ##############################################################################
|
||||
AS_IF([test "x$bash_dir" = "xyes"], [
|
||||
PKG_CHECK_MODULES([BASH_COMPLETION], [bash-completion >= 2.0],
|
||||
@@ -281,7 +329,7 @@ AS_IF([test "x$with_heading" != "xno"], [
|
||||
AS_IF([test "x$with_group" != "xno"], [
|
||||
AS_IF([test "x$group" = "xyes"], [
|
||||
group=root])])
|
||||
AC_DEFINE_UNQUOTED(DEFGROUP, "$group", [For /run/finit/socket])
|
||||
AC_DEFINE_UNQUOTED(DEFGROUP, "$group", [For /run/finit/socket and /run/finit/bus])
|
||||
|
||||
AS_IF([test "x$with_hostname" != "xno"], [
|
||||
AS_IF([test "x$hostname" = "xyes"], [
|
||||
@@ -311,7 +359,11 @@ AS_IF([test "x$rtc_file" != "xno"], [
|
||||
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
|
||||
PKG_CHECK_MODULES([blkid], [blkid],, [
|
||||
AC_MSG_ERROR([libblkid (util-linux) is required to build keventd.
|
||||
Install the dev package (e.g. libblkid-dev) or disable keventd with --without-keventd])])])
|
||||
|
||||
AS_IF([test "x$with_sulogin" != "xno"], [
|
||||
AS_IF([test "x$sulogin" = "xyes"], [
|
||||
@@ -344,6 +396,7 @@ AS_IF([test "x$with_plugin_path" != "xno"], [
|
||||
AM_CONDITIONAL(BASH, [test "x$bash_dir" != "xno"])
|
||||
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
||||
AM_CONDITIONAL(KEVENTD, [test "x$with_keventd" != "xno"])
|
||||
AM_CONDITIONAL(UDEV_RULES, [test "x$with_keventd" != "xno" -a "x$with_udev_rules" != "xno"])
|
||||
AM_CONDITIONAL(SULOGIN, [test "x$with_sulogin" != "xno"])
|
||||
AM_CONDITIONAL(WATCHDOGD, [test "x$with_watchdog" != "xno"])
|
||||
AM_CONDITIONAL(LIBSYSTEMD, [test "x$with_libsystemd" != "xno"])
|
||||
@@ -427,13 +480,15 @@ Optional features:
|
||||
Install doc/..........: $enable_doc
|
||||
Install contrib/......: $enable_contrib
|
||||
Bash completion.......: $bash_completion_dir
|
||||
Built-in keventd......: $with_keventd
|
||||
Built-in keventd......: $with_keventd (blkid: $blkid_LIBS)
|
||||
Built-in sulogin......: $with_sulogin $sulogin
|
||||
Built-in watchdogd....: $with_watchdog $watchdog
|
||||
Built-in logrotate....: $enable_logrotate
|
||||
D-Bus support (libink): $enable_dbus
|
||||
Replacement libsystemd: $with_libsystemd
|
||||
Use cgroup v2.........: $enable_cgroup
|
||||
Use libcap............: $enable_libcap
|
||||
Use PAM...............: $enable_pam
|
||||
Parse kernel cmdline..: $enable_kernel_cmdline
|
||||
Keep kernel logging...: $enable_kernel_logging
|
||||
Skip fsck check.......: $enable_fastboot
|
||||
|
||||
@@ -3,24 +3,34 @@
|
||||
|
||||
## Runlevel to start after bootstrap, runlevel 'S'
|
||||
# Default is 2
|
||||
#runlevel 2
|
||||
#runlevel = 2
|
||||
|
||||
# Top-level cgroups and their default settings. All groups mandatory
|
||||
# but more can be added, max 8 groups in total currently. The cgroup
|
||||
# 'root' is also available, reserved for RT processes. Settings are
|
||||
# as-is, only one shorthand 'mem.' exists, other than that it's the
|
||||
# cgroup v2 controller default names.
|
||||
#cgroup init cpu.weight:100
|
||||
#cgroup user cpu.weight:100
|
||||
#cgroup system cpu.weight:9700
|
||||
#cgroup init { cpu.weight = 100 }
|
||||
#cgroup user { cpu.weight = 100 }
|
||||
#cgroup system { cpu.weight = 9700 }
|
||||
|
||||
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
|
||||
# Finit upon receiving SIGINT (from the kernel).
|
||||
#task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
|
||||
#task reboot {
|
||||
# description = "Rebooting system"
|
||||
# runlevel = "12345789"
|
||||
# conditions = { "sys/key/ctrlaltdel" }
|
||||
# command = "initctl reboot"
|
||||
#}
|
||||
|
||||
# Task to run if the kernel gets a power fail condition is pressed.
|
||||
# Asserted by Finit upon receiving SIGPWR (from the kernel).
|
||||
#task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
|
||||
#task poweroff {
|
||||
# description = "Shutting down system"
|
||||
# runlevel = "12345789"
|
||||
# conditions = { "sys/pwr/fail" }
|
||||
# command = "initctl poweroff"
|
||||
#}
|
||||
|
||||
## Bootstrap services and tasks
|
||||
# Can be listed here or in /etc/finit.d/*.conf
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
# Handle PWR button to shutdown/reboot -- useful in Qemu (virt-manager)
|
||||
# Depends on syslogd having started. Redirect any output to log.
|
||||
service [2345] <pid/syslogd> log acpid -f -- ACPI daemon
|
||||
service acpid {
|
||||
description = "ACPI daemon"
|
||||
runlevel = "2345"
|
||||
conditions = { "pid/syslogd" }
|
||||
log { }
|
||||
command = "acpid -f"
|
||||
}
|
||||
|
||||
@@ -1 +1,7 @@
|
||||
service [2345] <pid/syslogd> env:-/etc/conf.d/crond crond -f -S $CRON_OPTS -- Cron daemon
|
||||
service crond {
|
||||
description = "Cron daemon"
|
||||
runlevel = "2345"
|
||||
conditions = { "pid/syslogd" }
|
||||
envfile = "-/etc/conf.d/crond"
|
||||
command = "crond -f -S $CRON_OPTS"
|
||||
}
|
||||
|
||||
@@ -1,2 +1,7 @@
|
||||
# Start SSH daemon as soon as basic networking comes up
|
||||
service [2345] env:-/etc/conf.d/dropbear dropbear -R -F $DROPBEAR_OPTS -- Dropbear SSH daemon
|
||||
service dropbear {
|
||||
description = "Dropbear SSH daemon"
|
||||
runlevel = "2345"
|
||||
envfile = "-/etc/conf.d/dropbear"
|
||||
command = "dropbear -R -F $DROPBEAR_OPTS"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
# Consoles to start getty on when system is up
|
||||
tty [12345] /dev/ttyS0 noclear
|
||||
tty [12345] /dev/tty1 noclear nowait
|
||||
tty [2345] /dev/tty2 noclear nowait
|
||||
tty [2345] /dev/tty3 noclear nowait
|
||||
tty ttyS0 {
|
||||
runlevel = "12345"
|
||||
device = "/dev/ttyS0"
|
||||
noclear = true
|
||||
}
|
||||
tty tty1 {
|
||||
runlevel = "12345"
|
||||
device = "/dev/tty1"
|
||||
noclear = true
|
||||
nowait = true
|
||||
}
|
||||
tty tty2 {
|
||||
runlevel = "2345"
|
||||
device = "/dev/tty2"
|
||||
noclear = true
|
||||
nowait = true
|
||||
}
|
||||
tty tty3 {
|
||||
runlevel = "2345"
|
||||
device = "/dev/tty3"
|
||||
noclear = true
|
||||
nowait = true
|
||||
}
|
||||
|
||||
@@ -1,2 +1,7 @@
|
||||
# Oneshot task to run once at bootstrap
|
||||
task [S] env:/etc/conf.d/loadkmap zcat $KEYMAP | loadkmap -- Loading keymap
|
||||
task keymap {
|
||||
description = "Loading keymap"
|
||||
runlevel = "S"
|
||||
envfile = "/etc/conf.d/loadkmap"
|
||||
command = "zcat $KEYMAP | loadkmap"
|
||||
}
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
service [2345] lxdm -- Lightweight Login Manager
|
||||
service lxdm {
|
||||
description = "Lightweight Login Manager"
|
||||
runlevel = "2345"
|
||||
command = "lxdm"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,2 @@
|
||||
## Linux kernel modules to load
|
||||
#module fbcon
|
||||
#module button
|
||||
#module evdev
|
||||
#module mousedev
|
||||
#module 8139cp
|
||||
#module softdog
|
||||
#modules = { "fbcon", "button", "evdev", "mousedev", "8139cp", "softdog" }
|
||||
|
||||
@@ -1,2 +1,9 @@
|
||||
# Busybox ntpd has no option to use syslog when running in foreground
|
||||
service [2345] <pid/syslogd> env:-/etc/conf.d/ntpd log ntpd -n $NTPD_OPTS -- NTP daemon
|
||||
service ntpd {
|
||||
description = "NTP daemon"
|
||||
runlevel = "2345"
|
||||
conditions = { "pid/syslogd" }
|
||||
envfile = "-/etc/conf.d/ntpd"
|
||||
log { }
|
||||
command = "ntpd -n $NTPD_OPTS"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,15 @@
|
||||
# Start syslogd as soon as possible, should always run
|
||||
# Start klogd as soon as possible, but after syslogd
|
||||
service [S12345] env:-/etc/conf.d/syslog syslogd -n $SYSLOGD_OPTS -- Syslog daemon
|
||||
service [S12345] <pid/syslogd> env:-/etc/conf.d/klogd klogd -n $KLOGD_OPTS -- Kernel log daemon
|
||||
service syslogd {
|
||||
description = "Syslog daemon"
|
||||
runlevel = "S12345"
|
||||
envfile = "-/etc/conf.d/syslog"
|
||||
command = "syslogd -n $SYSLOGD_OPTS"
|
||||
}
|
||||
service klogd {
|
||||
description = "Kernel log daemon"
|
||||
runlevel = "S12345"
|
||||
conditions = { "pid/syslogd" }
|
||||
envfile = "-/etc/conf.d/klogd"
|
||||
command = "klogd -n $KLOGD_OPTS"
|
||||
}
|
||||
|
||||
@@ -1 +1,6 @@
|
||||
service [S123456789] env:-/etc/conf.d/watchdog watchdog $WATCHDOG_OPTS $WATCHDOG_DEV -- System watchdog
|
||||
service watchdog {
|
||||
description = "System watchdog"
|
||||
runlevel = "S123456789"
|
||||
envfile = "-/etc/conf.d/watchdog"
|
||||
command = "watchdog $WATCHDOG_OPTS $WATCHDOG_DEV"
|
||||
}
|
||||
|
||||
@@ -3,24 +3,34 @@
|
||||
|
||||
## Runlevel to start after bootstrap, runlevel 'S'
|
||||
# Default is 2
|
||||
#runlevel 2
|
||||
#runlevel = 2
|
||||
|
||||
# Top-level cgroups and their default settings. All groups mandatory
|
||||
# but more can be added, max 8 groups in total currently. The cgroup
|
||||
# 'root' is also available, reserved for RT processes. Settings are
|
||||
# as-is, only one shorthand 'mem.' exists, other than that it's the
|
||||
# cgroup v2 controller default names.
|
||||
#cgroup init cpu.weight:100
|
||||
#cgroup user cpu.weight:100
|
||||
#cgroup system cpu.weight:9700
|
||||
#cgroup init { cpu.weight = 100 }
|
||||
#cgroup user { cpu.weight = 100 }
|
||||
#cgroup system { cpu.weight = 9700 }
|
||||
|
||||
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
|
||||
# Finit upon receiving SIGINT (from the kernel).
|
||||
#task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
|
||||
#task reboot {
|
||||
# description = "Rebooting system"
|
||||
# runlevel = "12345789"
|
||||
# conditions = { "sys/key/ctrlaltdel" }
|
||||
# command = "initctl reboot"
|
||||
#}
|
||||
|
||||
# Task to run if the kernel gets a power fail condition is pressed.
|
||||
# Asserted by Finit upon receiving SIGPWR (from the kernel).
|
||||
#task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
|
||||
#task poweroff {
|
||||
# description = "Shutting down system"
|
||||
# runlevel = "12345789"
|
||||
# conditions = { "sys/pwr/fail" }
|
||||
# command = "initctl poweroff"
|
||||
#}
|
||||
|
||||
## Bootstrap services and tasks
|
||||
# Can be listed here or in /etc/finit.d/*.conf
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
# Handle PWR button to shutdown/reboot -- useful in Qemu (virt-manager)
|
||||
# Depends on a syslog daemon having started. Redirect any output to log.
|
||||
service [2345] <pid/syslogd> env:-/etc/default/acpid log acpid -f $OPTIONS -- ACPI daemon
|
||||
service acpid {
|
||||
description = "ACPI daemon"
|
||||
runlevel = "2345"
|
||||
conditions = { "pid/syslogd" }
|
||||
envfile = "-/etc/default/acpid"
|
||||
log { }
|
||||
command = "acpid -f $OPTIONS"
|
||||
}
|
||||
|
||||
@@ -1 +1,8 @@
|
||||
task [2345] <sys/pwr/ac,pid/syslogd> halt:usr1 env:-/etc/default/anacron anacron -d -q $ANACRON_ARGS -- Anacron jobs
|
||||
task anacron {
|
||||
description = "Anacron jobs"
|
||||
runlevel = "2345"
|
||||
conditions = { "sys/pwr/ac", "pid/syslogd" }
|
||||
envfile = "-/etc/default/anacron"
|
||||
stop-signal = "usr1"
|
||||
command = "anacron -d -q $ANACRON_ARGS"
|
||||
}
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
sysv [S] /etc/init.d/apparmor -- AppArmor initialization
|
||||
sysv apparmor {
|
||||
description = "AppArmor initialization"
|
||||
runlevel = "S"
|
||||
command = "/etc/init.d/apparmor"
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1,6 @@
|
||||
service [2345] env:-/etc/default/avahi-daemon avahi-daemon -s $AVAHI_DAEMON_OPTS -- Avahi mDNS/DNS-SD Stack
|
||||
service avahi-daemon {
|
||||
description = "Avahi mDNS/DNS-SD Stack"
|
||||
runlevel = "2345"
|
||||
envfile = "-/etc/default/avahi-daemon"
|
||||
command = "avahi-daemon -s $AVAHI_DAEMON_OPTS"
|
||||
}
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
# To ignore errors like "org.freedesktop.hostname1", update the env file with
|
||||
# "--noplugin=hostname", i.e. append to BLUETOOTHD_OPTS
|
||||
service [2345] log:null env:-/etc/default/bluetooth /usr/libexec/bluetooth/bluetoothd -n $BLUETOOTHD_OPTS -- Bluetooth service
|
||||
service bluetoothd {
|
||||
description = "Bluetooth service"
|
||||
runlevel = "2345"
|
||||
envfile = "-/etc/default/bluetooth"
|
||||
log { file = "/dev/null" }
|
||||
command = "/usr/libexec/bluetooth/bluetoothd -n $BLUETOOTHD_OPTS"
|
||||
}
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
# Oneshot task to run once at bootstrap
|
||||
task [S] /lib/console-setup/console-setup.sh -- Setting up console font and keymap
|
||||
task console-setup {
|
||||
description = "Setting up console font and keymap"
|
||||
runlevel = "S"
|
||||
command = "/lib/console-setup/console-setup.sh"
|
||||
}
|
||||
|
||||
@@ -1 +1,7 @@
|
||||
service [2345] <sys/pwr/ac,pid/syslogd> env:-/etc/default/cron cron -f $EXTRA_OPTS -- Background job processing daemon
|
||||
service cron {
|
||||
description = "Background job processing daemon"
|
||||
runlevel = "2345"
|
||||
conditions = { "sys/pwr/ac", "pid/syslogd" }
|
||||
envfile = "-/etc/default/cron"
|
||||
command = "cron -f $EXTRA_OPTS"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
# On some systems, bootstrap can be really quick and cause elogind
|
||||
# to not start before a user has managed to log in. To prevent
|
||||
# this, add <pid/elogind> as condition to your TTYs in getty.conf
|
||||
service [2345] <pid/syslogd> /lib/elogind/elogind -- Login manager
|
||||
service elogind {
|
||||
description = "Login manager"
|
||||
runlevel = "2345"
|
||||
conditions = { "pid/syslogd" }
|
||||
command = "/usr/libexec/elogind"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,38 @@
|
||||
# Consoles to start getty on when system is up
|
||||
tty [12345] /dev/tty1 linux noclear nowait
|
||||
tty [2345] /dev/tty2 linux nowait
|
||||
tty [2345] /dev/tty3 linux nowait
|
||||
tty [2345] /dev/tty4 linux nowait
|
||||
tty [2345] /dev/tty5 linux nowait
|
||||
tty [2345] /dev/tty6 linux nowait
|
||||
tty tty1 {
|
||||
runlevel = "12345"
|
||||
device = "/dev/tty1"
|
||||
term = "linux"
|
||||
noclear = true
|
||||
nowait = true
|
||||
}
|
||||
tty tty2 {
|
||||
runlevel = "2345"
|
||||
device = "/dev/tty2"
|
||||
term = "linux"
|
||||
nowait = true
|
||||
}
|
||||
tty tty3 {
|
||||
runlevel = "2345"
|
||||
device = "/dev/tty3"
|
||||
term = "linux"
|
||||
nowait = true
|
||||
}
|
||||
tty tty4 {
|
||||
runlevel = "2345"
|
||||
device = "/dev/tty4"
|
||||
term = "linux"
|
||||
nowait = true
|
||||
}
|
||||
tty tty5 {
|
||||
runlevel = "2345"
|
||||
device = "/dev/tty5"
|
||||
term = "linux"
|
||||
nowait = true
|
||||
}
|
||||
tty tty6 {
|
||||
runlevel = "2345"
|
||||
device = "/dev/tty6"
|
||||
term = "linux"
|
||||
nowait = true
|
||||
}
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
# Oneshot task to run once at bootstrap
|
||||
task [S] /lib/console-setup/keyboard-setup.sh -- Setting up console keyboard layout
|
||||
task keyboard-setup {
|
||||
description = "Setting up console keyboard layout"
|
||||
runlevel = "S"
|
||||
command = "/lib/console-setup/keyboard-setup.sh"
|
||||
}
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
service [3] lightdm -- Light Display Manager
|
||||
service lightdm {
|
||||
description = "Light Display Manager"
|
||||
runlevel = "3"
|
||||
command = "lightdm"
|
||||
}
|
||||
|
||||
@@ -1,8 +1,2 @@
|
||||
## Linux kernel modules to load
|
||||
#module fbcon
|
||||
#module button
|
||||
#module evdev
|
||||
#module loop
|
||||
#module psmouse
|
||||
#module mousedev
|
||||
#module 8139cp
|
||||
#modules = { "fbcon", "button", "evdev", "loop", "psmouse", "mousedev", "8139cp" }
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
# Need to stop plymouth, or it'll block stdin on tty1
|
||||
task [S] /usr/bin/plymouth quit -- Stopping Plymouth Boot Screen
|
||||
task plymouth {
|
||||
description = "Stopping Plymouth Boot Screen"
|
||||
runlevel = "S"
|
||||
command = "/usr/bin/plymouth quit"
|
||||
}
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
# Start rsyslogd as soon as possible, should always run
|
||||
# Provides pid/syslogd condition
|
||||
service [S12345] name:syslogd env:-/etc/default/rsyslog rsyslogd -n $RSYSLOGD_OPTIONS -- Reliable syslog daemon
|
||||
service syslogd {
|
||||
description = "Reliable syslog daemon"
|
||||
runlevel = "S12345"
|
||||
envfile = "-/etc/default/rsyslog"
|
||||
command = "rsyslogd -n $RSYSLOGD_OPTIONS"
|
||||
}
|
||||
|
||||
@@ -1,2 +1,8 @@
|
||||
# Simple NTP client (SNTP)
|
||||
service [2345] <net/route/default> env:-/etc/default/sntpd sntpd -n $SNTPD_OPTIONS -- SNTP client
|
||||
service sntpd {
|
||||
description = "SNTP client"
|
||||
runlevel = "2345"
|
||||
conditions = { "net/route/default" }
|
||||
envfile = "-/etc/default/sntpd"
|
||||
command = "sntpd -n $SNTPD_OPTIONS"
|
||||
}
|
||||
|
||||
@@ -1,2 +1,8 @@
|
||||
# Start SSH daemon as soon as basic networking comes up
|
||||
service [2345] <net/lo/up> env:-/etc/default/ssh /usr/sbin/sshd -D $SSHD_OPTS -- OpenSSH daemon
|
||||
service sshd {
|
||||
description = "OpenSSH daemon"
|
||||
runlevel = "2345"
|
||||
conditions = { "net/lo/up" }
|
||||
envfile = "-/etc/default/ssh"
|
||||
command = "/usr/sbin/sshd -D $SSHD_OPTS"
|
||||
}
|
||||
|
||||
@@ -1,2 +1,7 @@
|
||||
# Start sysklogd as soon as possible, should always run if enabled
|
||||
service [S123456789] env:-/etc/default/syslogd syslogd -F $SYSLOGD_OPTIONS -- System logging daemon
|
||||
service syslogd {
|
||||
description = "System logging daemon"
|
||||
runlevel = "S123456789"
|
||||
envfile = "-/etc/default/syslogd"
|
||||
command = "syslogd -F $SYSLOGD_OPTIONS"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
# Here we use XDM since it has few dependencies (relatively speaking).
|
||||
# It is also an example of a service without a -- description.
|
||||
# service [3] lxdm -- Lightweight Login Manager
|
||||
service [3] xdm -nodaemon -- X Display Manager
|
||||
service xdm {
|
||||
description = "X Display Manager"
|
||||
runlevel = "3"
|
||||
command = "xdm -nodaemon"
|
||||
}
|
||||
|
||||
+107
-43
@@ -1,85 +1,149 @@
|
||||
# Sample finit.conf to demonstrate the syntax
|
||||
#
|
||||
host testbed
|
||||
hostname = "testbed"
|
||||
|
||||
# Linux kernel modules to load
|
||||
module button
|
||||
module evdev
|
||||
module loop
|
||||
module psmouse
|
||||
modules = { "button", "evdev", "loop", "psmouse" }
|
||||
|
||||
# Top-level cgroups and their default settings. All groups mandatory
|
||||
# but more can be added, max 8 groups in total currently. The cgroup
|
||||
# 'root' is also available, reserved for RT processes. Settings are
|
||||
# as-is, only one shorthand 'mem.' exists, other than that it's the
|
||||
# cgroup v2 controller default names.
|
||||
cgroup init cpu.weight:100
|
||||
cgroup user cpu.weight:100
|
||||
cgroup system cpu.weight:9700 cpu.max:50000
|
||||
cgroup init { cpu.weight = 100 }
|
||||
cgroup user { cpu.weight = 100 }
|
||||
cgroup system { cpu.weight = 9700 cpu.max = 50000 }
|
||||
|
||||
# Example extra cgroup
|
||||
cgroup maint cpu.weight:100
|
||||
cgroup maint { cpu.weight = 100 }
|
||||
|
||||
# Runlevel to start after bootstrap, runlevel 'S'
|
||||
runlevel 2
|
||||
runlevel = 2
|
||||
|
||||
# Network bringup script
|
||||
network service networking start
|
||||
network = "service networking start"
|
||||
|
||||
# Max file size for each log file: 100 kiB, rotate max 4 copies:
|
||||
# log => log.1 => log.2.gz => log.3.gz => log.4.gz
|
||||
log size:100k count:4
|
||||
log {
|
||||
size = 100k
|
||||
count = 4
|
||||
}
|
||||
|
||||
# Virtual consoles to start getty on
|
||||
tty /dev/tty1
|
||||
tty /dev/tty2
|
||||
tty /dev/tty3
|
||||
tty tty1 { device = "/dev/tty1" }
|
||||
tty tty2 { device = "/dev/tty2" }
|
||||
tty tty3 { device = "/dev/tty3" }
|
||||
|
||||
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
|
||||
# Finit upon receiving SIGINT (from the kernel).
|
||||
task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
|
||||
task reboot {
|
||||
description = "Rebooting system"
|
||||
runlevel = "12345789"
|
||||
conditions = { "sys/key/ctrlaltdel" }
|
||||
command = "initctl reboot"
|
||||
}
|
||||
|
||||
# Task to run if the kernel gets a power fail condition is pressed.
|
||||
# Asserted by Finit upon receiving SIGPWR (from the kernel).
|
||||
task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
|
||||
task poweroff {
|
||||
description = "Shutting down system"
|
||||
runlevel = "12345789"
|
||||
conditions = { "sys/pwr/fail" }
|
||||
command = "initctl poweroff"
|
||||
}
|
||||
|
||||
# Alternative method instead of runparts
|
||||
#task [S] /etc/init.d/keyboard-setup start -- Setting up preliminary keymap
|
||||
#task [S] /etc/init.d/acpid start -- Starting ACPI Daemon
|
||||
#task [S] /etc/init.d/kbd start -- Preparing console
|
||||
#run [2] /etc/init.d/networking start -- Start networking
|
||||
#task keyboard-setup {
|
||||
# description = "Setting up preliminary keymap"
|
||||
# runlevel = "S"
|
||||
# command = "/etc/init.d/keyboard-setup start"
|
||||
#}
|
||||
#task acpid {
|
||||
# description = "Starting ACPI Daemon"
|
||||
# runlevel = "S"
|
||||
# command = "/etc/init.d/acpid start"
|
||||
#}
|
||||
#task kbd {
|
||||
# description = "Preparing console"
|
||||
# runlevel = "S"
|
||||
# command = "/etc/init.d/kbd start"
|
||||
#}
|
||||
#run networking {
|
||||
# description = "Start networking"
|
||||
# runlevel = "2"
|
||||
# command = "/etc/init.d/networking start"
|
||||
#}
|
||||
|
||||
# Services to be monitored and respawned as needed
|
||||
|
||||
# klgod and syslogd are placed in the maint cgroup
|
||||
cgroup.maint
|
||||
service [2345] <pid/syslogd> klogd -n -- Kernel logging server
|
||||
service [2345] syslogd -n -- Syslog server
|
||||
# klogd and syslogd are placed in the maint cgroup. There is no
|
||||
# "current cgroup" to switch in this format, every block names its own.
|
||||
service klogd {
|
||||
description = "Kernel logging server"
|
||||
runlevel = "2345"
|
||||
conditions = { "pid/syslogd" }
|
||||
cgroup maint {}
|
||||
command = "klogd -n"
|
||||
}
|
||||
service syslogd {
|
||||
description = "Syslog server"
|
||||
runlevel = "2345"
|
||||
cgroup maint {}
|
||||
command = "syslogd -n"
|
||||
}
|
||||
|
||||
# gdm in the system cgroup (default when read from it's own .conf file)
|
||||
cgroup.system
|
||||
service [3] cgroup:cpu.weight:250,mem.max:10M gdm -- GNOME Display Manager
|
||||
# gdm gets its own limits inside the system group, which is where
|
||||
# services end up when no cgroup block is given.
|
||||
service gdm {
|
||||
description = "GNOME Display Manager"
|
||||
runlevel = "3"
|
||||
cgroup system {
|
||||
cpu.weight = 250
|
||||
memory.max = 10M
|
||||
}
|
||||
command = "gdm"
|
||||
}
|
||||
|
||||
# Start SSH daemon with opts from /etc/default/ssh (if available), move
|
||||
# to user cgroup with cpu.weight:250. Default for services is system
|
||||
# group. Default weight in user group is 100 (above). Max length of
|
||||
# cgroup argument is (currently) 63 chars.
|
||||
#
|
||||
# Notice alternative syntax where current cgroup is only set for this
|
||||
# particular service.
|
||||
service [2345] cgroup.user:cpu.weight:250,mem.max:10M env:-/etc/default/ssh /usr/sbin/sshd -D $SSHD_OPTS -- OpenSSH daemon
|
||||
# to user cgroup with cpu.weight 250. Default weight in the user group
|
||||
# is 100 (above).
|
||||
service sshd {
|
||||
description = "OpenSSH daemon"
|
||||
runlevel = "2345"
|
||||
envfile = "-/etc/default/ssh"
|
||||
cgroup user {
|
||||
cpu.weight = 250
|
||||
memory.max = 10M
|
||||
}
|
||||
command = "/usr/sbin/sshd -D $SSHD_OPTS"
|
||||
}
|
||||
|
||||
# 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] <!net/route/default> log:/var/log/ntpd.log ntpd -n -l -I eth0 -- NTP daemon
|
||||
# a dependency on a system default route (gateway) to be set. ntpd
|
||||
# does not respect SIGHUP, so Finit restarts it on reload instead.
|
||||
service ntpd {
|
||||
description = "NTP daemon"
|
||||
runlevel = "2345"
|
||||
conditions = { "net/route/default" }
|
||||
reload-signal = "none"
|
||||
log { file = "/var/log/ntpd.log" }
|
||||
command = "ntpd -n -l -I eth0"
|
||||
}
|
||||
|
||||
# Run start scripts from this directory
|
||||
# runparts /etc/start.d
|
||||
#runparts = "/etc/start.d"
|
||||
|
||||
# For multiple instances of the same service, add :ID somewhere between
|
||||
# the service/run/task keyword and the command.
|
||||
service :80 [2345] /sbin/httpd -f -h /http -p 80 -- Web server
|
||||
service :8080 [2345] /sbin/httpd -f -h /http -p 8080 -- Old web server
|
||||
# For multiple instances of the same service, add :ID to the block title.
|
||||
service httpd:80 {
|
||||
description = "Web server"
|
||||
runlevel = "2345"
|
||||
command = "/sbin/httpd -f -h /http -p 80"
|
||||
}
|
||||
service httpd:8080 {
|
||||
description = "Old web server"
|
||||
runlevel = "2345"
|
||||
command = "/sbin/httpd -f -h /http -p 8080"
|
||||
}
|
||||
|
||||
+16
-6
@@ -3,24 +3,34 @@
|
||||
|
||||
## Runlevel to start after bootstrap, runlevel 'S'
|
||||
# Default is 2
|
||||
#runlevel 2
|
||||
#runlevel = 2
|
||||
|
||||
# Top-level cgroups and their default settings. All groups mandatory
|
||||
# but more can be added, max 8 groups in total currently. The cgroup
|
||||
# 'root' is also available, reserved for RT processes. Settings are
|
||||
# as-is, only one shorthand 'mem.' exists, other than that it's the
|
||||
# cgroup v2 controller default names.
|
||||
#cgroup init cpu.weight:100
|
||||
#cgroup user cpu.weight:100
|
||||
#cgroup system cpu.weight:9700
|
||||
#cgroup init { cpu.weight = 100 }
|
||||
#cgroup user { cpu.weight = 100 }
|
||||
#cgroup system { cpu.weight = 9700 }
|
||||
|
||||
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
|
||||
# Finit upon receiving SIGINT (from the kernel).
|
||||
#task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
|
||||
#task reboot {
|
||||
# description = "Rebooting system"
|
||||
# runlevel = "12345789"
|
||||
# conditions = { "sys/key/ctrlaltdel" }
|
||||
# command = "initctl reboot"
|
||||
#}
|
||||
|
||||
# Task to run if the kernel gets a power fail condition is pressed.
|
||||
# Asserted by Finit upon receiving SIGPWR (from the kernel).
|
||||
#task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
|
||||
#task poweroff {
|
||||
# description = "Shutting down system"
|
||||
# runlevel = "12345789"
|
||||
# conditions = { "sys/pwr/fail" }
|
||||
# command = "initctl poweroff"
|
||||
#}
|
||||
|
||||
## Bootstrap services and tasks
|
||||
# Can be listed here or in /etc/finit.d/*.conf
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
# Handle PWR button to shutdown/reboot -- useful in Qemu (virt-manager)
|
||||
# Depends on syslogd having started. Redirect any output to log.
|
||||
service [2345] acpid -f -- ACPI daemon
|
||||
service acpid {
|
||||
description = "ACPI daemon"
|
||||
runlevel = "2345"
|
||||
command = "acpid -f"
|
||||
}
|
||||
|
||||
@@ -1 +1,6 @@
|
||||
service [2345] <pid/syslogd> crond -f -S -c /etc/crontabs -- Cron daemon
|
||||
service crond {
|
||||
description = "Cron daemon"
|
||||
runlevel = "2345"
|
||||
conditions = { "pid/syslogd" }
|
||||
command = "crond -f -S -c /etc/crontabs"
|
||||
}
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
service [2345] dhcpcd -B -M -- DHCP client
|
||||
service dhcpcd {
|
||||
description = "DHCP client"
|
||||
runlevel = "2345"
|
||||
command = "dhcpcd -B -M"
|
||||
}
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
service [S12345] dmeventd -f -- Device mapper event daemon
|
||||
service dmeventd {
|
||||
description = "Device mapper event daemon"
|
||||
runlevel = "S12345"
|
||||
command = "dmeventd -f"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,19 @@
|
||||
# Consoles to start Finit built-in getty on when system is up
|
||||
tty [12345] /dev/tty1 noclear nowait
|
||||
tty [2345] /dev/tty2 noclear nowait
|
||||
tty [2345] /dev/tty3 noclear nowait
|
||||
tty tty1 {
|
||||
runlevel = "12345"
|
||||
device = "/dev/tty1"
|
||||
noclear = true
|
||||
nowait = true
|
||||
}
|
||||
tty tty2 {
|
||||
runlevel = "2345"
|
||||
device = "/dev/tty2"
|
||||
noclear = true
|
||||
nowait = true
|
||||
}
|
||||
tty tty3 {
|
||||
runlevel = "2345"
|
||||
device = "/dev/tty3"
|
||||
noclear = true
|
||||
nowait = true
|
||||
}
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
# Oneshot task to run once at bootstrap
|
||||
task [S] zcat /etc/keymap/se.bmap.gz | loadkmap -- Loading keymap
|
||||
task keymap {
|
||||
description = "Loading keymap"
|
||||
runlevel = "S"
|
||||
command = "zcat /etc/keymap/se.bmap.gz | loadkmap"
|
||||
}
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
service [2345] lxdm -- Lightweight Login Manager
|
||||
service lxdm {
|
||||
description = "Lightweight Login Manager"
|
||||
runlevel = "2345"
|
||||
command = "lxdm"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
## Linux kernel modules to load
|
||||
#module fbcon
|
||||
#module button
|
||||
#module evdev
|
||||
#module mousedev
|
||||
#module 8139cp
|
||||
module softdog
|
||||
# Other candidates: fbcon, button, evdev, mousedev, 8139cp
|
||||
modules = { "softdog" }
|
||||
|
||||
@@ -1,2 +1,8 @@
|
||||
# Silly Busybox ntpd has no option to use syslog when running in foreground
|
||||
service [2345] <pid/syslogd> log ntpd -n -N -p pool.ntp.org -- NTP daemon
|
||||
service ntpd {
|
||||
description = "NTP daemon"
|
||||
runlevel = "2345"
|
||||
conditions = { "pid/syslogd" }
|
||||
log { }
|
||||
command = "ntpd -n -N -p pool.ntp.org"
|
||||
}
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
# Start SSH daemon as soon as basic networking comes up
|
||||
service [2345] /usr/sbin/sshd -D -- OpenSSH daemon
|
||||
service sshd {
|
||||
description = "OpenSSH daemon"
|
||||
runlevel = "2345"
|
||||
command = "/usr/sbin/sshd -D"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
# Start syslogd as soon as possible, should always run
|
||||
# Start klogd as soon as possible, but after syslogd
|
||||
service [S12345] syslogd -n -- Syslog daemon
|
||||
service [S12345] <pid/syslogd> klogd -n -- Kernel log daemon
|
||||
service syslogd {
|
||||
description = "Syslog daemon"
|
||||
runlevel = "S12345"
|
||||
command = "syslogd -n"
|
||||
}
|
||||
service klogd {
|
||||
description = "Kernel log daemon"
|
||||
runlevel = "S12345"
|
||||
conditions = { "pid/syslogd" }
|
||||
command = "klogd -n"
|
||||
}
|
||||
|
||||
@@ -1 +1,7 @@
|
||||
service @uuidd:uuidd [2345] uuidd -F -- UUID generation daemon
|
||||
service uuidd {
|
||||
description = "UUID generation daemon"
|
||||
runlevel = "2345"
|
||||
user = "uuidd"
|
||||
group = "uuidd"
|
||||
command = "uuidd -F"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
/Makefile
|
||||
/Makefile.in
|
||||
@@ -0,0 +1,6 @@
|
||||
EXTRA_DIST = org.finit.conf
|
||||
|
||||
if DBUS
|
||||
dbuspolicydir = $(datadir)/dbus-1/system.d
|
||||
dist_dbuspolicy_DATA = org.finit.conf
|
||||
endif
|
||||
@@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE busconfig PUBLIC
|
||||
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||||
<!--
|
||||
System-bus policy for finit.
|
||||
|
||||
finit (PID 1, root) owns the `org.finit` well-known name. The
|
||||
policy below lets unprivileged callers introspect, read
|
||||
properties, and query service / condition state, but disallows
|
||||
every state-changing method at the broker. finit *also* enforces
|
||||
per-method authorisation itself (LINK_METHOD_PRIVILEGED), so
|
||||
defense-in-depth: even if a permissive policy is installed by
|
||||
mistake, finit rejects unprivileged state changes. It reads the
|
||||
caller from SO_PEERCRED on the local bus, and on the system bus it
|
||||
asks the broker who sent each privileged call, via
|
||||
GetConnectionUnixUser.
|
||||
-->
|
||||
<busconfig>
|
||||
|
||||
<!-- Only finit (root) may own the org.finit bus name. -->
|
||||
<policy user="root">
|
||||
<allow own="org.finit"/>
|
||||
<allow send_destination="org.finit"/>
|
||||
<allow receive_sender="org.finit"/>
|
||||
</policy>
|
||||
|
||||
<!-- Everyone may introspect, read properties, and call the
|
||||
read-only Manager1 / Cond1 methods. Signals fan out
|
||||
unconditionally. -->
|
||||
<policy context="default">
|
||||
<allow send_destination="org.finit"
|
||||
send_interface="org.freedesktop.DBus.Introspectable"/>
|
||||
<allow send_destination="org.finit"
|
||||
send_interface="org.freedesktop.DBus.Peer"/>
|
||||
<allow send_destination="org.finit"
|
||||
send_interface="org.freedesktop.DBus.Properties"
|
||||
send_member="Get"/>
|
||||
<allow send_destination="org.finit"
|
||||
send_interface="org.freedesktop.DBus.Properties"
|
||||
send_member="GetAll"/>
|
||||
|
||||
<allow send_destination="org.finit"
|
||||
send_interface="org.finit.Manager1"
|
||||
send_member="ListServices"/>
|
||||
<allow send_destination="org.finit"
|
||||
send_interface="org.finit.Manager1"
|
||||
send_member="GetService"/>
|
||||
|
||||
<allow send_destination="org.finit"
|
||||
send_interface="org.finit.Cond1"
|
||||
send_member="Get"/>
|
||||
<allow send_destination="org.finit"
|
||||
send_interface="org.finit.Cond1"
|
||||
send_member="List"/>
|
||||
<allow send_destination="org.finit"
|
||||
send_interface="org.finit.Cond1"
|
||||
send_member="Dump"/>
|
||||
|
||||
<allow receive_sender="org.finit"/>
|
||||
</policy>
|
||||
|
||||
</busconfig>
|
||||
+302
-2
@@ -3,9 +3,281 @@ Change Log
|
||||
|
||||
All relevant changes are documented in this file.
|
||||
|
||||
[4.15][UNRELEASED]
|
||||
[5.0][UNRELEASED]
|
||||
--------------------
|
||||
|
||||
### Changes
|
||||
|
||||
- keventd is now a full device manager, promoted from the power supply
|
||||
monitor it was in v4, and the device management defaults have swapped:
|
||||
keventd is enabled by default (`--without-keventd` opts out, libblkid is
|
||||
required to build it), while the hotplug plugin, which runs an external
|
||||
`udevd`, `mdevd`, or `mdev`, is now opt-in. With the plugin enabled,
|
||||
keventd steps back to passive mode and monitors only power supply
|
||||
events, as before. As the system device manager it replaces mdev,
|
||||
mdevd, and udevd, and handles:
|
||||
|
||||
* udev rules: an engine covering most of the udev(7) grammar --
|
||||
parent-chain matching, `PROGRAM`/`RESULT`, `IMPORT`, `RUN`,
|
||||
`GOTO`/`LABEL`, and the standard substitutions -- reading the usual
|
||||
`udev/rules.d` directories under `/lib`, `/run`, and `/etc` with
|
||||
udev's precedence and masking. A curated ruleset derived from eudev
|
||||
3.2.14 is installed by default, `--without-udev-rules` skips it.
|
||||
See [Device Manager](keventd.md) for the supported subset and the
|
||||
few deliberate divergences
|
||||
|
||||
* builtins used by the ruleset: `blkid`, `hwdb`, `input_id`, `kmod`,
|
||||
`net_id`, `path_id`, and `usb_id`
|
||||
|
||||
* device nodes with per-subsystem default permissions, persistent
|
||||
symlinks (`/dev/disk/by-uuid`, `by-label`, `by-id`, `by-path`, plus
|
||||
`by-id`/`by-path` for input, serial, sound, v4l, and tape), kernel
|
||||
firmware load requests, and module loading from `MODALIAS`
|
||||
|
||||
* predictable network interface names via the eudev ruleset,
|
||||
`net.ifnames=0` on the kernel command line keeps classic names.
|
||||
**Note:** switching a system over to keventd can rename its NICs
|
||||
|
||||
* coldplug: as device manager keventd starts with `-c`, replaying add
|
||||
events for hardware present at boot. The `pid/keventd` condition
|
||||
is deferred until the coldplug queue has drained, so services
|
||||
gating on it can assume `/dev` is populated and symlinks are live
|
||||
|
||||
* `keventd -S`, the `udevadm settle` equivalent, asks the running
|
||||
daemon over D-Bus and falls back to polling the kernel's uevent
|
||||
sequence number
|
||||
|
||||
* libudev compatibility: per-device properties in `/run/udev/data`
|
||||
and processed uevents rebroadcast to netlink group 0x4, so
|
||||
libudev-zero consumers, e.g. compositors and libinput, see hotplug
|
||||
events
|
||||
|
||||
* new conditions for the service engine: `dev/<node>` for device
|
||||
nodes, `class/<subsystem>/<name>` for sysfs class devices without a
|
||||
node (LEDs, IIO, DSA ports), and `driver/<name>`, asserted while a
|
||||
driver is bound to at least one device
|
||||
|
||||
- Generated `/run/finit/system/*.conf` files for bundled services (keventd,
|
||||
watchdogd, runparts) are now read before `/lib/finit/system/*.conf` instead
|
||||
of after. Built-ins can now be referenced in `if:` statements from system
|
||||
.conf files and overridden by name from both `/lib/finit/system` and
|
||||
`/etc/finit.d`, the latter is still always read last
|
||||
- The `dbus.so` plugin, which starts an external `dbus-daemon`, is now enabled
|
||||
by default. It does nothing on systems without a `dbus-daemon` installed,
|
||||
and `--disable-dbus-plugin` opts out. The daemon it used to register from C
|
||||
now lives in `20-dbus.conf`, and the directories it needs in
|
||||
`tmpfiles.d/dbus.conf`, so both can be overridden from `/etc` like any other
|
||||
system file. Those directories are no longer chowned to `messagebus`,
|
||||
matching how Finit ships directories for other daemons
|
||||
- The bundled `sulogin` and `watchdogd` are now built and installed by
|
||||
default, like keventd and the D-Bus support. `--without-sulogin` and
|
||||
`--without-watchdog` opt out. Note, Finit starts `watchdogd` by itself
|
||||
when the WDT device node exists
|
||||
- The `tty` block takes `passenv`, which the line-based format has had since
|
||||
v4.4 (issue #286) and the block format was missing
|
||||
- New `provides` setting for run/task/service/sysv blocks, naming conditions
|
||||
the service asserts in addition to its own `pid/<ident>`. Lets variants of
|
||||
one service, qualified with `if`, share the barrier condition downstream
|
||||
services wait for, which a block title alone could not express. Any
|
||||
namespace is allowed, and a second claim on the same condition is refused
|
||||
with a warning naming the owner
|
||||
- The `command` setting in a block takes a list of candidates for the same
|
||||
service, `command = { "/lib/systemd/systemd-udevd", "-udevd" }`, and Finit
|
||||
starts the first one it finds. The line-based format could only express
|
||||
this by repeating the whole stanza per candidate
|
||||
- New `pam = "NAME"` setting for run/task/service/sysv blocks, runs the
|
||||
service inside a PAM session set up from `/etc/pam.d/NAME`, so the `session`
|
||||
stack applies to the process that becomes the daemon, e.g. limits from
|
||||
`pam_limits`, which override a per-service `rlimit`. Issue #420
|
||||
- Finit now ships with a built-in brokerless D-Bus implementation, **libink**,
|
||||
exposing the running init system as a peer on its own private bus at
|
||||
`/run/finit/bus`, and -- opportunistically -- registering `org.finit` on the
|
||||
standard system bus when a `dbus-daemon` is reachable. No external
|
||||
`libdbus`/`sd-bus`/`GIO` dependency. The bus implements the stock
|
||||
`org.freedesktop.DBus`, `Peer`, `Introspectable`, and `Properties`
|
||||
interfaces. See [D-Bus Integration](dbus.md) for the full surface, build
|
||||
flag, and `dbus-send`/`dbus-monitor` examples
|
||||
- New `org.finit.Manager1` interface at `/org/finit/manager`: `ListServices`,
|
||||
`GetService`, `Start`/`Stop`/`Restart`/`Reload`, `SetRunlevel`, `SetDebug`,
|
||||
`Signal`, `Suspend`, and the `Reboot`/`Halt`/`Poweroff` triplet, which take
|
||||
a timeout argument arming the emergency shutdown bypass like `initctl -t`.
|
||||
Read-only properties `Runlevel`, `PrevRunlevel`, `Version`; signals
|
||||
`ServiceStateChanged (sss)` and `RunlevelChanged (ss)`
|
||||
- New `org.finit.Service1` interface at `/org/finit/service/<encoded>`, one
|
||||
object per loaded service, with `Start`/`Stop`/`Restart`/`Reload` for
|
||||
working off an object handle rather than passing the identity string around
|
||||
- New `org.finit.Cond1` interface at `/org/finit/cond`: `Get`, `Set`, `Clear`,
|
||||
`List`, `Dump` for [user-defined conditions](conditions.md), with a
|
||||
`ConditionChanged (ss)` signal
|
||||
- keventd serves `org.finit.Device1` on its own bus at `/run/keventd/bus`:
|
||||
`Settle`, `Trigger`, `Info`, `RulesReload`, queue-state properties, and a
|
||||
`DeviceProcessed (ss)` signal. The `udevadm` settle/trigger/info
|
||||
equivalents are thereby bus methods and `keventd -S` asks the running daemon
|
||||
first. Finit also gained a `Manager1.ConfigReloaded` signal, fired when
|
||||
`initctl reload` completes, for external condition providers and monitoring
|
||||
- Privileged D-Bus methods accept root and members of the `--with-group`
|
||||
group; everyone else is refused. On the local bus the caller's uid and
|
||||
groups come straight from the kernel (`SO_PEERCRED` + `SO_PEERGROUPS`), so
|
||||
the check never blocks PID 1 on an NSS lookup. Over the system bus the uid
|
||||
is resolved from the broker (`GetConnectionUnixUser`) and privileged methods
|
||||
are root-only. Read-only methods are open
|
||||
- `initctl` now transparently routes through D-Bus when the bus is reachable,
|
||||
with the legacy `INIT_SOCKET` transport as a fallback: `start`, `stop`,
|
||||
`restart`, `reload`, `reload <svc>`, `reboot`, `halt`, `poweroff`,
|
||||
`suspend`, `debug`, `signal`, `runlevel`, and `cond {get,set,clr}` all use
|
||||
the new path. Two new subcommands show up that have no legacy equivalent:
|
||||
|
||||
* `initctl monitor` -- streams every signal on the bus to the terminal,
|
||||
one line per delivery (`HH:MM:SS iface.member(args)`), until
|
||||
interrupted. Same idea as `dbus-monitor`, but scoped to Finit and with
|
||||
no address plumbing required.
|
||||
|
||||
* Issuing `initctl cond set/clr` over D-Bus also fires the
|
||||
`Cond1.ConditionChanged` signal, so observers see user-driven state
|
||||
changes the same way they see service-driven ones.
|
||||
|
||||
- Restart log now spells out the signal name and flags core dumps,
|
||||
e.g. `killed by SIGKILL` or `killed by SIGSEGV, core dumped`, in place of
|
||||
the bare numeric `by signal: N`. Gives operators a much stronger breadcrumb
|
||||
when a daemon dies unexpectedly
|
||||
- Service `user:` and `group:` names, including supplementary groups, can
|
||||
now be up to 63 characters, up from 15. Longer names were silently
|
||||
truncated before the lookup, so the service never started. By Anees Rehman
|
||||
- `stop:` and `reload:` scripts take a timeout of their own, `stop:5,/path`,
|
||||
defaulting to the kill delay as before. Such a line used to crash Finit at
|
||||
config load
|
||||
- Shutdown now stops after the first successful remount of `/` read only.
|
||||
The plain `mount -n -o remount,ro /`, which reads `/etc/fstab`, is only
|
||||
used when both device-agnostic forms fail, the same order as Debian's
|
||||
`umountroot`. By Anees Rehman
|
||||
|
||||
### Fixes
|
||||
|
||||
- Reject a .conf file that declares the same block title twice. The title is
|
||||
the service identity and libConfuse merges two sections sharing one, so the
|
||||
file loaded as a single service holding a mix of both declarations,
|
||||
silently. This hit `system/10-hotplug.conf`, where the two `udevd` blocks
|
||||
left only the second command, dropping the service on systems that only have
|
||||
`systemd-udevd`. The same title in another file is still how a system .conf
|
||||
is overridden
|
||||
- Remove stale daemon-owned (`pid:!`) pidfiles after unclean exits. When a
|
||||
daemon dies via SIGKILL/OOM/segfault, or exits early during startup, its
|
||||
pidfile lingers and can prevent the next instance from starting --
|
||||
`dbus-daemon` for example refuses to start when its pidfile already exists,
|
||||
so Finit's restart loop gives up. Finit now drops the file when it still
|
||||
names the just-reaped PID and that PID is no longer alive (the liveness
|
||||
check guards against PID reuse). This is a controlled exception to the
|
||||
long-standing rule that Finit does not touch service-owned pidfiles
|
||||
- Fix misspelled `SIGUNKOWN` returned by `sig_name()` for unknown signal
|
||||
numbers, now spelled correctly as `SIGUNKNOWN`. Surfaced by the new restart
|
||||
log above
|
||||
- Fix mode of existing `d`/`D` directories in tmpfiles, the chmod branch
|
||||
never ran because the directory creation swallowed `EEXIST`. Mode and owner
|
||||
of `d`/`D`, `e`, and `f`/`F` entries, and of the service directories
|
||||
`mksubsysd()` creates, are now set through an open fd and only when they
|
||||
differ, so an immutable directory like `/var/empty` no longer warns on every
|
||||
boot. By Sam Brkopac
|
||||
- Fix a lost reload for a service paused mid-reload by a condition in
|
||||
flux. A second reload arriving meanwhile re-parsed the unchanged .conf
|
||||
and cleared the pending mark, so the service resumed without ever being
|
||||
reloaded. Seen on Infix, where sshd kept its old listen addresses after
|
||||
a change that landed as two reloads in a row
|
||||
|
||||
[4.17][] - 2026-04-28
|
||||
---------------------
|
||||
|
||||
### Changes
|
||||
|
||||
- Add Plymouth boot splash plugin to manage the `plymouthd` lifecycle across boot,
|
||||
`switch_root`, and shutdown. Activated by the `splash` kernel command line
|
||||
argument. By Aaron Andersen
|
||||
- Add `tty:` option for run/task/service stanzas to acquire a controlling
|
||||
terminal. The device is opened as stdin, set as the session's controlling TTY
|
||||
via `TIOCSCTTY`, and `TERM` is set automatically — `linux` for virtual terminals
|
||||
and `vt102` for serial lines. By Ollie Gutierrez
|
||||
- Improve console output atomicity at boot and shutdown: description and status
|
||||
(`[ OK ]` / `[FAIL]`) are emitted in a single write so kernel messages cannot
|
||||
split them. If output has been scrolled away, the description is re-printed
|
||||
before the final status line. Console buffer is drained with `tcdrain(2)` and
|
||||
ANSI attributes are reset before handing control back to the kernel at
|
||||
shutdown/reboot
|
||||
|
||||
### Fixes
|
||||
|
||||
- Fix reverse-dependency condition handling on reload: when a service without
|
||||
SIGHUP support is reloaded, its condition is now cleared immediately so
|
||||
dependents transition to `STOPPING` before `SIGTERM` is sent to the parent,
|
||||
preventing them from crashing with an incremented restart counter
|
||||
- Fix `/var/tmp` mode in `tmpfiles.d/var.conf` from `0777` to `1777` (sticky bit)
|
||||
to match `/tmp`, by Aaron Andersen
|
||||
- Fix potential memory corruption in config parser: stale pointer captures of
|
||||
`PATH` and `SHELL` at startup could dangle after environment modification;
|
||||
`conf_reset_env()` now reads from the live environment instead, by Vasily Zubko
|
||||
- Fix plugin name registration: replace `__FILE__` macro with explicit string
|
||||
literals in all plugin structs and debug messages, preventing subtle build-
|
||||
system–dependent macro expansion issues, by Vasily Zubko
|
||||
|
||||
|
||||
[4.16][] - 2026-02-27
|
||||
---------------------
|
||||
|
||||
### Changes
|
||||
|
||||
- Add `initctl switch-root` command and plugin hook point. Useful for
|
||||
systems requiring early boot tasks like LUKS unlock, LVM activation,
|
||||
or network boot before mounting the real root, by Aaron Andersen
|
||||
- Set USER and LOGNAME environment variables when dropping privileges.
|
||||
Fixes issues with software like rootless Podman that determines user
|
||||
identity from environment variables, by Aaron Andersen
|
||||
- Add `remain:yes` option for run/task oneshot commands, similar to the
|
||||
systemd `RemainAfterExit=yes`, by Aaron Andersen
|
||||
- Clear service conditions on `initctl reload NAME` to ensure dependent
|
||||
services are properly updated
|
||||
- Run service `stop:` and `reload:` scripts as non-blocking processes,
|
||||
preventing Finit from stalling on long-running helper scripts
|
||||
- Guard shutdown with timer watchdog to detect and debug shutdown hangs
|
||||
- Add `~` condition prefix to propagate reload from a dependency to the
|
||||
dependent service. E.g., `<!~pid/netd>` means not only a regular
|
||||
condition, but when `netd` reloads, restart this service too. Similar
|
||||
to systemd's directive `PropagatesReloadTo=`, but declared on the
|
||||
consumer side. Issue #416
|
||||
- `tmpfiles`: add support for `-E` and `--exclude-prefix` flags
|
||||
contributed by Aaron Andersen
|
||||
|
||||
### Fixes
|
||||
- Fix #464: invalid user:group examples in cgroups.md
|
||||
- Fix #466: elogind path for Debian-based distros, by Jackie Liu
|
||||
- Fix #467: TTY services stuck in restart state after non-zero exit.
|
||||
Throttling logic introduced in v4.15 had duplicate checks causing
|
||||
infinite timer loop, and TTYs lacked default restart timeout
|
||||
- Fix #475: clear pid condition on service collection to fix stale
|
||||
deps. When a service crashes (SIGKILL), the RUNNING → HALTED path
|
||||
bypasses STOPPING where `cond_clear()` is normally called, leaving
|
||||
dependents stuck
|
||||
- Fix #476: dependents not restarted after SIGHUP reload of service in
|
||||
dependency chain. Add `service_step_all()` at end of reload cycle to
|
||||
guarantee convergence after conditions are reasserted. See also the
|
||||
new `~` condition prefix (above) to propagate reload to dependents
|
||||
- Fix #478: fix `<dev/foo>` conditions at boot, conditions that exist
|
||||
before inotify was set up. Found and fixed by Mattias Walström
|
||||
- Fix reload of SIGHUP-capable services incorrectly disrupting their
|
||||
dependents. E.g., `initctl reload syslogd` would stop dbus, dnsmasq,
|
||||
etc. even though syslogd handles SIGHUP gracefully and its PID persists
|
||||
- Only remove managed pidfiles in service cleanup. For SysV services
|
||||
with `pid:!/path`, the pidfile belongs to the service itself and Finit
|
||||
should not delete it
|
||||
- Silence spurious cgroup warnings for short-lived processes where the
|
||||
kernel reaps the child before cgroup assignment completes
|
||||
- Fix handling of already-mounted cgroups in `cgroup_init()`, can occur
|
||||
after switch_root or in container environments
|
||||
- Improve cgroups documentation clarity, grammar, and examples
|
||||
|
||||
|
||||
[4.15][] - 2026-01-01
|
||||
---------------------
|
||||
|
||||
The Finit project now has a new home page: <https://finit-project.github.io>
|
||||
|
||||
### Changes
|
||||
- Change default reboot to SOC reset from WDT reset, issue #460
|
||||
- Bump required versions of libite (v2.6.2) and libuev (v2.4.1)
|
||||
@@ -24,17 +296,43 @@ All relevant changes are documented in this file.
|
||||
descriptive names like `/system/udevd/` instead of filename derived names
|
||||
like `/system/10-hotplug/`. Syntax supports combining with other options:
|
||||
`cgroup.system,name:foo,delegate,cpu.max:10000`
|
||||
- Add support for Linux capabilities, allowing services to run with minimal
|
||||
required privileges instead of running as root. Uses the modern IAB API
|
||||
(Inheritable, Ambient, Bounding) from libcap. By Aaron Andersen
|
||||
- Add support for supplementary groups for services. Uses the syntax
|
||||
`@user:group,sup1,sup2` to explicitly specify supplementary groups, in
|
||||
addition to reading group membership from `/etc/group`. By Aaron Andersen
|
||||
- Add CPU throttled information to `initctl` output, showing when a service
|
||||
has been throttled due to reaching its CPU quota
|
||||
- Add memory field to `initctl --json` status output for cgroup-enabled
|
||||
services
|
||||
- Default to user and group `root` (UID 0) for services
|
||||
- Always check that service user and group resolve to valid UID/GID pairs,
|
||||
otherwise log error and refuse to start service
|
||||
- Hide cursor at boot and shutdown for cleaner visual experience
|
||||
- Rename `tty` services early from `init` -> `getty` even though no getty
|
||||
process has been started yet. This to aid in boot timing detection using
|
||||
tools like `bootchartd` (BusyBox version or bootchart2 project) when Finit
|
||||
only shows *"Please press Enter to activate this console."*
|
||||
- Services with `respawn` option (including TTYs) now delay retry on non-zero
|
||||
exit codes instead of immediate respawn. Prevents busy-loop when service
|
||||
fails repeatedly, which on some systems may have a crippling effect
|
||||
|
||||
### Fixes
|
||||
- Fix #453: RTC plugin fixes by Ming Liu, Atlas Copco
|
||||
- Fix #455: ANSI escape sequences logged by tools using glib logging,
|
||||
caused by use of PTY instead of pipe for stdout/stderr redirection
|
||||
- Fix #462: `/dev/pts` mounted with wrong mode (400 instead of 620), causing
|
||||
permission issues with pseudo-terminals
|
||||
- getty: fix terminal scrollback issues after login on console TTY. Mouse
|
||||
scroll wheel and Shift+PgUp/PgDn sometimes would not work properly
|
||||
- Fix flickering and artifacts in `initctl top`
|
||||
- Fix file descriptor leak in `initctl top`
|
||||
- Fix incorrect "max" limit reporting in `initctl [top|cgroup|--json]` output
|
||||
for child cgroups. Resolves effective limits by walking the cgroup hierarchy
|
||||
- Fix issue with running Finit under `bootchartd` (bootchart2 project), always
|
||||
set `PATH` and `SHELL` envs early, before attempting to mount `/proc` et al
|
||||
- Always reset ownership and permissions on TTY device nodes before launching getty
|
||||
- Ensure mount/unmount skips `noauto` entries
|
||||
|
||||
|
||||
@@ -1885,7 +2183,9 @@ Major bug fix release.
|
||||
|
||||
* Initial release
|
||||
|
||||
[UNRELEASED]: https://github.com/finit-project/finit/compare/4.14...HEAD
|
||||
[UNRELEASED]: https://github.com/finit-project/finit/compare/4.17...HEAD
|
||||
[4.17]: https://github.com/finit-project/finit/compare/4.16...4.17
|
||||
[4.16]: https://github.com/finit-project/finit/compare/4.15...4.16
|
||||
[4.15]: https://github.com/finit-project/finit/compare/4.14...4.15
|
||||
[4.14]: https://github.com/finit-project/finit/compare/4.13...4.14
|
||||
[4.13]: https://github.com/troglobit/finit/compare/4.12...4.13
|
||||
|
||||
@@ -3,6 +3,7 @@ EXTRA_DIST = AUTHORS ChangeLog.md
|
||||
|
||||
docsdir := @docdir@/doc
|
||||
dist_docs_DATA = build.md cmdline.md commands.md conditions.md \
|
||||
dbus.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 \
|
||||
|
||||
+118
-8
@@ -2,10 +2,23 @@ Building Finit
|
||||
==============
|
||||
|
||||
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 three external libraries:
|
||||
|
||||
- [libuEv][], the event loop
|
||||
- [libite][] (-lite), much needed frog DNA
|
||||
- [libConfuse][], the parser behind the .conf format
|
||||
|
||||
The bundled device manager, keventd, needs a fourth: libblkid from
|
||||
[util-linux][]. It reads the filesystem UUID and label off block
|
||||
devices, which is what the curated rules name the `/dev/disk/by-uuid/`
|
||||
and `/dev/disk/by-label/` symlinks after. keventd is enabled by
|
||||
default, so this is a hard requirement unless you build with
|
||||
`--without-keventd`.
|
||||
|
||||
PAM session support for services is built by default. It needs
|
||||
[Linux-PAM][] (-lpam); the build falls back to no PAM support when that
|
||||
library is missing. A static build, `--enable-static`, disables PAM
|
||||
too, since libpam loads its modules with `dlopen()`.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Most free/open source software packages that use `configure` default
|
||||
@@ -22,6 +35,8 @@ version of the above mentioned libraries. Currently required versions:
|
||||
|
||||
- libite v2.2.0, or later
|
||||
- libuEv v2.2.0, or later
|
||||
- libConfuse v3.3, or later
|
||||
- libblkid, any version, when keventd is enabled
|
||||
|
||||
|
||||
Configure
|
||||
@@ -44,21 +59,56 @@ Below are a few of the main switches to configure:
|
||||
built-ins (.o files) and all external libraries, except the C library
|
||||
will be linked statically.
|
||||
|
||||
* `--disable-pam`: Opt out of Finit's built-in PAM session support,
|
||||
enabled by default, which lets a service declare `pam = "name"` and
|
||||
run inside a session set up from `/etc/pam.d/name`. Needs libpam,
|
||||
falls back to disabled when it is missing, and is also disabled for
|
||||
`--enable-static` builds. Asking for `--enable-pam` and
|
||||
`--enable-static` together is an error rather than a fallback. See
|
||||
[PAM Sessions](config/pam.md)
|
||||
|
||||
* `--enable-kernel-cmdline`: Enable Finit pre-4.1 parsing of init args from
|
||||
`/proc/cmdline`, this is *not recommended* since Finit may be running as the
|
||||
init for container apps that can see the host's `/proc` filesystem
|
||||
|
||||
* `--disable-dbus`: Opt out of Finit's built-in D-Bus support, enabled by
|
||||
default. See [D-Bus Integration](dbus.md) for what it provides. Not to
|
||||
be confused with `--disable-dbus-plugin` below, which only governs
|
||||
starting an external `dbus-daemon`
|
||||
|
||||
* `--enable-alsa-utils-plugin`: Enable the optional `alsa-utils.so` sound plugin.
|
||||
|
||||
* `--enable-dbus-plugin`: Enable the optional D-Bus `dbus.so` plugin.
|
||||
* `--disable-dbus-plugin`: Drop the `dbus.so` plugin, which launches
|
||||
`dbus-daemon` at boot. Enabled by default; the plugin does nothing on
|
||||
a system that has no `dbus-daemon` installed, so opting out is only
|
||||
needed to keep init from starting a bus on a system that has one.
|
||||
Unrelated to the built-in bus, see `--disable-dbus` above.
|
||||
|
||||
* `--enable-resolvconf-plugin`: Enable the `resolvconf.so` optional 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.
|
||||
* `--without-keventd`: Drop the bundled device manager, for systems that
|
||||
run mdev, mdevd, or udevd instead. Enabled by default, and the only
|
||||
thing that pulls in libblkid. See [Bundled Device Manager](keventd.md).
|
||||
|
||||
* `--without-sulogin`: Drop the bundled `sulogin`, enabled by default,
|
||||
and use the system `sulogin(8)` instead. The one shipped with Finit
|
||||
*allows password-less* login if the `root` user is disabled or has no
|
||||
password at all. `--with-sulogin=USER` prompts for another user's
|
||||
password than `root`'s.
|
||||
|
||||
* `--without-watchdog`: Drop the bundled `watchdogd`, enabled by default
|
||||
on `/dev/watchdog`, `--with-watchdog=DEV` selects another device.
|
||||
Finit starts it when the device node exists, see [Watchdog](watchdog.md).
|
||||
|
||||
* `--with-libsystemd`: Build the replacement `libsystemd`, which lets
|
||||
programs that use `sd_notify()` talk to Finit without systemd. Off by
|
||||
default because it installs `libsystemd.so.0` in `$libdir`: on a host
|
||||
that has the real one, ours shadows it in the loader cache and every
|
||||
program linking it, `dbus-daemon` and `udevd` included, loses the
|
||||
symbols it needs. Safe on a systemd-free system, which is the point
|
||||
of it.
|
||||
|
||||
For more configure flags, see <kbd>./configure --help</kbd>
|
||||
|
||||
@@ -85,8 +135,7 @@ Then configure, build and install:
|
||||
|
||||
```shell
|
||||
$ ./configure --prefix=/usr --exec-prefix= \
|
||||
--sysconfdir=/etc --localstatedir=/var \
|
||||
--with-keventd --with-watchdog
|
||||
--sysconfdir=/etc --localstatedir=/var
|
||||
$ make
|
||||
.
|
||||
.
|
||||
@@ -114,6 +163,60 @@ Linux config to:
|
||||
> `/etc/fstab`.
|
||||
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
`make check` runs the test suite in a private namespace, so it is safe
|
||||
on a running system. It needs `unshare` and, on Ubuntu, unprivileged
|
||||
user namespaces enabled:
|
||||
|
||||
```shell
|
||||
sudo sysctl kernel.apparmor_restrict_unprivileged_userns=0
|
||||
make check
|
||||
```
|
||||
|
||||
The D-Bus message parser is the only place in Finit where bytes off a
|
||||
socket become pointers, so it also has a fuzz target. `make check`
|
||||
runs it as a fixed sweep, which takes milliseconds and needs nothing
|
||||
beyond the normal build. To fuzz it properly, build it with clang and
|
||||
libFuzzer:
|
||||
|
||||
```shell
|
||||
clang -fsanitize=fuzzer,address -DLINK_FUZZ_LIBFUZZER -D_GNU_SOURCE \
|
||||
-I libink -I . -o fuzz-msg-parse \
|
||||
test/src/fuzz-msg-parse.c libink/*.c
|
||||
mkdir -p .fuzz-corpus
|
||||
./fuzz-msg-parse .fuzz-corpus -max_total_time=300
|
||||
```
|
||||
|
||||
Give it a corpus directory as above and it saves what it learns there,
|
||||
so the next run picks up where this one left off instead of starting
|
||||
cold. Nothing writes to it unless you name it: without the argument
|
||||
libFuzzer keeps everything in memory and the run leaves only crashes
|
||||
behind. `make distclean` clears the corpus and the target.
|
||||
|
||||
Once a corpus has grown, most of it reaches code some earlier input
|
||||
already reached. Minimise it:
|
||||
|
||||
```shell
|
||||
./fuzz-msg-parse -merge=1 .fuzz-corpus-min .fuzz-corpus
|
||||
rm -rf .fuzz-corpus && mv .fuzz-corpus-min .fuzz-corpus
|
||||
```
|
||||
|
||||
Run `./configure` first, the target needs the generated `config.h`.
|
||||
If the link fails with `cannot find -lstdc++`, install the `libstdc++`
|
||||
headers matching the newest GCC on the system, not the default one:
|
||||
clang picks the newest tree it finds, and that is the one that needs
|
||||
them. CI runs this target on every pull request, carrying its
|
||||
corpus between runs so it reaches deeper over time.
|
||||
|
||||
Feed a file back to the target to reproduce a find:
|
||||
|
||||
```shell
|
||||
./fuzz-msg-parse crash-3f2a...
|
||||
```
|
||||
|
||||
|
||||
Running
|
||||
-------
|
||||
|
||||
@@ -171,7 +274,11 @@ Notice the `--` separator.
|
||||
To debug startup issues, in particular issues with getty/login, add
|
||||
the following to your Finit .conf file:
|
||||
|
||||
tty [12345789] notty noclear
|
||||
tty board {
|
||||
runlevel = "12345789"
|
||||
notty = true
|
||||
noclear = true
|
||||
}
|
||||
|
||||
The `notty` option ensures reusing the stdin/stdout set up by the
|
||||
kernel. Remember, this is only for debugging and would leave your
|
||||
@@ -189,3 +296,6 @@ it only for debugging start up issues when Finit crashes.
|
||||
[1]: https://github.com/finit-project/finit/releases/download/4.3/finit-4.3.tar.gz
|
||||
[libuEv]: https://github.com/troglobit/libuev
|
||||
[libite]: https://github.com/troglobit/libite
|
||||
[libConfuse]: https://github.com/libconfuse/libconfuse
|
||||
[util-linux]: https://github.com/util-linux/util-linux
|
||||
[Linux-PAM]: https://github.com/linux-pam/linux-pam
|
||||
|
||||
+4
-3
@@ -41,7 +41,7 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
|
||||
|
||||
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
|
||||
setting `rcsd = "/path/to/finit.d"` to override the default rcS.d
|
||||
directory.
|
||||
|
||||
* `finit.debug[=bool]`: Enable finit debug. This is operated
|
||||
@@ -104,8 +104,9 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
|
||||
* `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.
|
||||
and TTYs in runlevel 1 will be started, so a `tty` block with
|
||||
`runlevel = "1"`, `device = "@console"`, and `nologin = true`
|
||||
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
|
||||
|
||||
+124
-37
@@ -7,18 +7,26 @@ mechanism for common synchronization problems. For example:
|
||||
- *"wait for service A to start before starting service B"*, or
|
||||
- *"wait for basic network access to be available"*
|
||||
|
||||
Conditions are similar in syntax to declaring runlevels per service.
|
||||
They are specified within angle brackets `<>` and can be applied to any
|
||||
of the `service`, `task`, or `run` stanza. Multiple conditions may be
|
||||
specified separated by comma. Multiple conditions are logically AND'ed
|
||||
A condition is named in the `conditions` list of a `service`, `task`, or
|
||||
`run` block. The list may hold several, and they are logically AND'ed
|
||||
during evaluation, i.e. all conditions must be satisfied in order for a
|
||||
service to run.
|
||||
service to run. In running text, and in `initctl` output, a condition
|
||||
is written inside angle brackets, `<pid/syslogd>`.
|
||||
|
||||
A special syntax, using a leading `!` in run/task/service conditions,
|
||||
denote if a:
|
||||
One prefix can be used on a condition:
|
||||
|
||||
- service does not support `SIGHUP`
|
||||
- run/task should not block runlevel changes (i.e., bootstrap)
|
||||
- `~` -- propagate reload from this dependency, see below
|
||||
|
||||
The line-based format also accepts a leading `!` on the list, which is
|
||||
not a condition and not a negation. It is a flag on the block, and it
|
||||
means two unrelated things depending on where it sits: a service does
|
||||
not support `SIGHUP` (noreload), or a run/task should not block
|
||||
runlevel changes, i.e. bootstrap. Each of those is its own key here:
|
||||
|
||||
| Line-based | Block format |
|
||||
|---|---|
|
||||
| `<!...>` on a service or sysv | `reload-signal = "none"` |
|
||||
| `<!...>` on a run or task | `required = false` |
|
||||
|
||||
Finit guarantees by default that all run/tasks run (at least) once
|
||||
per runlevel. For most tasks this is a good default, for example
|
||||
@@ -27,7 +35,12 @@ that are unlikely to happen it is not. (See example below.)
|
||||
|
||||
### Example
|
||||
|
||||
service [2345] <pid/setupd,pid/zebra> /sbin/netd -- Network monitor
|
||||
service netd {
|
||||
description = "Network monitor"
|
||||
runlevel = "2345"
|
||||
conditions = { "pid/setupd", "pid/zebra" }
|
||||
command = "/sbin/netd"
|
||||
}
|
||||
|
||||
In this example the Network monitor daemon `netd` is not started until
|
||||
both the `pid/setupd` *and* `pid/zebra` conditions are satisfied. A
|
||||
@@ -42,15 +55,62 @@ being created, i.e., the service's default readiness notification.
|
||||
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
|
||||
service dropbear {
|
||||
description = "Dropbear SSH daemon"
|
||||
runlevel = "2345789"
|
||||
reload-signal = "none"
|
||||
envfile = "-/etc/default/dropbear"
|
||||
command = "dropbear -F -R $DROPBEAR_ARGS"
|
||||
}
|
||||
|
||||
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 `<!>`:
|
||||
moving to the next runlevel after bootstrap, so we set
|
||||
`required = false`:
|
||||
|
||||
task [S0123456789] <!sys/pwr/fail> name:pwrfail initctl poweroff -- Power failure, shutting down
|
||||
task pwrfail {
|
||||
description = "Power failure, shutting down"
|
||||
runlevel = "S0123456789"
|
||||
conditions = { "sys/pwr/fail" }
|
||||
required = false
|
||||
command = "initctl poweroff"
|
||||
}
|
||||
|
||||
|
||||
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 svc_b {
|
||||
description = "Needs A (barrier)"
|
||||
conditions = { "pid/svc_a" }
|
||||
command = "/sbin/svc_b"
|
||||
}
|
||||
|
||||
service svc_c {
|
||||
description = "Propagate reload from B"
|
||||
conditions = { "~pid/svc_b" }
|
||||
reload-signal = "none"
|
||||
command = "/sbin/svc_c"
|
||||
}
|
||||
|
||||
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
|
||||
`reload-signal = "none"`, instead of merely resumed. If `svc_c`
|
||||
supported `SIGHUP`, 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
|
||||
@@ -79,7 +139,12 @@ services, or run/task jobs, on external site-dependent stimuli.
|
||||
|
||||
**Example:**
|
||||
|
||||
service [2345] <usr/foo> alarm --arg foo -- Foo alarm
|
||||
service alarm {
|
||||
description = "Foo alarm"
|
||||
runlevel = "2345"
|
||||
conditions = { "usr/foo" }
|
||||
command = "alarm --arg foo"
|
||||
}
|
||||
|
||||
For convenience, prefixing with `usr/` is allowed, but any other slashes
|
||||
or period characters are disallowed. E.g., to trigger the `Foo alarm`,
|
||||
@@ -102,8 +167,9 @@ Static (one-shot) conditions, like `usr/`, never enter the `flux` state.
|
||||
> "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`.
|
||||
> by Finit when they instead exit on the signal. For such services,
|
||||
> set `reload-signal = "none"` to tell Finit the service does not
|
||||
> support `SIGHUP`.
|
||||
|
||||
|
||||
Built-in Conditions
|
||||
@@ -111,25 +177,35 @@ Built-in Conditions
|
||||
|
||||
Finit comes with a set of plugins for conditions:
|
||||
|
||||
- `devmon` (built-in)
|
||||
- `netlink`
|
||||
- `pidfile`
|
||||
- `keventd`: provides `<dev/...>`, `<class/...>`, `<driver/...>`, and
|
||||
`<sys/pwr/...>`
|
||||
- `devmon` (built-in fallback for `<dev/...>` without keventd)
|
||||
- `netlink`: provides `<net/...>`
|
||||
- `pidfile`: provides `<pid/...>`
|
||||
- `sys`
|
||||
- `usr`
|
||||
|
||||
The `devmon` (built-in) plugin monitors `/dev` and `/dev/dir` for device
|
||||
nodes being created and removed. It is active only when a run, task, or
|
||||
service has declared a `<dev/foo>` or `<dev/dir/bar>` condition.
|
||||
The `dev/` conditions are provided by `keventd`, the built-in device
|
||||
manager. When keventd creates a device node in `/dev`, it also asserts
|
||||
the corresponding `dev/` condition. When a device is removed, the
|
||||
condition is cleared. If keventd is not in use (an external device
|
||||
manager like udevd is used instead), the `devmon` built-in provides the
|
||||
same conditions by monitoring `/dev` and `/dev/dir` with inotify.
|
||||
|
||||
The `pidfile` plugin (recursively) watches `/run/` (recursively) for PID
|
||||
files created by the monitored services, and sets a corresponding
|
||||
condition in the `pid/` namespace.
|
||||
keventd also asserts `class/<subsystem>/<name>` for devices that have
|
||||
no `/dev` node, e.g. LEDs and DSA switch ports, and `driver/<name>`
|
||||
while a driver is bound to at least one device. See
|
||||
[keventd](keventd.md) for details.
|
||||
|
||||
The `pidfile` plugin recursively watches `/run/` 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 `sys` and `usr` plugins 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.
|
||||
|
||||
@@ -164,6 +240,8 @@ Built-in conditions:
|
||||
- `usr/foo`
|
||||
- `boot/arg`
|
||||
- `dev/node` and `dev/dir/node`
|
||||
- `class/<subsystem>/<name>`
|
||||
- `driver/<name>`
|
||||
|
||||
> [!NOTE]
|
||||
> Here, `up` means administratively up, the interface flag `IFF_UP`.
|
||||
@@ -175,16 +253,16 @@ Composition
|
||||
-----------
|
||||
|
||||
The `pid/` conditions are generated by the Finit `pidfile.so` plugin and
|
||||
composed from a service's `name:` and `:id`. By default the basename of
|
||||
the daemon and the empty string.
|
||||
composed from a service's block title and its `:id`. By default the
|
||||
basename of the daemon and the empty string.
|
||||
|
||||
| **service** | **condition** |
|
||||
|----------------------------------------------------|------------------|
|
||||
| /sbin/foo | pid/foo |
|
||||
| /sbin/bar -p /run/baz.pid | pid/bar |
|
||||
| name:lxc :foo lxc-start -n foo -p /run/lxc/foo.pid | pid/lxc:foo |
|
||||
| /usr/bin/dbus-daemon | pid/dbus-daemon |
|
||||
| :222 dropbear -p 222 | pid/dropbear:222 |
|
||||
| **service** | **condition** |
|
||||
|-------------------------------------------------------------------|------------------|
|
||||
| `service { command = "/sbin/foo" }` | pid/foo |
|
||||
| `service { command = "/sbin/bar -p /run/baz.pid" }` | pid/bar |
|
||||
| `service lxc:foo { command = "lxc-start -n foo -p /run/lxc/foo.pid" }` | pid/lxc:foo |
|
||||
| `service { command = "/usr/bin/dbus-daemon" }` | pid/dbus-daemon |
|
||||
| `service dropbear:222 { command = "dropbear -p 222" }` | pid/dropbear:222 |
|
||||
|
||||
The condition is asserted when `pidfile.so` receives an inotify event
|
||||
for a file matching `/run/*.pid`, `/run/**/*.pid`, or `/run/**/pid`,
|
||||
@@ -194,9 +272,13 @@ When Finit configuration files are changed and the `initctl reload`
|
||||
command is called, it is expected of services to touch their PID files
|
||||
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,
|
||||
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
|
||||
can be worked around by setting `pidfile` and `pidfile-create` in the
|
||||
service block for the daemon. It is far from optimal since any
|
||||
synchronization of depending services may fail due to the daemon not
|
||||
having reinitialized/created their IPC sockets, or similar.
|
||||
|
||||
@@ -277,6 +359,11 @@ This STOP/CONT handling minimizes the number of unnecessary service
|
||||
restarts that would otherwise occur because a depending service was sent
|
||||
`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 if it has
|
||||
`reload-signal = "none"`, instead of simply being resumed.
|
||||
|
||||
Therefore, any plugin that supplies Finit with conditions must ensure
|
||||
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
|
||||
|
||||
+58
-30
@@ -16,14 +16,17 @@ 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:
|
||||
Capabilities are specified with the `capabilities` key, alias `caps`:
|
||||
|
||||
```conf
|
||||
service [2345] name:nginx \
|
||||
@www-data:www-data \
|
||||
caps:^cap_net_bind_service \
|
||||
/usr/sbin/nginx -g 'daemon off;' \
|
||||
-- Web server
|
||||
service nginx {
|
||||
description = "Web server"
|
||||
runlevel = "2345"
|
||||
user = "www-data"
|
||||
group = "www-data"
|
||||
capabilities = { "^cap_net_bind_service" }
|
||||
command = "/usr/sbin/nginx -g 'daemon off;'"
|
||||
}
|
||||
```
|
||||
|
||||
This example allows nginx to bind to privileged ports (like 80 and 443) while
|
||||
@@ -52,7 +55,7 @@ with the following prefixes:
|
||||
Multiple capabilities can be specified as a comma-separated list:
|
||||
|
||||
```conf
|
||||
caps:^cap_net_raw,^cap_net_admin,^cap_net_bind_service
|
||||
capabilities = { "^cap_net_raw", "^cap_net_admin", "^cap_net_bind_service" }
|
||||
```
|
||||
|
||||
## Common Use Cases
|
||||
@@ -62,10 +65,13 @@ caps:^cap_net_raw,^cap_net_admin,^cap_net_bind_service
|
||||
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;'
|
||||
service webserver {
|
||||
runlevel = "2345"
|
||||
user = "www-data"
|
||||
group = "www-data"
|
||||
capabilities = { "^cap_net_bind_service" }
|
||||
command = "/usr/sbin/nginx -g 'daemon off;'"
|
||||
}
|
||||
```
|
||||
|
||||
### Network Monitoring (Raw Sockets)
|
||||
@@ -73,10 +79,12 @@ service [2345] name:webserver \
|
||||
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
|
||||
service tcpdump {
|
||||
runlevel = "2345"
|
||||
user = "tcpdump"
|
||||
capabilities = { "^cap_net_raw", "^cap_net_admin" }
|
||||
command = "/usr/sbin/tcpdump -i eth0 -w /var/log/capture.pcap"
|
||||
}
|
||||
```
|
||||
|
||||
### NTP Daemon (System Time)
|
||||
@@ -84,10 +92,12 @@ service [2345] name:tcpdump \
|
||||
Allow time synchronization without full root:
|
||||
|
||||
```conf
|
||||
service [2345] name:ntpd \
|
||||
@ntp \
|
||||
caps:^cap_sys_time,^cap_sys_nice \
|
||||
/usr/sbin/ntpd -n
|
||||
service ntpd {
|
||||
runlevel = "2345"
|
||||
user = "ntp"
|
||||
capabilities = { "^cap_sys_time", "^cap_sys_nice" }
|
||||
command = "/usr/sbin/ntpd -n"
|
||||
}
|
||||
```
|
||||
|
||||
## Available Capabilities
|
||||
@@ -115,9 +125,10 @@ Common capabilities include (see `man 7 capabilities` for the complete list):
|
||||
- Only grant what the service actually needs
|
||||
- Don't grant `cap_sys_admin` unless absolutely necessary
|
||||
|
||||
2. **Always specify a user**
|
||||
- Always use `@user` to drop to a non-root user
|
||||
- Capabilities work best when combined with user separation
|
||||
2. **Specify a user (preferably non-root)**
|
||||
- The `user` setting is **required** for `capabilities` to take effect
|
||||
- For ambient capabilities (`^`), use a non-root user (not `"root"`)
|
||||
- Example: `user = "www-data"`, `user = "nginx"`, `user = "tcpdump"`
|
||||
|
||||
3. **Use ambient capabilities (`^`)**
|
||||
- The `^` prefix ensures capabilities survive exec()
|
||||
@@ -158,19 +169,36 @@ ps -o user,pid,cmd -p $(pidof nginx)
|
||||
|
||||
- Linux kernel 4.3+ (for ambient capabilities support)
|
||||
- libcap library installed
|
||||
- Finit built with `--enable-libcap`
|
||||
- Finit built with `--enable-libcap`, otherwise a `capabilities` list is
|
||||
ignored, with a warning
|
||||
|
||||
## Limitations
|
||||
|
||||
- Capabilities are only applied when both `@user` and `caps:` are specified
|
||||
- The service must drop to a non-root user for capabilities to be effective
|
||||
- `capabilities` requires `user` to be set for it to take effect
|
||||
- Without `user`, the service runs as root with full capabilities and
|
||||
the `capabilities` list is silently ignored
|
||||
- You can use `user = "root"`, but see below about ambient capabilities
|
||||
- For ambient capabilities (`^`, recommended), the user **must be non-root**
|
||||
- Using `user = "root"` with `^` capabilities will not work effectively, as ambient
|
||||
capabilities are only added to the effective set when euid ≠ 0
|
||||
- Use inheritable (`%`) or bounding (`!`) capabilities with `user = "root"` if needed
|
||||
- Finit warns about this when reading the .conf file:
|
||||
|
||||
nginx: ambient capabilities ('^') have no effect as root, use a
|
||||
non-root user, or '%' and '!' entries
|
||||
- Services without `capabilities` use standard privilege dropping:
|
||||
- Services with a non-root `user` have no special capabilities
|
||||
- Services without `user` run as root with full capabilities
|
||||
- A capability granted by `pam_cap.so` in a [PAM session](pam.md) is
|
||||
merged into this set, but only when `capabilities` is also set.
|
||||
Without it the grant is lost when privileges drop
|
||||
- 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
|
||||
|
||||
- `man 7 capabilities` - Linux capabilities overview
|
||||
- `man 3 cap_iab` - IAB capability API documentation
|
||||
- `man 8 setcap` - Set file capabilities
|
||||
- `man 8 getcap` - Query file capabilities
|
||||
- `man 1 capsh` - Capability shell wrapper
|
||||
- [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
|
||||
|
||||
+142
-67
@@ -1,72 +1,94 @@
|
||||
There are three major cgroup configuration directives:
|
||||
Finit has two `cgroup` blocks for controlling resource allocation:
|
||||
|
||||
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
|
||||
1. **Top-level definition**, at file scope: declares a group such as
|
||||
`init`, `system`, or `user`, and its default settings.
|
||||
|
||||
cgroup system { cpu.weight = 9700 }
|
||||
|
||||
2. **Joining a group**, inside a service block: names the group this
|
||||
service runs in, and may override settings for itself alone.
|
||||
|
||||
service foo {
|
||||
cgroup maint { memory.max = 1G }
|
||||
command = "/path/to/cmd"
|
||||
}
|
||||
|
||||
> [!NOTE]
|
||||
> 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 covers this well:
|
||||
> <https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html>
|
||||
|
||||
Top-level Group Configuration
|
||||
-----------------------------
|
||||
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
|
||||
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
|
||||
cgroup system { cpu.weight = 9700 }
|
||||
|
||||
# Example extra cgroup 'maint'
|
||||
cgroup maint cpu.weight:100
|
||||
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.
|
||||
`init/` cgroup is reserved for the early boot helpers Finit drives
|
||||
itself, like udev and mdev. PID 1 runs in the root cgroup, since a
|
||||
cgroup holding processes cannot delegate controllers to its children.
|
||||
The `user/` cgroup is for local TTY logins spawned by getty.
|
||||
|
||||
Selecting Cgroups
|
||||
------------------
|
||||
Joining a Cgroup
|
||||
----------------
|
||||
|
||||
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:
|
||||
**Syntax:** `cgroup NAME { settings }` (inside a service block)
|
||||
|
||||
cgroup.maint
|
||||
service [...] <...> /path/to/foo args -- description
|
||||
service [...] <...> /path/to/bar args -- description
|
||||
Every block says which group it joins, by name. An empty block joins
|
||||
without changing anything:
|
||||
|
||||
or
|
||||
service foo {
|
||||
cgroup maint {}
|
||||
command = "/path/to/foo args"
|
||||
}
|
||||
|
||||
service [...] <...> cgroup.maint /path/to/foo args -- description
|
||||
service bar {
|
||||
cgroup maint {}
|
||||
command = "/path/to/bar args"
|
||||
}
|
||||
|
||||
The latter form also allows per-stanza limits. Two syntaxes are supported:
|
||||
Both services run in the `maint/` cgroup. Settings inside the block
|
||||
apply to that service alone:
|
||||
|
||||
**New comma-separated syntax (recommended):**
|
||||
service foo {
|
||||
cgroup maint {
|
||||
cpu.max = 10000
|
||||
memory.max = 655360
|
||||
}
|
||||
command = "/path/to/foo args"
|
||||
}
|
||||
|
||||
service [...] <...> cgroup.maint,cpu.max:10000,mem.max:655360 /path/to/foo args -- description
|
||||
> [!NOTE]
|
||||
> The legacy format has a standalone `cgroup.NAME` line that selects a
|
||||
> group for every stanza following it in the file, and a `cgroup:options`
|
||||
> form that applies settings to whichever group is current without
|
||||
> naming it. Neither has an equivalent here, by design: a block that
|
||||
> joins a group says so itself, so the group cannot depend on what came
|
||||
> earlier in the file.
|
||||
|
||||
**Old colon-separated syntax (legacy):**
|
||||
|
||||
service [...] <...> cgroup.maint: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.
|
||||
Every cgroup setting maps directly to cgroup v2 syntax, so `cpu.max`
|
||||
maps to the file `/sys/fs/cgroup/maint/foo/cpu.max`. There is no
|
||||
filtering, the one exception being the shorthand `mem.`, which expands
|
||||
to `memory.`. If the file is not available, either the controller is
|
||||
missing from your Linux kernel, or the name is misspelled.
|
||||
|
||||
### Overriding Cgroup Leaf Names
|
||||
|
||||
@@ -75,40 +97,66 @@ 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:
|
||||
To use a more descriptive name (recommended for clarity), set `name`
|
||||
inside the cgroup block:
|
||||
|
||||
service [...] <...> cgroup.system,name:udevd /lib/systemd/systemd-udevd -- Device event daemon
|
||||
service udevd {
|
||||
description = "Device event daemon"
|
||||
cgroup system { name = "udevd" }
|
||||
command = "/lib/systemd/systemd-udevd"
|
||||
}
|
||||
|
||||
This creates the cgroup at `/sys/fs/cgroup/system/udevd/` instead.
|
||||
|
||||
The syntax supports combining the name override with other options:
|
||||
`name` combines with any other setting:
|
||||
|
||||
service [...] <...> cgroup.system,name:udevd,cpu.max:10000 /lib/systemd/systemd-udevd -- Device event daemon
|
||||
service udevd {
|
||||
description = "Device event daemon"
|
||||
cgroup system {
|
||||
name = "udevd"
|
||||
cpu.max = 10000
|
||||
}
|
||||
command = "/lib/systemd/systemd-udevd"
|
||||
}
|
||||
|
||||
Or with delegation:
|
||||
|
||||
service [2345] user:podman group:podman \
|
||||
cgroup.containers,name:podman,delegate,mem.max:4G \
|
||||
/usr/bin/podman system service -- Podman API
|
||||
service podman {
|
||||
description = "Podman API"
|
||||
runlevel = "2345"
|
||||
user = "podman"
|
||||
group = "podman"
|
||||
cgroup containers {
|
||||
name = "podman"
|
||||
delegate = true
|
||||
memory.max = 4G
|
||||
}
|
||||
command = "/usr/bin/podman system service"
|
||||
}
|
||||
|
||||
A daemon using `SCHED_RR` currently need to run outside the default cgroups.
|
||||
A daemon using `SCHED_RR` currently needs to run outside the default
|
||||
cgroups.
|
||||
|
||||
service [...] <...> cgroup.root /path/to/daemon arg -- Real-Time process
|
||||
service rt {
|
||||
description = "Real-Time process"
|
||||
cgroup root {}
|
||||
command = "/path/to/daemon arg"
|
||||
}
|
||||
|
||||
Cgroup Delegation
|
||||
-----------------
|
||||
|
||||
For services that need to create their own child cgroups (container runtimes
|
||||
like Docker, Podman, systemd-nspawn, LXC), use the `delegate` option:
|
||||
like Docker, Podman, systemd-nspawn, LXC), set `delegate`:
|
||||
|
||||
service [2345] user:dockerd group:dockerd \
|
||||
cgroup.system,delegate /usr/bin/dockerd -- Docker daemon
|
||||
|
||||
Or with the old colon syntax:
|
||||
|
||||
service [2345] user:dockerd group:dockerd \
|
||||
cgroup.system:delegate /usr/bin/dockerd -- Docker daemon
|
||||
service dockerd {
|
||||
description = "Docker daemon"
|
||||
runlevel = "2345"
|
||||
user = "dockerd"
|
||||
group = "dockerd"
|
||||
cgroup system { delegate = true }
|
||||
command = "/usr/bin/dockerd"
|
||||
}
|
||||
|
||||
This allows the container runtime to:
|
||||
|
||||
@@ -126,22 +174,49 @@ When delegation is enabled, Finit:
|
||||
|
||||
**Requirements:**
|
||||
|
||||
- The service should specify `user:` and `group:` for proper ownership
|
||||
- The service should specify `user` and `group` for proper ownership
|
||||
- Controllers are delegated from the parent cgroup
|
||||
|
||||
**Example with additional config (new syntax):**
|
||||
**Example with additional config:**
|
||||
|
||||
service [2345] user:podman group:podman \
|
||||
cgroup.containers,delegate,mem.max:4G \
|
||||
/usr/bin/podman system service -- Podman API
|
||||
service podman {
|
||||
description = "Podman API"
|
||||
runlevel = "2345"
|
||||
user = "podman"
|
||||
group = "podman"
|
||||
cgroup containers {
|
||||
delegate = true
|
||||
memory.max = 4G
|
||||
}
|
||||
command = "/usr/bin/podman system service"
|
||||
}
|
||||
|
||||
**Or with old syntax:**
|
||||
This delegates the cgroup while also setting a 4GB memory limit.
|
||||
|
||||
service [2345] user:podman group:podman \
|
||||
cgroup.containers:delegate,mem.max:4G \
|
||||
/usr/bin/podman system service -- Podman API
|
||||
**Container template example:**
|
||||
|
||||
Both examples delegate the cgroup while also setting a 4GB memory limit.
|
||||
Here's a real-world example from [Infix OS](https://github.com/kernelkit/infix)
|
||||
for running rootful podman container instances using delegation:
|
||||
|
||||
sysv container:%i {
|
||||
description = "container %i"
|
||||
runlevel = "2345"
|
||||
reload-signal = "none"
|
||||
pidfile = "/run/container:%i.pid"
|
||||
stop-timeout = 30
|
||||
log { priority = "local1" identity = "%i" }
|
||||
|
||||
exec-start-pre = "/usr/sbin/container"
|
||||
exec-start-pre-timeout = 0
|
||||
exec-cleanup = "/usr/sbin/container"
|
||||
exec-cleanup-timeout = 0
|
||||
|
||||
cgroup system { delegate = true }
|
||||
command = "container -n %i"
|
||||
}
|
||||
|
||||
This template uses `sysv` type with delegation, demonstrating that cgroup
|
||||
delegation works with different service types, not just `service`.
|
||||
|
||||
**Cgroup structure with delegation:**
|
||||
|
||||
@@ -154,7 +229,7 @@ Initially, the service process runs directly in the cgroup root:
|
||||
|
||||
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
|
||||
it automatically creates a `supervisor/` subdirectory and moves service-related
|
||||
processes there:
|
||||
|
||||
/sys/fs/cgroup/system/container@web/
|
||||
|
||||
+7
-6
@@ -6,15 +6,16 @@ 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:
|
||||
Global environment variables go in an `environment` block, `env` for
|
||||
short:
|
||||
|
||||
set foo=bar
|
||||
set baz="qux"
|
||||
environment {
|
||||
foo = "bar"
|
||||
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`
|
||||
so if `foo` 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.
|
||||
|
||||
+26
-22
@@ -24,8 +24,8 @@ the following layout is recommended:
|
||||
| `- ...
|
||||
`- run/
|
||||
`- finit/
|
||||
|- bus # Finit's own D-Bus socket, see doc/dbus.md
|
||||
`- system/
|
||||
|- dbus.conf
|
||||
|- keventd.conf
|
||||
|- runparts.conf
|
||||
|- watchdogd.conf
|
||||
@@ -35,18 +35,21 @@ 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 `/run/finit/system/*.conf` are generated by Finit for its
|
||||
built-in services: runparts, [watchdog](../watchdog.md), and
|
||||
[`keventd`](../keventd.md), if they are enabled. They are read before
|
||||
the other .conf directories, so any later file can reference them in
|
||||
`if:` statements and override them by name.
|
||||
|
||||
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 hard-coded services provided by plugins before.
|
||||
|
||||
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/`.
|
||||
All .conf files in both directories can be either replaced by a system
|
||||
administrator or overridden by a file with the same name in
|
||||
`/etc/finit.d/`, which is always read last -- copy a .conf there and
|
||||
modify it, or symlink it to `/dev/null` to disable it outright.
|
||||
|
||||
Services in the `available/` and `enabled/` sub-directories are called
|
||||
dynamic services, in contrast to static services -- the only difference
|
||||
@@ -55,27 +58,28 @@ 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.
|
||||
with `finit.conf`, then `/run/finit/system/*.conf`,
|
||||
`/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:**
|
||||
|
||||
/run/finit/system/keventd.conf
|
||||
/run/finit/system/runparts.conf
|
||||
/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`,
|
||||
The resulting combined configuration is read in order, 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.
|
||||
properties of `run`. For an example on the relation of `service` and
|
||||
`run`, 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
|
||||
@@ -84,7 +88,7 @@ see [Conditional Loading](services.md#conditional-loading), below.
|
||||
>
|
||||
> 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`.
|
||||
> top-level setting `rcsd = "/path/to/finit.d"`.
|
||||
|
||||
Filesystem Layout
|
||||
-----------------
|
||||
@@ -180,7 +184,7 @@ document [Finit Services](../service.md).
|
||||
Alternate finit.d/
|
||||
------------------
|
||||
|
||||
**Syntax:** `rcsd /path/to/finit.d`
|
||||
**Syntax:** `rcsd = "/path/to/finit.d"`
|
||||
|
||||
The Finit rcS.d directory is set at compile time with:
|
||||
|
||||
@@ -194,7 +198,7 @@ configurations, starting with the kernel command line option:
|
||||
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
|
||||
rcsd = "/etc/factory.d"
|
||||
|
||||
> [!NOTE]
|
||||
> This directive is only available from the top-level bootstrap .conf
|
||||
@@ -203,6 +207,6 @@ another set of .conf files, e.g.:
|
||||
Including Finit Configs
|
||||
------------------------
|
||||
|
||||
**Syntax:** `include <CONF>`
|
||||
**Syntax:** `include("CONF")`
|
||||
|
||||
Include another configuration file. Absolute path required.
|
||||
|
||||
+99
-13
@@ -6,24 +6,110 @@ 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:
|
||||
A `.conf` file is a series of blocks. Every setting is a key inside
|
||||
one, so nothing has to be remembered by position:
|
||||
|
||||
```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
|
||||
service sysklogd {
|
||||
description = "System log daemon"
|
||||
runlevel = "S123456789"
|
||||
envfile = "-/etc/default/sysklogd"
|
||||
command = "syslogd -F $SYSLOGD_ARGS"
|
||||
}
|
||||
```
|
||||
|
||||
Values are quoted strings, bare words, or integers. Lists use braces,
|
||||
and a block may carry a title, which becomes the service identity:
|
||||
|
||||
```aconf
|
||||
# shell comment
|
||||
// C++ comment
|
||||
/* C comment */
|
||||
|
||||
key = "value" # string
|
||||
number = 20 # integer
|
||||
flag = true # boolean
|
||||
list = { "one", "two" } # string list
|
||||
block title { key = "value" } # titled section
|
||||
|
||||
path = "${HOME}/thing" # environment expansion
|
||||
include("/etc/finit.d/extra.conf") # include another file
|
||||
```
|
||||
|
||||
Bare words work wherever a string is expected, so `memory.max = 65M`
|
||||
and `restart = always` need no quotes.
|
||||
|
||||
### Two conventions
|
||||
|
||||
Keys are kebab-case, never `snake_case` or `CamelCase`: `restart-sec`,
|
||||
`stop-timeout`, `reboot-watchdog`.
|
||||
|
||||
Keys that take a list are plural: `conditions`, `conflicts`,
|
||||
`capabilities`, `modules`, `extra-groups`. Two imperatives keep their
|
||||
singular form because they are verbs rather than nouns: `mknod` and
|
||||
`include`.
|
||||
|
||||
### Short forms
|
||||
|
||||
Nine keys have an alias. An alias may abbreviate the canonical name,
|
||||
or preserve the spelling the line-based format used; it never renames.
|
||||
|
||||
| Canonical | Alias | Canonical | Alias |
|
||||
|---|---|---|---|
|
||||
| `description` | `desc` | `manual-start` | `manual` |
|
||||
| `conditions` | `cond` | `remain-after-exit` | `remain` |
|
||||
| `capabilities` | `caps` | `stop-signal` | `halt` |
|
||||
| `modules` | `mod` | `stop-timeout` | `kill` |
|
||||
| `envfile` | `env` | | |
|
||||
|
||||
### Optional paths
|
||||
|
||||
A leading `-` on a path means carry on if it is not there:
|
||||
|
||||
```aconf
|
||||
service foo {
|
||||
envfile = "-/etc/default/foo" # skip the file if missing
|
||||
command = "-/usr/sbin/foo" # skip the whole block if missing
|
||||
}
|
||||
```
|
||||
|
||||
That is the only mark meaning "optional". Two others mean something
|
||||
else: `!` on `runlevel` inverts the set, e.g. `runlevel = "!12345"`,
|
||||
and `~` on a condition propagates a reload from the service it names.
|
||||
Both are covered where they apply.
|
||||
|
||||
|
||||
Both Formats Are Read
|
||||
---------------------
|
||||
|
||||
Finit also reads the line-based format it has always used, where a
|
||||
stanza is a keyword followed by values whose meaning comes from their
|
||||
position:
|
||||
|
||||
```aconf
|
||||
service [S123456789] env:-/etc/default/sysklogd syslogd -F $SYSLOGD_ARGS -- System log daemon
|
||||
```
|
||||
|
||||
That format still works and is not going away. It is frozen at the
|
||||
Finit 4.x feature set, so new settings appear only in the block format,
|
||||
and the documentation is written in blocks throughout. To convert a
|
||||
file, see the [Syntax Migration Guide](migration.md).
|
||||
|
||||
There is no new file extension and no marker line. Every file is still
|
||||
`*.conf`, and Finit decides which format a file is in by reading it: if
|
||||
it parses as blocks it is a block file, otherwise it goes to the
|
||||
line-based parser. A file is one format or the other, never a mix.
|
||||
|
||||
Because the two are told apart before either parser commits, a typo
|
||||
reports its own file and line instead of being mistaken for the other
|
||||
format:
|
||||
|
||||
```
|
||||
parse error: /etc/finit.d/foo.conf:3: no such option 'commnad'
|
||||
```
|
||||
|
||||
The .conf files `/etc/finit.conf` and `/etc/finit.d/*` support many
|
||||
directives. Some are restricted, e.g., only available at bootstrap,
|
||||
settings. 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.
|
||||
|
||||
|
||||
+36
-17
@@ -1,13 +1,13 @@
|
||||
General Logging
|
||||
===============
|
||||
|
||||
**Syntax:** `log size:200k count:5`
|
||||
**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.
|
||||
Log rotation for run/task/services that redirect output to a log file
|
||||
with their own `log` block. 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
|
||||
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.
|
||||
@@ -17,33 +17,48 @@ 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
|
||||
The `run`, `task`, and `service` blocks take a `log` block of their own,
|
||||
redirecting `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:
|
||||
An empty block means syslog with the defaults, and three keys adjust it:
|
||||
|
||||
log:/path/to/file
|
||||
log:prio:facility.level,tag:ident
|
||||
log:console
|
||||
log:null
|
||||
log
|
||||
| Setting | Description |
|
||||
|---|---|
|
||||
| `file` | Write to this path instead of syslog |
|
||||
| `priority` | Syslog `facility.level`, default `daemon.info` |
|
||||
| `identity` | Syslog tag, default the basename of the command |
|
||||
|
||||
Default `prio` is `daemon.info` and default `tag` is the basename of the
|
||||
service or run/task command.
|
||||
`/dev/console` and `/dev/null` are spelled as the paths they are:
|
||||
|
||||
service foo { log { } command = "foo" } # syslog
|
||||
service foo { log { file = "/var/log/foo" } command = "foo" } # a file
|
||||
service foo { log { file = "/dev/console" } command = "foo" } # console
|
||||
service foo { log { file = "/dev/null" } command = "foo" } # discard
|
||||
|
||||
> [!NOTE]
|
||||
> A `log` block at file scope is a different setting -- that one is the
|
||||
> global rotation above, and it takes only `size` and `count`.
|
||||
|
||||
Log rotation is controlled using the global `log` setting.
|
||||
|
||||
**Example:**
|
||||
|
||||
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
|
||||
service ntpd {
|
||||
description = "NTP daemon"
|
||||
log {
|
||||
priority = "user.warn"
|
||||
identity = "ntpd"
|
||||
}
|
||||
command = "/sbin/ntpd pool.ntp.org"
|
||||
}
|
||||
|
||||
Output Buffering
|
||||
----------------
|
||||
|
||||
When using the `log` directive, Finit redirects the service's stdout and
|
||||
When using the `log` block, 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.
|
||||
@@ -53,7 +68,11 @@ 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
|
||||
service myservice {
|
||||
description = "My service"
|
||||
log { }
|
||||
command = "/usr/bin/stdbuf -oL /path/to/command"
|
||||
}
|
||||
|
||||
The `-oL` option forces line-buffered output, and `-o0` forces unbuffered
|
||||
output. See `stdbuf(1)` for details.
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
Syntax Migration Guide
|
||||
======================
|
||||
|
||||
Finit reads both configuration formats. Every file is still `*.conf`,
|
||||
and the format is detected per file, so a system can be migrated one
|
||||
file at a time -- a file is one format or the other, never a mix.
|
||||
|
||||
This guide maps each part of a line-based stanza to its block key.
|
||||
|
||||
The shape of the change:
|
||||
|
||||
service [S12345] <pid/syslogd> env:-/etc/default/klogd name:klogd klogd -n $KLOGD_OPTS -- Kernel log daemon
|
||||
|
||||
becomes
|
||||
|
||||
service klogd {
|
||||
description = "Kernel log daemon"
|
||||
runlevel = "S12345"
|
||||
conditions = { "pid/syslogd" }
|
||||
envfile = "-/etc/default/klogd"
|
||||
command = "klogd -n $KLOGD_OPTS"
|
||||
}
|
||||
|
||||
The block title is the service identity, shown by `initctl`. Multiple
|
||||
instances spell the ID in the title: `service sshd:1 { ... }`. The
|
||||
legacy bare-ID form, `service :80 ...`, has no equivalent -- the title
|
||||
carries both name and ID.
|
||||
|
||||
Positional parts
|
||||
----------------
|
||||
|
||||
| Line-based | Block key |
|
||||
|----------------------------------|-------------------------------------------------------|
|
||||
| `service`, `task`, `run`, `sysv` | same, as block type |
|
||||
| `[S12345]` | `runlevel = "S12345"` |
|
||||
| `<pid/a,net/b>` | `conditions = { "pid/a", "net/b" }` |
|
||||
| `<!pid/a>` on service/sysv | `conditions = { "pid/a" }` + `reload-signal = "none"` |
|
||||
| `<!pid/a>` on run/task | `conditions = { "pid/a" }` + `required = false` |
|
||||
| `@user:group,extra` | `user`, `group`, `extra-groups = { "extra" }` |
|
||||
| `name:foo :1` | block title `foo:1` |
|
||||
| the command and arguments | `command = "..."` |
|
||||
| `-- Description text` | `description = "..."` |
|
||||
|
||||
The `!` was a flag on the stanza, not a negation, and meant different
|
||||
things for daemons and one-shots; each meaning is now its own key. A
|
||||
`~` prefix on a condition is unchanged: `conditions = { "~pid/a" }`.
|
||||
|
||||
Service options
|
||||
---------------
|
||||
|
||||
| Line-based | Block key |
|
||||
|----------------------------------|--------------------------------------------------|
|
||||
| `env:[-]/path` | `envfile = "[-]/path"` |
|
||||
| `pid:/path` | `pidfile = "/path"` + `pidfile-create = true` |
|
||||
| `pid:!/path` | `pidfile = "/path"` |
|
||||
| `pid` | `pidfile = true` + `pidfile-create = true` |
|
||||
| `log` | `log { }` |
|
||||
| `log:/path` | `log { file = "/path" }` |
|
||||
| `log:null`, `log:console` | `log { file = "/dev/null" }`, `"/dev/console"` |
|
||||
| `log:prio:p,tag:t` | `log { priority = "p" identity = "t" }` |
|
||||
| `notify:systemd` | `notify = "systemd"` |
|
||||
| `type:forking` | `type = "forking"` |
|
||||
| `manual:yes` | `manual-start = true` |
|
||||
| `remain:yes` | `remain-after-exit = true` |
|
||||
| `restart:always` / `restart:NUM` | `restart = "always"` / `restart-max = NUM` |
|
||||
| `restart_sec:SEC` | `restart-sec = SEC` |
|
||||
| `norestart` | `restart = "never"` |
|
||||
| `respawn` | `respawn = true` |
|
||||
| `oncrash:reboot` | `oncrash = "reboot"` |
|
||||
| `halt:SIG` | `stop-signal = "SIG"` |
|
||||
| `kill:SEC` | `stop-timeout = SEC` |
|
||||
| `pre:[TMO,]/script` | `exec-start-pre`, `exec-start-pre-timeout` |
|
||||
| `ready:[TMO,]/script` | `exec-start-ready`, and its `-timeout` |
|
||||
| `stop:[TMO,]/script` | `exec-stop`, and its `-timeout` |
|
||||
| `post:[TMO,]/script` | `exec-stop-post`, and its `-timeout` |
|
||||
| `reload:[TMO,]/script` | `exec-reload`, and its `-timeout` |
|
||||
| `cleanup:[TMO,]/script` | `exec-cleanup`, and its `-timeout` |
|
||||
| `caps:^cap_a,%cap_b` | `capabilities = { "^cap_a", "%cap_b" }` |
|
||||
| `conflict:a,b` | `conflicts = { "a", "b" }` |
|
||||
| `if:svc` / `if:<cond>` | `if = "svc"` / `if = "cond"`, no angle brackets |
|
||||
| `tty:/dev/x` | `tty = "/dev/x"` |
|
||||
| `nowarn` | leading `-` on `command` or `envfile` |
|
||||
| `restarttmo:` | dropped, was already an alias for `restart_sec:` |
|
||||
|
||||
Repeated stanzas
|
||||
----------------
|
||||
|
||||
The line-based format has no titles, so the same service could be
|
||||
declared more than once and Finit would sort out which line applied.
|
||||
A block title *is* the identity, and two blocks sharing one in the
|
||||
same file are rejected. The two shapes that relied on the repetition
|
||||
convert differently.
|
||||
|
||||
**Several candidate binaries for one service.** The daemon is known
|
||||
under more than one name and the stanzas were repeated once per name,
|
||||
each with `nowarn` so the ones that were not installed were skipped:
|
||||
|
||||
service nowarn pid:!/run/udevd.pid [S12345789] /lib/systemd/systemd-udevd -- Device event daemon
|
||||
service nowarn pid:!/run/udevd.pid [S12345789] udevd -- Device event daemon
|
||||
|
||||
The candidates now go in one block, and Finit starts the first one it
|
||||
finds:
|
||||
|
||||
service udevd {
|
||||
description = "Device event daemon"
|
||||
runlevel = "S12345789"
|
||||
pidfile = "/run/udevd.pid"
|
||||
command = { "/lib/systemd/systemd-udevd", "-udevd" }
|
||||
}
|
||||
|
||||
**One service gated differently per platform.** The command is the
|
||||
same every time, only `if:` and the conditions differ, e.g. a syslog
|
||||
daemon that has to wait for whichever hotplug daemon the system has:
|
||||
|
||||
service if:udevd nowarn env:-/etc/default/sysklogd <run/udevadm:5/success> \
|
||||
[S0123456789] syslogd -F $SYSLOGD_ARGS -- System log daemon
|
||||
service if:mdev nowarn env:-/etc/default/sysklogd <run/coldplug/success> \
|
||||
[S0123456789] syslogd -F $SYSLOGD_ARGS -- System log daemon
|
||||
|
||||
All of these are one service, `syslogd`, and everything downstream
|
||||
waits for the one `pid/syslogd` barrier it provides. That barrier is
|
||||
the reason the repetition existed: the title alone spells it, so
|
||||
separate titles would rename it.
|
||||
|
||||
Give each variant its own title and name the shared barrier with
|
||||
`provides`:
|
||||
|
||||
service syslogd:udev {
|
||||
description = "System log daemon"
|
||||
runlevel = "S0123456789"
|
||||
if = "udevd"
|
||||
conditions = { "run/udevadm:5/success" }
|
||||
provides = "pid/syslogd"
|
||||
envfile = "-/etc/default/sysklogd"
|
||||
command = "-syslogd -F $SYSLOGD_ARGS"
|
||||
}
|
||||
service syslogd:mdev {
|
||||
description = "System log daemon"
|
||||
runlevel = "S0123456789"
|
||||
if = "mdev"
|
||||
conditions = { "run/coldplug/success" }
|
||||
provides = "pid/syslogd"
|
||||
envfile = "-/etc/default/sysklogd"
|
||||
command = "-syslogd -F $SYSLOGD_ARGS"
|
||||
}
|
||||
|
||||
Whichever variant `if` qualifies asserts `pid/syslogd` on top of its
|
||||
own `pid/syslogd:udev`, so downstream blocks need no change. The `if`
|
||||
statements are meant to be mutually exclusive; if two of them do
|
||||
qualify, the second claim is refused with a warning and only the first
|
||||
variant supplies the barrier. See [Provided
|
||||
Conditions](service-opts.md#provided-conditions).
|
||||
|
||||
`initctl` now knows the variants apart, `initctl status syslogd:udev`,
|
||||
and a bare `initctl status syslogd` still lists them all.
|
||||
|
||||
Splitting the variants across files also works, since the ban on
|
||||
duplicate titles is per file, as does leaving that one file in the
|
||||
line-based format. Neither is needed for this shape any more.
|
||||
|
||||
Cgroups
|
||||
-------
|
||||
|
||||
The standalone `cgroup.NAME` line selected a group for every stanza
|
||||
after it in the file, and `cgroup:opts` applied settings to whichever
|
||||
group was current. Neither survives: every block names its own group,
|
||||
so nothing depends on what came earlier in the file.
|
||||
|
||||
cgroup.maint
|
||||
service [2345] cgroup:cpu.weight:250 foo -- Foo daemon
|
||||
|
||||
becomes
|
||||
|
||||
service foo {
|
||||
description = "Foo daemon"
|
||||
runlevel = "2345"
|
||||
cgroup maint { cpu.weight = 250 }
|
||||
command = "foo"
|
||||
}
|
||||
|
||||
Top-level group declarations keep their name and settings:
|
||||
|
||||
cgroup system cpu.weight:9700 mem.max:10M
|
||||
|
||||
becomes
|
||||
|
||||
cgroup system {
|
||||
cpu.weight = 9700
|
||||
memory.max = 10M
|
||||
}
|
||||
|
||||
TTYs
|
||||
----
|
||||
|
||||
The three positional variants become three key choices:
|
||||
|
||||
tty [12345] /dev/ttyS0 115200 noclear vt220
|
||||
tty [12345] /sbin/getty -L ttyS0 115200 vt100
|
||||
tty [12345] notty
|
||||
|
||||
become
|
||||
|
||||
tty ttyS0 {
|
||||
runlevel = "12345"
|
||||
device = "/dev/ttyS0"
|
||||
baud = 115200
|
||||
term = "vt220"
|
||||
noclear = true
|
||||
}
|
||||
tty getty {
|
||||
runlevel = "12345"
|
||||
command = "/sbin/getty -L ttyS0 115200 vt100"
|
||||
}
|
||||
tty shell {
|
||||
runlevel = "12345"
|
||||
notty = true
|
||||
}
|
||||
|
||||
The bare flags keep their names as booleans: `noclear`, `nowait`,
|
||||
`nologin`, `passenv`, `rescue`, e.g. `passenv` becomes
|
||||
`passenv = true`.
|
||||
|
||||
A `tty` block is named by the device, not the title, so all three above
|
||||
show up as `tty:ttyS0` and the like in `initctl`. The title still has
|
||||
to be unique within the file.
|
||||
|
||||
Top-level directives
|
||||
--------------------
|
||||
|
||||
| Line-based | Block key |
|
||||
|----------------------------------|----------------------------------------------------------|
|
||||
| `host NAME`, `hostname NAME` | `hostname = "NAME"` |
|
||||
| `module foo args` (repeated) | `modules = { "foo args", ... }` |
|
||||
| `network script args` | `network = "script args"` |
|
||||
| `runlevel N` | `runlevel = N` |
|
||||
| `rcsd /path` | `rcsd = "/path"` |
|
||||
| `runparts [progress] [sysv] DIR` | `runparts = "DIR"`, `runparts-progress`, `runparts-sysv` |
|
||||
| `set KEY=VAL` (repeated) | `environment { KEY = "VAL" }` |
|
||||
| `log size:100k count:4` | `log { size = 100k count = 4 }` |
|
||||
| `rlimit [hard\|soft] RES LIM` | `rlimit { hard.res = LIM }` |
|
||||
| `readiness none` | `readiness = "none"` |
|
||||
| `reboot-delay N` | `reboot-delay = N` |
|
||||
| `reboot-watchdog on` | `reboot-watchdog = true` |
|
||||
| `service-interval SEC` | `service-interval = SEC` |
|
||||
| `shutdown script` | `shutdown = "script"` |
|
||||
| `mknod /dev/x c 1 2` | `mknod = { "/dev/x c 1 2" }` |
|
||||
| `include /path` | `include("/path")` |
|
||||
|
||||
Worth knowing
|
||||
-------------
|
||||
|
||||
* Templates work unchanged: `%i` is replaced before the file is
|
||||
parsed, so `service serv:%i { ... }` in a `serv@.conf` behaves
|
||||
exactly like its legacy counterpart.
|
||||
* A list cannot hold comments; the lexer reads entries after a `#`
|
||||
regardless. Put commented-out candidates above the list.
|
||||
* `${VAR}` in a value is expanded when the file is read, against
|
||||
Finit's environment, and `${VAR:-default}` works too. An unset
|
||||
variable expands to nothing. A plain `$VAR` is left alone and
|
||||
reaches the service, which is what keeps `command = "syslogd -F
|
||||
$SYSLOGD_ARGS"` working with an `envfile`.
|
||||
* New settings only appear in the block format. The first are the
|
||||
[per-service directories](service-opts.md#service-directories),
|
||||
`runtime-dir` and friends, and [`pam`](pam.md).
|
||||
|
||||
For the full description of every key, see the rest of the
|
||||
[Configuration](index.md) section.
|
||||
@@ -0,0 +1,151 @@
|
||||
PAM Sessions
|
||||
============
|
||||
|
||||
`pam = "NAME"` runs a service inside a PAM session set up from
|
||||
`/etc/pam.d/NAME`. The `session` stack in that file runs for the
|
||||
process that goes on to become the daemon, so modules like `pam_limits`,
|
||||
`pam_env`, or `pam_keyinit` see the service the way they see a login.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
A display server that needs the session a login would have arranged for
|
||||
it:
|
||||
|
||||
```conf
|
||||
service weston {
|
||||
user = "weston"
|
||||
pam = "weston-autologin"
|
||||
command = "/usr/bin/weston --continue-without-input"
|
||||
}
|
||||
```
|
||||
|
||||
With `/etc/pam.d/weston-autologin`:
|
||||
|
||||
```
|
||||
auth required pam_permit.so
|
||||
account required pam_unix.so
|
||||
session required pam_unix.so
|
||||
session required pam_limits.so
|
||||
```
|
||||
|
||||
The `auth` line is needed even though nothing is ever authenticated.
|
||||
Opening the session goes through `pam_setcred()`, which consults the
|
||||
`auth` stack, and an empty stack comes back as a permission denial, so a
|
||||
pam.d file with only `account` and `session` lines keeps the service
|
||||
from starting.
|
||||
|
||||
The value names a file in `/etc/pam.d`, it is not a path. A value
|
||||
holding `/` or `..`, or one too long to fit, is refused, with an error
|
||||
in the log when the .conf file is read. The service does not start
|
||||
either, `initctl status` reports it as missing. Like the per-service
|
||||
directory keys, `pam` exists in the block format only.
|
||||
|
||||
## No Authentication
|
||||
|
||||
Finit runs the account and session stacks, `pam_acct_mgmt()`,
|
||||
`pam_setcred()`, and `pam_open_session()`, and never
|
||||
`pam_authenticate()`. A module that asks a question gets a
|
||||
conversation error back and its entry in the stack fails.
|
||||
|
||||
A service whose account is denied, an expired account say, does not
|
||||
start, and neither does one naming a pam.d file that is not installed.
|
||||
The child exits 71 (`EX_OSERR`), `initctl status` shows the service as
|
||||
crashed, and PAM's own reason is in the log.
|
||||
|
||||
## Requirements
|
||||
|
||||
PAM support is built by default, see [Building Finit](../build.md).
|
||||
Without it, e.g. after `--disable-pam`, a service declaring `pam` is
|
||||
refused rather than started with the stacks skipped:
|
||||
|
||||
weston: pam weston-autologin requires Finit built with --enable-pam
|
||||
|
||||
## Which Blocks Take It
|
||||
|
||||
`service`, `task`, `run`, and `sysv`. Not `tty`: `login` opens a
|
||||
session of its own there.
|
||||
|
||||
Every fork gets its own session, so the `pre:`, `post:`, `ready:`, and
|
||||
`cleanup:` scripts each open and close one too, as do the stop and
|
||||
reload scripts and the `stop` call on a `sysv` script.
|
||||
|
||||
A refused value stops those too. A `pre:` script forks before the
|
||||
start-time check runs, so it exits 71 without running instead of the
|
||||
service being reported missing.
|
||||
|
||||
## The User
|
||||
|
||||
`user` decides who the session is for. Without it the session is for
|
||||
root.
|
||||
|
||||
systemd documents the opposite for its equivalent. `systemd.exec(5)`
|
||||
says `PAMName=` is "only useful in conjunction with the `User=`
|
||||
setting, and is otherwise ignored". That was true of systemd up to and
|
||||
including v256, v257 changed it to open a session for the manager's own
|
||||
user, and the man page was never updated. Finit does what v257 does.
|
||||
|
||||
A service with a [controlling tty](tty.md#controlling-tty-for-services)
|
||||
has it passed to PAM as `PAM_TTY`, for the modules that care which
|
||||
terminal a session is on.
|
||||
|
||||
## Precedence
|
||||
|
||||
Three places where PAM and a Finit setting cover the same ground:
|
||||
|
||||
- `pam_limits` overrides a per-service `rlimit`. A block asking for
|
||||
`nofile = 4096` under a `limits.conf` that says 512 gets 512.
|
||||
- `pam_env` overrides Finit's own environment defaults, `PATH`, `USER`,
|
||||
`LOGNAME`, and `HOME`, and `envfile` in turn overrides `pam_env`. A
|
||||
`HOME` from the session stack also moves the working directory, which
|
||||
otherwise is the home directory from `/etc/passwd`.
|
||||
- The groups from `/etc/group` and `extra-groups` override `pam_group`.
|
||||
|
||||
## The Session Keeper
|
||||
|
||||
A helper is forked next to the service to close the session when the
|
||||
service exits, `(finit-pam)`:
|
||||
|
||||
```
|
||||
CGroup : /system/weston cpu 0 [100, max] mem [--.--, max]
|
||||
|- 312 /usr/bin/weston --continue-without-input
|
||||
`- 313 (finit-pam)
|
||||
```
|
||||
|
||||
There is one per fork. It runs as the service's user, in the service's
|
||||
cgroup, and stopping the service takes it along.
|
||||
|
||||
A daemon that reaps children in its own `wait()` loop will see a child
|
||||
it never forked. systemd has the same property, with `(sd-pam)`.
|
||||
|
||||
## Limitations
|
||||
|
||||
- `type = "forking"` closes the session early. The initial process
|
||||
exits by design, the keeper's parent-death signal fires with it, and
|
||||
the session is closed while the real daemon runs on. Finit warns
|
||||
about the combination when it reads the .conf file, and starts the
|
||||
service anyway:
|
||||
|
||||
/etc/finit.d/foo.conf: foo: pam with type = forking closes the
|
||||
session when the initial process exits
|
||||
|
||||
- A daemon whose initial thread exits while the process lives closes the
|
||||
session the same way. The parent-death signal follows the thread that
|
||||
forked the keeper, not the process.
|
||||
- A capability granted by `pam_cap.so` is only kept when the service
|
||||
also sets [`capabilities`](capabilities.md).
|
||||
- The keeper shares the service's cgroup, so an empty cgroup directory
|
||||
can outlive a stop until the next start reuses it. Cosmetic.
|
||||
- A module that blocks has no time bound. `pam_open_session()` waits
|
||||
for as long as the module does, `pam_ldap` against an unreachable
|
||||
server, say, or `pam_mount` on a hung network mount. The fork has already succeeded by then, so the service
|
||||
reaches the running state and stays there with no daemon behind it.
|
||||
Nothing crashes and nothing restarts.
|
||||
|
||||
## See Also
|
||||
|
||||
- [Service Options](service-opts.md) - the other run/task/service keys
|
||||
- [Linux Capabilities](capabilities.md) - the key `pam_cap.so` needs
|
||||
- [Building Finit](../build.md) - `--disable-pam` and its dependency
|
||||
- [pam(8)](https://man7.org/linux/man-pages/man8/pam.8.html) - the PAM library
|
||||
- [pam.d(5)](https://man7.org/linux/man-pages/man5/pam.d.5.html) - the file format
|
||||
- [pam_limits(8)](https://man7.org/linux/man-pages/man8/pam_limits.8.html) - limits from `limits.conf`
|
||||
+13
-6
@@ -47,16 +47,23 @@ system administrator.
|
||||
|
||||
The bundled default `rescue.conf` contains nothing more than:
|
||||
|
||||
runlevel 1
|
||||
tty [12345] rescue
|
||||
runlevel = 1
|
||||
tty rescue {
|
||||
runlevel = "12345"
|
||||
rescue = true
|
||||
}
|
||||
|
||||
The `tty` has the `rescue` option set, which works similar to the board
|
||||
bring-up tty option `notty`. The major difference being that `sulogin`
|
||||
The `tty` block has `rescue` set, which works similar to the board
|
||||
bring-up setting `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:
|
||||
If Finit cannot find `/lib/finit/rescue.conf` it falls back to a
|
||||
built-in equivalent, which runs in every runlevel it can:
|
||||
|
||||
tty [12345] rescue
|
||||
tty rescue {
|
||||
runlevel = "12345789"
|
||||
rescue = true
|
||||
}
|
||||
|
||||
There is no way to exit the *fallback* rescue mode.
|
||||
+48
-31
@@ -26,12 +26,20 @@ the lifetime of your system.
|
||||
|
||||
Example:
|
||||
|
||||
task [S] /lib/console-setup/console-setup.sh
|
||||
service [S12345] env:-/etc/default/rsyslog rsyslogd -n $RSYSLOGD_ARGS
|
||||
task console-setup {
|
||||
runlevel = "S"
|
||||
command = "/lib/console-setup/console-setup.sh"
|
||||
}
|
||||
|
||||
service rsyslogd {
|
||||
runlevel = "S12345"
|
||||
envfile = "-/etc/default/rsyslog"
|
||||
command = "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`.
|
||||
changed in `/etc/finit.conf` with `runlevel = N`, 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.
|
||||
@@ -44,7 +52,7 @@ 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
|
||||
enabled either by `network = "script"`, or if you have an
|
||||
`/etc/network/interfaces` file, Finit calls `ifup -a` -- at the very
|
||||
least the loopback interface is brought up.
|
||||
|
||||
@@ -58,7 +66,7 @@ least the loopback interface is brought up.
|
||||
Runlevel Configuration
|
||||
----------------------
|
||||
|
||||
**Syntax:** `runlevel <N>`
|
||||
**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.
|
||||
@@ -76,11 +84,11 @@ Finit disables networking in this mode.
|
||||
Networking
|
||||
----------
|
||||
|
||||
**Syntax:** `network <PATH>`
|
||||
**Syntax:** `network = "PATH"`
|
||||
|
||||
Script or program to bring up networking, with optional arguments.
|
||||
|
||||
Deprecated. We recommend using dedicated task/run stanzas per runlevel,
|
||||
Deprecated. We recommend using dedicated task/run blocks per runlevel,
|
||||
or `/etc/network/interfaces` if you have a system with `ifupdown`, like
|
||||
Debian, Ubuntu, Linux Mint, or an embedded BusyBox system.
|
||||
|
||||
@@ -90,7 +98,7 @@ Debian, Ubuntu, Linux Mint, or an embedded BusyBox system.
|
||||
System Hostname
|
||||
---------------
|
||||
|
||||
**Syntax:** `host <NAME>`, or `hostname <NAME>`
|
||||
**Syntax:** `hostname = "NAME"`
|
||||
|
||||
Set system hostname to NAME, unless `/etc/hostname` exists in which case
|
||||
the contents of that file is used.
|
||||
@@ -103,16 +111,24 @@ Deprecated. We recommend using `/etc/hostname` instead.
|
||||
Kernel Modules
|
||||
--------------
|
||||
|
||||
**Syntax:** `module <MODULE> [ARGS]`
|
||||
**Syntax:** `modules = { "MODULE [ARGS]", ... }`, alias `mod`
|
||||
|
||||
Load a kernel module, with optional arguments. Similar to `insmod`
|
||||
command line tool.
|
||||
Load kernel modules, each with optional arguments. Similar to the
|
||||
`insmod` command line tool.
|
||||
|
||||
modules = { "button", "evdev", "softdog" }
|
||||
|
||||
> [!NOTE]
|
||||
> A list cannot hold comments; the lexer reads the entries after a `#`
|
||||
> regardless. Put commented-out candidates above the list.
|
||||
|
||||
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`:
|
||||
load (or coldplug) every required module. Hotplug module loading is
|
||||
handled by [keventd](../keventd.md), the built-in device manager. On
|
||||
systems using the hotplug plugin with BusyBox mdev instead, add to
|
||||
`/etc/mdev.conf`:
|
||||
|
||||
$MODALIAS=.* root:root 0660 @modprobe -b "$MODALIAS"
|
||||
|
||||
@@ -122,34 +138,35 @@ BusyBox mdev tool, add to `/etc/mdev.conf`:
|
||||
Resource Limits
|
||||
---------------
|
||||
|
||||
**Syntax:** `rlimit [hard|soft] RESOURCE <LIMIT|unlimited>`
|
||||
**Syntax:** `rlimit { RESOURCE = LIMIT }`, with `soft.` or `hard.` prefix
|
||||
|
||||
Set the hard or soft limit for a resource, or both if that argument is
|
||||
Set the hard or soft limit for a resource, or both if the prefix 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.
|
||||
[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 {
|
||||
hard.as = 8388608 # no more than 8MB of address space
|
||||
soft.core = unlimited # core dumps may be arbitrarily large
|
||||
cpu = 10 # soft & hard = 10 sec
|
||||
}
|
||||
|
||||
`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.
|
||||
blocks can share the same rlimits if they are in the same .conf.
|
||||
|
||||
For a service with [`pam`](pam.md), `pam_limits` runs after these
|
||||
limits are applied, so `limits.conf` has the last word.
|
||||
|
||||
Miscellaneous Settings
|
||||
----------------------
|
||||
|
||||
**Syntax:** `reboot-delay <0-60>`
|
||||
**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
|
||||
@@ -167,7 +184,7 @@ sync(2) has been called, twice.
|
||||
> writing; it can actually take a short time before all the blocks are
|
||||
> finally written.
|
||||
|
||||
**Syntax:** `reboot-watchdog <on|off|true|false|1|0>`
|
||||
**Syntax:** `reboot-watchdog = true|false`
|
||||
|
||||
Controls whether the system should reboot via the watchdog timer (WDT)
|
||||
or directly via the SoC/kernel. When enabled, Finit will:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Run-parts Scripts
|
||||
-----------------
|
||||
|
||||
**Syntax:** `runparts [progress] [sysv] <DIR>`
|
||||
**Syntax:** `runparts = "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
|
||||
@@ -14,9 +14,10 @@ whatever the next runlevel is set to be (default 2). E.g., generate a
|
||||
|
||||
**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).
|
||||
- `runparts-progress = true`: display the progress of each script being
|
||||
executed
|
||||
- `runparts-sysv = true`: 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.
|
||||
@@ -24,7 +25,7 @@ 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
|
||||
in their interaction with Finit. Like a standalone `run` block 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
|
||||
@@ -39,13 +40,13 @@ either terminate or start in the background or you will block Finit.
|
||||
|
||||
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,
|
||||
order between scripts. Symlinks to existing daemons can also 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`.
|
||||
and `K01foo` may be a symlink to `another/directory/foo`.
|
||||
|
||||
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
||||
|
||||
@@ -13,7 +13,12 @@ file `/etc/default/foo`. Like this:
|
||||
|
||||
* `/etc/finit.conf`:
|
||||
|
||||
service [2345] env:-/etc/default/foo foo -n $FOO_OPTIONS -- Example foo daemon
|
||||
service foo {
|
||||
description = "Example foo daemon"
|
||||
runlevel = "2345"
|
||||
envfile = "-/etc/default/foo"
|
||||
command = "foo -n $FOO_OPTIONS"
|
||||
}
|
||||
|
||||
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
|
||||
@@ -22,6 +27,11 @@ 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.
|
||||
For a service with [`pam`](pam.md), the session environment is applied
|
||||
before `envfile`, so the file overrides anything `pam_env` set.
|
||||
|
||||
> The leading `-` on `envfile` 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. The same mark works on `command`, where it means carry on if
|
||||
> the binary is missing.
|
||||
|
||||
+287
-90
@@ -1,21 +1,22 @@
|
||||
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 `run`, `task`, `tty`, `service` and `sysv` blocks take settings as
|
||||
keys. This section lists them with their limitations.
|
||||
|
||||
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:
|
||||
The name of a service, shown by the `initctl` tool, is the block title.
|
||||
It defaults to the basename of the executable if the title is omitted:
|
||||
|
||||
name:<service-name>
|
||||
service sshd {
|
||||
command = "/usr/sbin/sshd -D"
|
||||
}
|
||||
|
||||
For multiple instances of a service, with the same `name`, set the
|
||||
identifier `:ID` to prevent Finit from replacing previous instances:
|
||||
For multiple instances of a service, with the same name, add an
|
||||
identifier after a colon 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
|
||||
service ssdp:eth1 { command = "ssdpd eth1" }
|
||||
service ssdp:eth2 { command = "ssdpd eth2" }
|
||||
|
||||
The [`initctl`](../initctl.md) tool will list these two services as:
|
||||
|
||||
@@ -23,101 +24,295 @@ The [`initctl`](../initctl.md) tool will list these two services as:
|
||||
- ssdp:eth2
|
||||
|
||||
Conflicting services that must be prevented from starting, use the
|
||||
`conflict:` option:
|
||||
`conflicts` key:
|
||||
|
||||
service [S12345789] udevd -- Device event management daemon
|
||||
run [S] conflict:udevd mdev -s -- Populating device tree
|
||||
service udevd { command = "udevd" }
|
||||
run mdev {
|
||||
runlevel = "S"
|
||||
conflicts = { "udevd" }
|
||||
command = "mdev -s"
|
||||
}
|
||||
|
||||
Multiple conflicting services can be separated using `,`:
|
||||
The list may name several, and an instance is named the same way it is
|
||||
declared:
|
||||
|
||||
service :1 abc
|
||||
service :2 abc
|
||||
service conflict:abc:1,abc:2 cde
|
||||
service abc:1 { command = "abc 1" }
|
||||
service abc:2 { command = "abc 2" }
|
||||
service cde { conflicts = { "abc:1", "abc:2" } command = "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>`.
|
||||
If a service should not be automatically started, set `manual-start`.
|
||||
It can then be started at any time with `initctl start <service>`:
|
||||
|
||||
manual:yes
|
||||
service lldpd {
|
||||
manual-start = true
|
||||
command = "/usr/sbin/lldpd -d"
|
||||
}
|
||||
|
||||
Other run/task/service options are:
|
||||
Other run/task/service settings are:
|
||||
|
||||
* `caps:...` -- see the [Linux Capabilities](capabilities.md) section
|
||||
* `cgroups:...` -- 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
|
||||
* `capabilities` -- see the [Linux Capabilities](capabilities.md) section
|
||||
* `cgroup NAME {}` -- see the [Cgroups](cgroups.md) section
|
||||
* `envfile` -- see the [Service Environment](service-env.md) section
|
||||
* `log {}` -- see [Redirecting Output](logging.md#redirecting-output)
|
||||
* `tty` -- see [Controlling TTY](tty.md#controlling-tty-for-services)
|
||||
* `notify` -- see [Service Synchronization](service-sync.md)
|
||||
* `pam` -- see the [PAM Sessions](pam.md) section
|
||||
* `if` -- see [Conditional Execution](services.md#conditional-execution)
|
||||
* `type = "forking"` -- see description of the [service](services.md) block
|
||||
* a leading `-` on `command` -- see
|
||||
[Conditional Loading](services.md#conditional-loading)
|
||||
|
||||
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:
|
||||
Command Candidates
|
||||
------------------
|
||||
|
||||
* `restart:NUM` -- number of times Finit tries to restart a crashing
|
||||
service, default: 10, max: 255. When this limit is reached the
|
||||
The `command` setting may list several candidates for the same
|
||||
service, in which case Finit starts the first one it finds:
|
||||
|
||||
service udevd {
|
||||
command = { "/lib/systemd/systemd-udevd", "-udevd" }
|
||||
}
|
||||
|
||||
A candidate that is not installed is skipped without a warning, that
|
||||
is the point of listing more than one. The leading `-` is read from
|
||||
the candidate that wins, or from the last one when none are found, so
|
||||
a block with a single command behaves as it always has.
|
||||
|
||||
The candidates are alternative spellings of one service, not a
|
||||
fallback for a service that fails to start. Finit chooses when the
|
||||
.conf file is read and does not revisit the choice.
|
||||
|
||||
A [`tty`](tty.md) block takes the same list, where the candidates are
|
||||
the getty to run:
|
||||
|
||||
tty ttyAMA0 {
|
||||
command = { "/sbin/agetty -L ttyAMA0 115200 vt100",
|
||||
"/sbin/getty -L 115200 /dev/ttyAMA0 vt100" }
|
||||
}
|
||||
|
||||
Provided Conditions
|
||||
-------------------
|
||||
|
||||
A service always asserts `pid/<ident>` for itself, named after the
|
||||
block title. `provides` names conditions it asserts in addition to
|
||||
that one:
|
||||
|
||||
service syslogd:udev {
|
||||
if = "udevd"
|
||||
provides = "pid/syslogd"
|
||||
command = "syslogd -F"
|
||||
}
|
||||
|
||||
This is what lets variants of one service, picked apart by
|
||||
[`if`](services.md#conditional-execution), share the barrier that
|
||||
everything downstream waits for. Each variant has its own title, so
|
||||
each is its own service to `initctl`, while the condition they publish
|
||||
stays the same.
|
||||
|
||||
Any namespace works, `pid/`, `usr/`, `service/`, since the point is
|
||||
publishing a name existing configuration already waits on. A value
|
||||
without a namespace separator is not a condition and is rejected. The
|
||||
list holds at most four.
|
||||
|
||||
A provided condition is asserted and cleared with the service, exactly
|
||||
like its own, so stopping the provider clears the barrier.
|
||||
|
||||
Two services cannot supply the same condition. The second claim is
|
||||
refused, with the owner named:
|
||||
|
||||
finit.conf: second: provides condition <usr/barrier> already registered by service first, ignoring
|
||||
|
||||
The service itself still registers and runs, only the claim is
|
||||
dropped. Which one is "first" is .conf load order, so it follows the
|
||||
file names, see [Files & Layout](files.md).
|
||||
|
||||
A real identity outranks a claim on it. `provides = "pid/sshd"` in a
|
||||
system that also runs a service titled `sshd` loses to that service,
|
||||
because `pid/<ident>` is how Finit tracks the service itself.
|
||||
|
||||
`initctl cond dump` names the owner of every condition, which for a
|
||||
provided one is the service that claimed it:
|
||||
|
||||
$ initctl cond dump
|
||||
PID IDENT STATUS CONDITION
|
||||
1234 syslogd:udev on <pid/syslogd>
|
||||
1234 syslogd:udev on <pid/syslogd:udev>
|
||||
|
||||
Duplicate Titles
|
||||
----------------
|
||||
|
||||
The title is the service identity, so two blocks sharing a title in
|
||||
one file are two declarations of one service. The parser underneath
|
||||
merges them without a word, leaving a single service holding a mix of
|
||||
both, so Finit rejects the file and names the title:
|
||||
|
||||
/etc/finit.d/hotplug.conf:12: found duplicate title 'udevd'
|
||||
|
||||
Nothing from a rejected file is loaded and the rest of the
|
||||
configuration is unaffected.
|
||||
|
||||
The same title in *another* file is fine. That is how a system .conf
|
||||
is overridden, the later file wins, see [Files & Layout](files.md).
|
||||
|
||||
Two shapes need a single identity and used to be written as repeated
|
||||
declarations. One is a service with several candidate binaries, which
|
||||
is now a [command list](#command-candidates). The other is a service
|
||||
gated differently per platform, e.g. a syslog daemon waiting for
|
||||
whichever hotplug daemon the system happens to have. For that one,
|
||||
give each variant its own file, or keep them as one-liners in the
|
||||
line-based format, which has no titles. The [migration
|
||||
guide](migration.md) works through it.
|
||||
|
||||
Restarting
|
||||
----------
|
||||
|
||||
Services are automatically started, restarted, and stopped, depending
|
||||
on the configuration and conditions. Within the confines of that the
|
||||
following settings are available:
|
||||
|
||||
* `restart-max = 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 NAME`
|
||||
* `restart_sec:SEC` -- number of seconds before Finit tries to restart
|
||||
a crashing service, default: 2 seconds for the first five retries,
|
||||
then back-off to 5 seconds. The maximum of this configured value
|
||||
and the above (2 and 5) will be used
|
||||
* `restart:always` -- no upper limit on the number of times Finit
|
||||
tries to restart a crashing service. Same as `restart:-1`
|
||||
* `norestart` -- dont restart on failures, same as `restart:0`
|
||||
* `respawn` -- bypasses the `restart` mechanism completely, allows
|
||||
endless restarts. Useful in many use-cases, but not what `service`
|
||||
was originally designed for so not the default behavior
|
||||
* `oncrash:reboot` -- when all retries have failed, and the service
|
||||
has *crashed*, if this option is set the system is rebooted
|
||||
* `oncrash:script` -- similarly, but instead of rebooting, call the
|
||||
`post:script` action 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`
|
||||
* `restart-sec = SEC` -- number of seconds before Finit tries to
|
||||
restart a crashing service. The default is 2 seconds for the first
|
||||
half of `restart-max` attempts, then a back-off to 5 seconds -- with
|
||||
the default `restart-max` that is the first five retries. The
|
||||
greater of this configured value and the back-off is used
|
||||
* `restart = "always"` -- no upper limit on the number of times Finit
|
||||
tries to restart a crashing service
|
||||
* `restart = "never"` -- do not restart on failures. `false` is
|
||||
accepted as a synonym, and `true` selects the default policy
|
||||
* `respawn = true` -- bypasses the `restart` mechanism completely,
|
||||
allowing endless restarts. Exiting is treated as normal work
|
||||
rather than failure, so the service is restarted at once instead of
|
||||
being counted and delayed. This is how a `tty` behaves; it is not
|
||||
what `service` was designed for, so it is not the default
|
||||
* `remain-after-exit = true` -- for `run` and `task` only. Prevents
|
||||
the task from re-running on runlevel re-entry and ensures the
|
||||
`exec-stop-post` script runs when the task is explicitly stopped or
|
||||
leaves its valid runlevels. This is systemd's `RemainAfterExit=`.
|
||||
See [Task and Run](task-and-run.md) for more details
|
||||
* `oncrash = "reboot"` -- when all retries have failed, and the
|
||||
service has *crashed*, the system is rebooted
|
||||
* `oncrash = "script"` -- similarly, but instead of rebooting, call
|
||||
the `exec-stop-post` script with exit code `crashed`, see below
|
||||
|
||||
> [!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.
|
||||
Service directories
|
||||
-------------------
|
||||
|
||||
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`.
|
||||
Five settings ask Finit to create a directory for the service before it
|
||||
starts, owned by its `user` and `group`, mode 0755. The value is a
|
||||
directory name, resolved under a fixed base -- absolute paths and `..`
|
||||
are refused:
|
||||
|
||||
Services, including the `sysv` variant, support pre/post/ready and
|
||||
cleanup scripts:
|
||||
| Setting | Base | Environment variable |
|
||||
|---|---|---|
|
||||
| `runtime-dir` | `/run` | `RUNTIME_DIRECTORY` |
|
||||
| `state-dir` | `/var/lib` | `STATE_DIRECTORY` |
|
||||
| `cache-dir` | `/var/cache` | `CACHE_DIRECTORY` |
|
||||
| `logs-dir` | `/var/log` | `LOGS_DIRECTORY` |
|
||||
| `config-dir` | `/etc` | `CONFIGURATION_DIRECTORY` |
|
||||
|
||||
* `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
|
||||
Each resolved path is exported to the process environment under the
|
||||
listed name, the same names systemd uses for `RuntimeDirectory=` and
|
||||
friends. As in systemd, `config-dir` is the odd one out: it is created
|
||||
but never chowned.
|
||||
|
||||
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:
|
||||
Each takes a matching `-mode`, e.g. `runtime-dir-mode = 0700`, default
|
||||
0755. Modes are octal, with the leading zero.
|
||||
|
||||
The mode of the named directory is locked down again on every start.
|
||||
Its contents are left alone as long as the owner is right; if the owner
|
||||
has drifted, everything under it is chowned back.
|
||||
|
||||
The runtime directory is removed again when the service stops, after
|
||||
any `exec-stop-post` script has run; `/run` is a tmpfs so it would not
|
||||
survive a reboot anyway. The other four persist. A completed `run` or
|
||||
`task` counts as stopped, unless `remain-after-exit` keeps it alive
|
||||
until stopped for real. `runtime-dir-preserve` adjusts this, same
|
||||
values as systemd's `RuntimeDirectoryPreserve=`:
|
||||
|
||||
* `"no"` -- removed when the service stops, the default
|
||||
* `"restart"` -- kept across restarts, removed on a real stop
|
||||
* `"yes"` -- never removed
|
||||
|
||||
This is what lets a service drop privileges and still create, and
|
||||
later touch, its own PID file:
|
||||
|
||||
service ntpd {
|
||||
user = "ntp"
|
||||
group = "ntp"
|
||||
runtime-dir = "ntpd"
|
||||
pidfile = "/run/ntpd/ntpd.pid"
|
||||
command = "/usr/sbin/ntpd -n -p /run/ntpd/ntpd.pid"
|
||||
}
|
||||
|
||||
These settings exist only in the block format.
|
||||
|
||||
Stopping and reloading
|
||||
----------------------
|
||||
|
||||
When stopping a service, either manually or when moving to another
|
||||
runlevel, Finit starts by sending `SIGTERM` to let the process shut
|
||||
down gracefully. If it has not been collected within 3 seconds,
|
||||
`SIGKILL` follows. Both ends of that are configurable:
|
||||
|
||||
* `stop-signal = "SIGPWR"` -- send this instead of `SIGTERM`
|
||||
* `stop-timeout = 10` -- seconds to wait before `SIGKILL`, 1-300
|
||||
|
||||
Some services need more than a signal:
|
||||
|
||||
* `exec-stop = "script [args]"` -- run instead of sending the stop
|
||||
signal, and instead of `stop` for `sysv`
|
||||
* `exec-reload = "script [args]"` -- run instead of sending `SIGHUP`.
|
||||
Like systemd, Finit sets `$MAINPID` as a convenience to scripts,
|
||||
which in effect also allows `exec-reload = "kill -HUP $MAINPID"`
|
||||
|
||||
If a daemon cannot be reloaded with a signal at all, say so and Finit
|
||||
restarts it instead:
|
||||
|
||||
service dropbear {
|
||||
reload-signal = "none"
|
||||
command = "/usr/sbin/dropbear -R -F"
|
||||
}
|
||||
|
||||
`SIGHUP` is the default and the only other accepted value, with or
|
||||
without the `SIG` prefix and in any case.
|
||||
|
||||
Scripts
|
||||
-------
|
||||
|
||||
Services, including the `sysv` variant, support six lifecycle scripts:
|
||||
|
||||
* `exec-start-pre` -- called before the sysv/service is started
|
||||
* `exec-start-ready` -- called when the sysv/service is ready
|
||||
* `exec-stop` -- called instead of the stop signal
|
||||
* `exec-stop-post` -- called after the sysv/service has stopped
|
||||
* `exec-reload` -- called instead of `SIGHUP`
|
||||
* `exec-cleanup` -- called when run/task/sysv/service is removed
|
||||
|
||||
Each takes a matching `-timeout`, in seconds, 0-3600, after which Finit
|
||||
kills the script. It defaults to the `stop-timeout` value and can be
|
||||
disabled by setting it to zero:
|
||||
|
||||
service foo {
|
||||
exec-start-pre = "/etc/foo/pre.sh"
|
||||
exec-start-pre-timeout = 10
|
||||
command = "/usr/sbin/foo"
|
||||
}
|
||||
|
||||
These scripts run as the same user and group as the service itself,
|
||||
with any `envfile` sourced. They 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:
|
||||
The `exec-stop-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
|
||||
@@ -125,11 +320,13 @@ variables. Yes, the text is correct, the naming was an accident:
|
||||
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.
|
||||
When a run/task/sysv/service is removed (disable + reload) it is first
|
||||
stopped and then removed from the runlevel. The `exec-stop-post`
|
||||
script always runs when the process has stopped, and `exec-cleanup`
|
||||
runs when the block 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.
|
||||
> notification. A script that outlives its timeout is killed, so pick
|
||||
> one that suits the work, or set it to zero to opt out and take
|
||||
> responsibility for the script terminating.
|
||||
|
||||
+20
-13
@@ -32,28 +32,35 @@ 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
|
||||
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
|
||||
service watchdogd { notify = "pid" command = "watchdogd" }
|
||||
service foo { notify = "systemd" command = "foo" }
|
||||
service bar { notify = "s6" command = "bar" }
|
||||
service qux { notify = "none" command = "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`.
|
||||
The `notify = "none"` setting 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
|
||||
service watchdogd {
|
||||
notify = "pid"
|
||||
command = "watchdogd"
|
||||
}
|
||||
|
||||
For details on the syntax and options, see below.
|
||||
service stress-ng {
|
||||
conditions = { "service/watchdogd/ready" }
|
||||
command = "stress-ng --cpu 8"
|
||||
}
|
||||
|
||||
For the full list of conditions, see [Finit Conditions](../conditions.md).
|
||||
|
||||
> [!NOTE]
|
||||
> On `initctl reload` conditions are set in "flux", while figuring out
|
||||
@@ -66,7 +73,7 @@ For details on the syntax and options, see below.
|
||||
> 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.)
|
||||
> (Declare the service with `reload-signal = "none"`.)
|
||||
>
|
||||
> For default, PID file style readiness notification, daemons are
|
||||
> expected to either create their PID files, or touch it using
|
||||
|
||||
@@ -7,14 +7,19 @@ 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
|
||||
the wrapper script in the Finit `.conf` service block. 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
|
||||
service program {
|
||||
description = "Example Program"
|
||||
runlevel = "235"
|
||||
reload-signal = "none"
|
||||
command = "/etc/start.d/program"
|
||||
}
|
||||
|
||||
* `/etc/start.d/program:`
|
||||
|
||||
@@ -26,6 +31,6 @@ example employs a wrapper script in `/etc/start.d`.
|
||||
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.
|
||||
> The example sets `reload-signal = "none"` to say the program does not
|
||||
> support `SIGHUP`. Finit then stop/starts the service instead of
|
||||
> signalling it at restart/reload events.
|
||||
|
||||
+236
-81
@@ -1,16 +1,17 @@
|
||||
Services
|
||||
========
|
||||
|
||||
**Syntax:** `service [LVLS] <COND> /path/to/daemon ARGS -- Optional description`
|
||||
**Syntax:** `service NAME { command = "/path/to/daemon ARGS" }`
|
||||
|
||||
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.
|
||||
limits controlling this are configurable, see
|
||||
[Service Options](service-opts.md).
|
||||
|
||||
> [!TIP]
|
||||
> To allow endless restarts, see the [`respawn` option](service-opts.md)
|
||||
> To allow endless restarts, see [`respawn`](service-opts.md#restarting)
|
||||
|
||||
For daemons that support it, we recommend appending `--foreground`,
|
||||
`--no-background`, `-n`, `-F`, or similar command line argument to
|
||||
@@ -19,65 +20,105 @@ 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:
|
||||
are supported using the same syntax as forking `sysv` services, by
|
||||
naming the file to watch with `pidfile`. There is an alternative 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
|
||||
service ntpd {
|
||||
description = "NTP daemon"
|
||||
type = "forking"
|
||||
command = "ntpd"
|
||||
}
|
||||
|
||||
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`.
|
||||
`/var/run/ntpd.pid`. If Finit guesses wrong, name the file yourself
|
||||
with `pidfile = "/path/to/file.pid"`.
|
||||
|
||||
The file belongs to the service: Finit reads it but does not create or
|
||||
remove it. That is the default, and `pidfile-create = true` is what
|
||||
asks Finit to write the file instead. The one exception is *stale*
|
||||
cleanup — if the service dies without removing its own pidfile
|
||||
(SIGKILL, OOM, segfault), and the file still names the just-reaped
|
||||
PID, Finit removes it before the next retry. This prevents daemons
|
||||
that refuse to start on an existing pidfile (e.g. `dbus-daemon`)
|
||||
from getting stuck in a crash-restart loop.
|
||||
|
||||
**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
|
||||
service ospfd {
|
||||
description = "OSPF daemon"
|
||||
runlevel = "2345"
|
||||
conditions = { "pid/zebra" }
|
||||
command = "/sbin/ospfd"
|
||||
}
|
||||
|
||||
`[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.
|
||||
`runlevel` denotes the runlevels `ospfd` is allowed to run in, it is
|
||||
optional and defaults to level 2-4 if omitted.
|
||||
|
||||
`conditions` lists what must be asserted before starting `ospfd`. In
|
||||
this example Finit waits for another service, `zebra`, to have created
|
||||
its PID file in `/var/run/quagga/zebra.pid`. Finit watches *all* files
|
||||
in `/var/run`, for each file named `*.pid`, or `*/pid`, Finit opens it
|
||||
and finds the matching `NAME:ID` using the PID.
|
||||
|
||||
A condition may be prefixed with `~` to propagate a reload of the
|
||||
upstream service to this one, rather than merely pausing and resuming
|
||||
it:
|
||||
|
||||
conditions = { "~pid/zebra" }
|
||||
|
||||
If `ospfd` cannot be reloaded with `SIGHUP` at all, that is a property
|
||||
of `ospfd` and not of the condition, so it is said directly:
|
||||
|
||||
reload-signal = "none"
|
||||
|
||||
The legacy format spells that second one as a `!` leading the condition
|
||||
list, which is not accepted here. 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:
|
||||
application Finit provides a workaround. With `pidfile-create` Finit
|
||||
creates the file when starting and removes it when stopping. The path
|
||||
comes from `pidfile`, which takes three forms:
|
||||
|
||||
pid[:[/path/to/]filename[.pid]]
|
||||
pidfile = true # /var/run/<command basename>.pid
|
||||
pidfile = "bar" # a bare name, /var/run/bar.pid
|
||||
pidfile = "/run/bar.pid" # an explicit path
|
||||
|
||||
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:
|
||||
Such a file is also used by the Finit condition subsystem, so another
|
||||
service, run or task can depend on `pid/bar`. Here foo is not started
|
||||
until bar has:
|
||||
|
||||
service pid:/run/bar.pid bar -- Bar Service
|
||||
service <pid/bar> foo -- Foo Service
|
||||
service bar {
|
||||
description = "Bar Service"
|
||||
pidfile = "/run/bar.pid"
|
||||
pidfile-create = true
|
||||
command = "bar"
|
||||
}
|
||||
|
||||
service foo {
|
||||
description = "Foo Service"
|
||||
conditions = { "pid/bar" }
|
||||
command = "foo"
|
||||
}
|
||||
|
||||
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:
|
||||
and s6 style notification. This is enabled with the `notify` key:
|
||||
|
||||
* `notify:systemd` -- tells Finit the service uses the `sd_notify()`
|
||||
* `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
|
||||
* `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
|
||||
@@ -85,7 +126,11 @@ option:
|
||||
(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
|
||||
service mdevd {
|
||||
runlevel = "S12345789"
|
||||
notify = "s6"
|
||||
command = "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
|
||||
@@ -99,7 +144,13 @@ then service's ready condition which other services can depend on:
|
||||
|
||||
This can be used to synchronize the start of another run/task/service:
|
||||
|
||||
task [S] <service/mdevd/ready> @root:root mdevd-coldplug
|
||||
task mdevd-coldplug {
|
||||
runlevel = "S"
|
||||
conditions = { "service/mdevd/ready" }
|
||||
user = "root"
|
||||
group = "root"
|
||||
command = "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
|
||||
@@ -115,87 +166,191 @@ 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:
|
||||
command should be executed with, using `user`, `group` and
|
||||
`extra-groups`, all optional:
|
||||
|
||||
run [2345] @joe:users logger "Hello world"
|
||||
run hello {
|
||||
runlevel = "2345"
|
||||
user = "joe"
|
||||
group = "users"
|
||||
command = "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`, list them in `extra-groups`:
|
||||
|
||||
service caddy {
|
||||
user = "caddy"
|
||||
group = "caddy"
|
||||
extra-groups = { "ssl-cert" }
|
||||
command = "/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:
|
||||
multiple web servers, add `:ID` to the block title, 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
|
||||
service httpd:80 {
|
||||
description = "Web server"
|
||||
runlevel = "2345"
|
||||
command = "httpd -f -h /http -p 80"
|
||||
}
|
||||
|
||||
Without the `:ID` to the service the latter will overwrite the former
|
||||
and only the old web server would be started and supervised.
|
||||
service httpd:8080 {
|
||||
description = "Old web server"
|
||||
runlevel = "2345"
|
||||
command = "httpd -f -h /http -p 8080"
|
||||
}
|
||||
|
||||
Without the `:ID` the latter will overwrite the former and only the old
|
||||
web server would be started and supervised.
|
||||
|
||||
> [!NOTE]
|
||||
> The line-based format also accepts a bare ID, `service :80 ...`,
|
||||
> deriving the name from the command. There is no block equivalent:
|
||||
> the title carries both name and ID.
|
||||
|
||||
|
||||
Conditional Loading
|
||||
-------------------
|
||||
|
||||
Finit support conditional loading of stanzas. The following example is
|
||||
take from the `system/hotplug.conf` file in the Finit distribution.
|
||||
Finit supports conditional loading of blocks. The following example is
|
||||
taken from the `system/10-hotplug.conf` file in the Finit distribution.
|
||||
Here we only show a simplified subset.
|
||||
|
||||
Starting with the `nowarn` option.
|
||||
Starting with the udev daemon, which goes by two names depending on
|
||||
how it was built. Both are candidates for the same service:
|
||||
|
||||
service nowarn name:udevd pid:udevd /lib/systemd/systemd-udevd
|
||||
service nowarn name:udevd pid:udevd udevd
|
||||
service udevd {
|
||||
pidfile = "udevd"
|
||||
command = { "/lib/systemd/systemd-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`.
|
||||
When loading the .conf file Finit looks for
|
||||
`/lib/systemd/systemd-udevd`, and if that is not there it moves on to
|
||||
`udevd`. A candidate that is not installed is expected, so no warning
|
||||
is logged for the ones that are skipped. The leading `-` on the last
|
||||
one says it is also fine if none of them are found, in which case the
|
||||
block is dropped quietly and no service named `udevd` exists.
|
||||
|
||||
run nowarn if:udevd <pid/udevd> :1 udevadm settle -t 0
|
||||
> [!NOTE]
|
||||
> This needs to be one block. The title is the service identity, so
|
||||
> two blocks titled `udevd` in the same file are two declarations of
|
||||
> one service, which Finit rejects. See [Duplicate
|
||||
> titles](service-opts.md#duplicate-titles).
|
||||
|
||||
This line is only loaded if we know of a service named `udevd`. Again,
|
||||
run udevadm:1 {
|
||||
runlevel = "S"
|
||||
if = "udevd"
|
||||
conditions = { "pid/udevd" }
|
||||
command = "-udevadm settle -t 0"
|
||||
}
|
||||
|
||||
This block 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
|
||||
run mdev {
|
||||
description = "Populating device tree"
|
||||
runlevel = "S"
|
||||
conflicts = { "udevd" }
|
||||
command = "-mdev -s"
|
||||
}
|
||||
|
||||
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:
|
||||
Conditional loading can also be negated, so the previous block can be
|
||||
written as:
|
||||
|
||||
run nowarn if:!udevd [S] mdev -s -- Populating device tree
|
||||
run mdev {
|
||||
description = "Populating device tree"
|
||||
runlevel = "S"
|
||||
if = "!udevd"
|
||||
command = "-mdev -s"
|
||||
}
|
||||
|
||||
The reason for using `conflict` in this example is that a conflict can be
|
||||
resolved. Stanzas marked with `conflict:foo` are rechecked at runtime.
|
||||
The reason for using `conflicts` in this example is that a conflict can
|
||||
be resolved. Blocks naming a conflict are rechecked at runtime.
|
||||
|
||||
|
||||
Conditional Execution
|
||||
---------------------
|
||||
|
||||
Similar to conditional loading of stanzas there is conditional runtime
|
||||
Similar to conditional loading of blocks 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.
|
||||
runlevel. E.g., a task with `runlevel = "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
|
||||
run startup {
|
||||
runlevel = "S"
|
||||
conditions = { "pid/sysrepo" }
|
||||
command = "confd -b --load startup-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`.
|
||||
run failure {
|
||||
runlevel = "S"
|
||||
if = "usr/fail-startup"
|
||||
conditions = { "pid/sysrepo" }
|
||||
command = "confd --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.
|
||||
The two run blocks 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 one to load
|
||||
`failure-config`.
|
||||
|
||||
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:
|
||||
Notice the critical difference between the `conditions` list and `if`.
|
||||
The former is a condition for starting; the latter is a condition to
|
||||
check whether a run/task/service is qualified to even be considered.
|
||||
`if` has a negation of its own, `!`, which is unrelated to anything in
|
||||
the `conditions` list.
|
||||
|
||||
run [S] if:<!usr/startup-ok> name:failure <pid/sysrepo> confd ...
|
||||
What `if` compares against depends on the value. A namespace
|
||||
separator makes it a condition, anything else is a service name:
|
||||
|
||||
| `if` | Asks |
|
||||
|---|---|
|
||||
| `"udevd"` | is a service by this name known? |
|
||||
| `"usr/foo"` | was this condition set? |
|
||||
|
||||
Both are questions about whether the block belongs in the running
|
||||
configuration at all, usually answered from what bootstrap established.
|
||||
A statement is all of one kind or the other, so the block is rejected
|
||||
if you mix them.
|
||||
|
||||
> [!NOTE]
|
||||
> `if` qualifies, it does not track. A condition asserted or cleared
|
||||
> later does not start or stop the service by itself -- that is what
|
||||
> the `conditions` list is for.
|
||||
|
||||
Conditional execution can also be negated, so provided the file loaded
|
||||
did the opposite, i.e., set a condition on success, the previous block
|
||||
can be written as:
|
||||
|
||||
run failure {
|
||||
runlevel = "S"
|
||||
if = "!usr/startup-ok"
|
||||
conditions = { "pid/sysrepo" }
|
||||
command = "confd ..."
|
||||
}
|
||||
|
||||
Variants of one service are often qualified this way, one per platform,
|
||||
and they usually have to supply the same barrier to whatever waits for
|
||||
them. Each variant needs its own title, since a title is an identity,
|
||||
and the shared barrier is named with `provides`. See [Provided
|
||||
Conditions](service-opts.md#provided-conditions).
|
||||
|
||||
+26
-17
@@ -9,42 +9,45 @@ from a serialized boot process.
|
||||
SysV Init Scripts
|
||||
-----------------
|
||||
|
||||
**Syntax:** `sysv [LVLS] <COND> /path/to/init-script -- Optional description`
|
||||
**Syntax:** `sysv NAME { command = "/path/to/init-script" }`
|
||||
|
||||
> `<COND>` is described in the [Services](services.md) section.
|
||||
> [!NOTE]
|
||||
> Conditions, runlevels, and the other settings a `sysv` block takes
|
||||
> are described in [Service Options](service-opts.md).
|
||||
|
||||
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.
|
||||
A `sysv` block is a supervised daemon, like `service`, but started and
|
||||
stopped through a SysV style init script instead of a command line. The
|
||||
intention is to reuse existing setup and init scripts from 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
|
||||
the Finit .conf, where the `sysv` block is declared, is modified, Finit
|
||||
calls `init-script restart` on `initctl reload`. Similar to how
|
||||
`service` stanzas work.
|
||||
`service` blocks 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`.
|
||||
by declaring the PID file to look for: `pidfile = "/path/to/file.pid"`.
|
||||
Finit does not create that file, it watches it for the resulting
|
||||
forked-off PID. That is the default; `pidfile-create = true` asks Finit
|
||||
to write it instead. The same applies to forking daemons with no way to
|
||||
run in the foreground, see [Services](services.md).
|
||||
|
||||
> [!TIP]
|
||||
> See also [SysV Init Compatibility](#sysv-init-compatibility).
|
||||
|
||||
`runparts DIRECTORY`
|
||||
--------------------
|
||||
Run-parts
|
||||
---------
|
||||
|
||||
For a directory with traditional start/stop scripts that should run, in
|
||||
order, at bootstrap, Finit provides the `runparts` directive. It runs
|
||||
order, at bootstrap, Finit provides the `runparts` setting. 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
|
||||
runparts = "/etc/rc2.d"
|
||||
|
||||
Files in these directories are usually named `SNNfoo` and `KNNfoo`,
|
||||
which Finit knows about and automatically appends the correct argument:
|
||||
@@ -64,7 +67,12 @@ 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
|
||||
sysv inetd {
|
||||
description = "OpenBSD inet daemon"
|
||||
runlevel = "2345"
|
||||
conditions = { "pid/syslogd" }
|
||||
command = "/etc/init.d/openbsd-inetd"
|
||||
}
|
||||
|
||||
The init script header could be parsed to extract `Default-Start:` and
|
||||
other parameters for the `sysv` command to Finit. There is currently no
|
||||
@@ -83,6 +91,7 @@ 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).
|
||||
|
||||
> [!NOTE]
|
||||
> In Finit releases before v4.5 this script blocked Finit execution and
|
||||
> made it as good as impossible to call `initctl` during that time.
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
run (sequence)
|
||||
--------------
|
||||
|
||||
**Syntax:** `run [LVLS] <COND> /path/to/cmd ARGS -- Optional description`
|
||||
**Syntax:** `run NAME { command = "/path/to/cmd ARGS" }`
|
||||
|
||||
> `<COND>` is described in the [Services](services.md) section.
|
||||
> Conditions, runlevels, and the other settings a `run` block takes are
|
||||
> described in [Service Options](service-opts.md).
|
||||
|
||||
One-shot command to run in sequence when entering a runlevel, with
|
||||
optional arguments and description. `run` commands are guaranteed to be
|
||||
@@ -31,16 +32,70 @@ also the `--quiet` and `--batch` options.
|
||||
task (parallel)
|
||||
---------------
|
||||
|
||||
**Syntax:** `task [LVLS] <COND> /path/to/cmd ARGS -- Optional description`
|
||||
**Syntax:** `task NAME { command = "/path/to/cmd ARGS" }`
|
||||
|
||||
> `<COND>` is described in the [Services](services.md) section.
|
||||
> A `task` block takes the same settings as `run`, see
|
||||
> [Service Options](service-opts.md).
|
||||
|
||||
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
|
||||
task bar {
|
||||
runlevel = "S"
|
||||
command = "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-after-exit
|
||||
-----------------
|
||||
|
||||
By default, a `run` or `task` will re-run each time its runlevel is
|
||||
entered, and its `exec-stop-post` script does not run on completion.
|
||||
|
||||
With `remain-after-exit`, the task runs once and does not re-run on
|
||||
runlevel re-entry:
|
||||
|
||||
task firewall {
|
||||
description = "Firewall setup"
|
||||
runlevel = "2345"
|
||||
remain-after-exit = true
|
||||
command = "/usr/sbin/setup-firewall"
|
||||
}
|
||||
|
||||
This has the following effects:
|
||||
|
||||
* The task does not re-run on runlevel re-entry
|
||||
* The `exec-stop-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 firewall {
|
||||
description = "Firewall setup"
|
||||
runlevel = "2345"
|
||||
remain-after-exit = true
|
||||
exec-stop-post = "/usr/sbin/teardown-firewall"
|
||||
command = "/usr/sbin/setup-firewall"
|
||||
}
|
||||
```
|
||||
|
||||
The firewall rules are created once. The `exec-stop-post` script runs when
|
||||
entering runlevel 0 (halt) or 6 (reboot), or on explicit stop.
|
||||
|
||||
> [!NOTE]
|
||||
> The `remain-after-exit` setting is not supported for bootstrap-only
|
||||
> tasks (tasks with only runlevel S). Bootstrap tasks are deleted
|
||||
> immediately after completion, and their `exec-stop-post` scripts never
|
||||
> run. A warning is logged if `remain-after-exit` is used on such tasks.
|
||||
|
||||
@@ -5,16 +5,20 @@ 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
|
||||
service avahi-autoipd:%i {
|
||||
description = "ZeroConf for %i"
|
||||
command = "avahi-autoipd --syslog %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:
|
||||
instance of `%i` will be replaced with `eth0` before the file is
|
||||
parsed, so it works in the block title, in any value, and in the
|
||||
command line alike. Inspect the result with `initctl show
|
||||
avahi-autoipd:eth0`, and check a running instance with:
|
||||
|
||||
```
|
||||
$ initctl status avahi-autoipd:eth0
|
||||
|
||||
+115
-34
@@ -1,67 +1,99 @@
|
||||
TTYs and Consoles
|
||||
=================
|
||||
|
||||
**Syntax:** `tty [LVLS] <COND> DEV [BAUD] [noclear] [nowait] [nologin] [TERM]`
|
||||
`tty [LVLS] <COND> CMD <ARGS> [noclear] [nowait]`
|
||||
`tty [LVLS] <COND> [notty] [rescue]`
|
||||
**Syntax:** `tty NAME { device = DEV }` -- built-in getty
|
||||
`tty NAME { command = "CMD ARGS" }` -- external getty
|
||||
`tty NAME { notty = true }`, or `{ rescue = true }` -- bare shell, no device
|
||||
|
||||
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 block title NAME is what `initctl` shows. The three variants differ
|
||||
in what they open: `device` runs the built-in getty on that TTY, and DEV
|
||||
may be the special keyword `@console`, expanded from
|
||||
`/sys/class/tty/console/active`, useful on embedded systems. `command`
|
||||
hands the TTY to an external getty. `notty` opens nothing at all.
|
||||
|
||||
The default baud rate is 0, i.e., keep kernel default.
|
||||
`command` may name several candidates, `{ "agetty ...", "getty ..." }`,
|
||||
and Finit runs the first one it finds. See [Command
|
||||
Candidates](service-opts.md#command-candidates).
|
||||
|
||||
> The `tty` stanza inherits runlevel, condition (and other feature)
|
||||
> parsing from the `service` stanza. So TTYs can run in one or many
|
||||
Settings common to all three:
|
||||
|
||||
| Setting | Alias | Description |
|
||||
|---|---|---|
|
||||
| `runlevel` | | Runlevels to run in, e.g. `"12345"` |
|
||||
| `conditions` | `cond` | Conditions to wait for |
|
||||
| `noclear` | | Do not clear the TTY after each session |
|
||||
| `nowait` | | Do not wait for Enter before the login prompt |
|
||||
| `nologin` | | Skip login, give a shell straight away |
|
||||
| `passenv` | | Pass the environment on to `login`, built-in getty only |
|
||||
|
||||
The `device` variant takes two more:
|
||||
|
||||
| Setting | Description |
|
||||
|---|---|
|
||||
| `baud` | Baud rate, default 0, i.e., keep kernel default |
|
||||
| `term` | `$TERM` value, e.g. `"vt220"` |
|
||||
|
||||
> A `tty` block inherits runlevel, condition (and other feature)
|
||||
> parsing from the `service` block. 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
|
||||
tty ttyAMA0 {
|
||||
runlevel = "12345"
|
||||
device = "/dev/ttyAMA0"
|
||||
baud = 115200
|
||||
term = "vt220"
|
||||
noclear = true
|
||||
}
|
||||
|
||||
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.
|
||||
device node is required, the same output the kernel uses is reused for
|
||||
stdio. With `notty` a shell is started (`nologin`, `noclear`, and
|
||||
`nowait` are implied); with `rescue` the bundled
|
||||
`/libexec/finit/sulogin` presents 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
|
||||
tty getty {
|
||||
runlevel = "12345"
|
||||
command = "/sbin/getty -L 115200 /dev/ttyAMA0 vt100"
|
||||
}
|
||||
|
||||
The `noclear` option disables clearing the TTY after each session.
|
||||
tty agetty {
|
||||
runlevel = "12345"
|
||||
command = "/sbin/agetty -L ttyAMA0 115200 vt100"
|
||||
nowait = true
|
||||
}
|
||||
|
||||
The `noclear` setting 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`
|
||||
The `nowait` setting 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.
|
||||
The `nologin` setting disables getty and `/bin/login`, and gives the
|
||||
user a root (login) shell on the given TTY 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
|
||||
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`. The speed
|
||||
can be omitted to keep the kernel default.
|
||||
it out by querying sysfs: `/sys/class/tty/console/active`. Leave
|
||||
`baud` out 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,
|
||||
@@ -69,18 +101,67 @@ can be omitted to keep the kernel default.
|
||||
|
||||
**Example:**
|
||||
|
||||
tty [12345] @console noclear vt220
|
||||
tty console {
|
||||
runlevel = "12345"
|
||||
device = "@console"
|
||||
term = "vt220"
|
||||
noclear = true
|
||||
}
|
||||
|
||||
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
|
||||
tty board {
|
||||
runlevel = "12345789"
|
||||
notty = true
|
||||
}
|
||||
|
||||
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:
|
||||
One can also use a `service` block to start a stand-alone shell:
|
||||
|
||||
service [12345] /bin/sh -l
|
||||
service shell {
|
||||
runlevel = "12345"
|
||||
command = "/bin/sh -l"
|
||||
}
|
||||
|
||||
Controlling TTY for Services
|
||||
----------------------------
|
||||
|
||||
The `tty` setting gives a `run`, `task`, or `service` a controlling
|
||||
terminal on the given device. The device is opened, set as the
|
||||
controlling terminal for the session (after `setsid()`), and connected to
|
||||
the process's stdin, stdout, and stderr. A default `TERM` environment
|
||||
variable is set based on the device type: `vt102` for serial lines and
|
||||
`linux` for virtual terminals.
|
||||
|
||||
The value may be a device node like `/dev/ttyS0`, or the special
|
||||
keyword `@console` (see above). Note that `@console` expands only to
|
||||
the first console, not all.
|
||||
|
||||
When `tty` is combined with a `log` block, stdout and stderr are
|
||||
redirected to the log sink instead of the TTY, but stdin remains
|
||||
connected to the TTY device.
|
||||
|
||||
> The `tty` setting is for `run`, `task`, and `service` blocks only.
|
||||
> A `tty` block (for getty/login) is a different thing entirely, see
|
||||
> above.
|
||||
|
||||
**Example:**
|
||||
|
||||
service foo {
|
||||
description = "Foo on serial console"
|
||||
runlevel = "2345"
|
||||
tty = "/dev/ttyS0"
|
||||
command = "/usr/sbin/foo"
|
||||
}
|
||||
|
||||
task setup {
|
||||
description = "Board bringup on console"
|
||||
runlevel = "S"
|
||||
tty = "@console"
|
||||
command = "my-setup-script"
|
||||
}
|
||||
+375
@@ -0,0 +1,375 @@
|
||||
D-Bus Integration
|
||||
=================
|
||||
|
||||
Finit ships with a built-in, brokerless [D-Bus][] implementation, **libink**
|
||||
(`-link`), that exposes the running init system as a peer on its own private
|
||||
bus, and optionally on the system bus when `dbus-daemon` is available.
|
||||
Everything `initctl` does is also reachable from any generic D-Bus tooling —
|
||||
`dbus-send`, `dbus-monitor`, `gdbus`, language bindings, dashboards,
|
||||
monitoring agents, etc.
|
||||
|
||||
> [!NOTE]
|
||||
> D-Bus support is enabled by default, opt out at build time with
|
||||
> `--disable-dbus`, see [Building](build.md) for details. When disabled,
|
||||
> `initctl` keeps using the legacy `INIT_SOCKET` transport and Finit
|
||||
> exposes no bus.
|
||||
|
||||
Bus address
|
||||
-----------
|
||||
|
||||
| Bus | Address |
|
||||
|------------------------|---------------------------------------------|
|
||||
| Local (always) | `unix:path=/run/finit/bus` |
|
||||
| System (opportunistic) | `unix:path=/var/run/dbus/system_bus_socket` |
|
||||
|
||||
The bundled device manager serves its own `org.finit.Device1` the same
|
||||
way on `unix:path=/run/keventd/bus`, see [keventd](keventd.md); one
|
||||
socket per daemon, no forwarding between them.
|
||||
|
||||
The **local** bus is brokerless: clients connect straight to Finit over a
|
||||
Unix-domain socket using the standard D-Bus SASL EXTERNAL handshake. No
|
||||
`dbus-daemon` is required, which makes it suitable for embedded systems that
|
||||
don't ship one.
|
||||
|
||||
The socket is `0660`, owned by `root` and the group given to
|
||||
`--with-group` at build time, the same gate as `/run/finit/socket` that
|
||||
`initctl` falls back on. The bus reaches every operation `initctl`
|
||||
does, so restricting one and not the other would leave the door open.
|
||||
Members of that group may use it, see [Authorization](#authorization).
|
||||
|
||||
Finit accepts at most 64 concurrent local-bus peers; further
|
||||
connections are refused until one disconnects. Match rules given to
|
||||
`AddMatch` support the `type`, `interface`, `member`, and `path` keys;
|
||||
`arg0` and its variants are not implemented.
|
||||
|
||||
For the system bus a standard busconfig policy ships in
|
||||
`dbus-1/org.finit.conf`, installed to `$datadir/dbus-1/system.d`: only
|
||||
root may own `org.finit`, unprivileged callers reach introspection,
|
||||
properties, and the read-only methods.
|
||||
Finit also enforces per-method authorization itself, so a permissive
|
||||
policy installed by mistake does not open state-changing methods.
|
||||
|
||||
The **system** bus is best-effort: Finit probes for a running `dbus-daemon`
|
||||
and, when reachable, claims the well-known name `org.finit` so that standard
|
||||
tooling sees Finit just like any other system service:
|
||||
|
||||
```sh
|
||||
dbus-send --system --print-reply --dest=org.finit /org/finit/manager \
|
||||
org.finit.Manager1.ListServices
|
||||
|
||||
dbus-monitor --system "sender='org.finit'"
|
||||
```
|
||||
|
||||
If no system bus is present (the common case on embedded targets), this step
|
||||
is silently skipped.
|
||||
|
||||
Object tree
|
||||
-----------
|
||||
|
||||
```
|
||||
/
|
||||
├── org/
|
||||
│ └── finit/
|
||||
│ ├── manager Manager1
|
||||
│ ├── cond Cond1
|
||||
│ └── service/
|
||||
│ ├── keventd Service1 (one per service)
|
||||
│ ├── sshd
|
||||
│ └── …
|
||||
└── org/freedesktop/DBus Standard well-known interfaces
|
||||
```
|
||||
|
||||
Every node implements the usual stock interfaces:
|
||||
|
||||
| Interface | Purpose |
|
||||
|---------------------------------------|-------------------------------------------|
|
||||
| `org.freedesktop.DBus` | `Hello`, `AddMatch`, `RemoveMatch` — on `/org/freedesktop/DBus` only |
|
||||
| `org.freedesktop.DBus.Peer` | `Ping`, `GetMachineId` |
|
||||
| `org.freedesktop.DBus.Introspectable` | `Introspect()` — XML description |
|
||||
| `org.freedesktop.DBus.Properties` | `Get`, `GetAll`; nothing is writable |
|
||||
|
||||
Note: `Hello`, `AddMatch`, and `RemoveMatch` are answered on the canonical
|
||||
`/org/freedesktop/DBus` object only, as per the D-Bus specification.
|
||||
|
||||
`org.finit.Manager1`
|
||||
--------------------
|
||||
|
||||
Lives at **`/org/finit/manager`**. Owns the global init operations
|
||||
and the service registry.
|
||||
|
||||
### Methods
|
||||
|
||||
| Method | In sig | Out sig | Priv. | Notes |
|
||||
|------------------------------|--------|---------|-------|-----------------------------------------------------------|
|
||||
| `ListServices` | — | `as` | no | Returns identities (`name`, `name:id`) of loaded services |
|
||||
| `GetService` | `s` | `o` | no | Resolves an identity to its `Service1` object path |
|
||||
| `Start` | `s` | — | yes | Start the service(s) matching the identity |
|
||||
| `Stop` | `s` | — | yes | Stop the service(s) matching the identity |
|
||||
| `Restart` | `s` | — | yes | Restart (stop + start) the service(s) |
|
||||
| `Reload` | — | — | yes | Re-read all `*.conf` and apply changes |
|
||||
| `SetRunlevel` | `u` | — | yes | Transition to runlevel `u` (0–9) |
|
||||
| `SetDebug` | — | — | yes | Toggle Finit's runtime debug flag |
|
||||
| `Signal` | `su` | — | yes | Send signal `u` (1–31) to services matching identity `s` |
|
||||
| `Suspend` | — | — | yes | `sync()` + suspend-to-RAM |
|
||||
| `Reboot`, `Halt`, `Poweroff` | `u` | — | yes | Trigger the corresponding shutdown sequence; the argument arms the emergency fallback timer (seconds, 0 = none) |
|
||||
|
||||
Edge cases follow the legacy `initctl` protocol: `Suspend` and the
|
||||
reboot family reply `WrongRunlevel` during bootstrap and shutdown,
|
||||
`SetRunlevel` is a warning + no-op in runlevel 0/6 and records the
|
||||
level for the end of bootstrap in runlevel S, and `Signal` fails for
|
||||
stopped services. One deliberate divergence: a `SetRunlevel` argument
|
||||
outside 0–9 returns `InvalidArgs`, where the legacy protocol
|
||||
acknowledges silently.
|
||||
|
||||
### Properties
|
||||
|
||||
All read-only strings; observable via `Properties.Get` and
|
||||
`Properties.GetAll`.
|
||||
|
||||
| Property | Type | Returns |
|
||||
|----------------|------|--------------------------------------------------------|
|
||||
| `Runlevel` | `s` | Current runlevel as a digit (`"2"`, `"3"`, …) or `"S"` |
|
||||
| `PrevRunlevel` | `s` | Previous runlevel, same encoding, `"N"` when none |
|
||||
| `Version` | `s` | Finit's version string (`PACKAGE_VERSION`) |
|
||||
|
||||
### Signals
|
||||
|
||||
| Signal | Body | Fires when |
|
||||
|-----------------------|----------------------------------------|------------------------|
|
||||
| `ServiceStateChanged` | `sss` — identity, old state, new state | Service transitions |
|
||||
| `RunlevelChanged` | `ss` — old level, new level | System runlevel change |
|
||||
| `ConfigReloaded` | — | `initctl reload` completed; providers of generation-file conditions re-assert |
|
||||
|
||||
State names emitted by `ServiceStateChanged` are stable wire strings:
|
||||
`halted`, `done`, `dead`, `cleanup`, `teardown`, `stopping`, `setup`,
|
||||
`paused`, `waiting`, `starting`, `running`. `RunlevelChanged` levels
|
||||
use the same encoding as the `Runlevel` property: digits, `"S"`, `"N"`.
|
||||
|
||||
`org.finit.Service1` (per-service objects)
|
||||
------------------------------------------
|
||||
|
||||
Lives at **`/org/finit/service/<encoded>`**, one object per loaded service.
|
||||
`<encoded>` is the service identity (name, or `name:id` for templated
|
||||
services) put through systemd-style `_HH` hex escaping — ASCII alphanumerics
|
||||
and `_` pass through, anything else becomes `_HH` where `HH` is the hex byte.
|
||||
Use `Manager1.GetService(identity)` to look up the exact path rather than
|
||||
constructing it by hand.
|
||||
|
||||
| Method | In sig | Out sig | Priv. | Notes |
|
||||
|-----------|--------|---------|-------|-------------------------------------------------------------|
|
||||
| `Start` | — | — | yes | Equivalent to `Manager1.Start(<identity>)` for this service |
|
||||
| `Stop` | — | — | yes | … |
|
||||
| `Restart` | — | — | yes | … |
|
||||
| `Reload` | — | — | yes | Send the service's `reload-signal`, default `SIGHUP`; restart when set to `"none"` |
|
||||
|
||||
### Properties
|
||||
|
||||
All read-only; observable via `Properties.Get` and `Properties.GetAll`.
|
||||
|
||||
| Property | Type | Returns |
|
||||
|-----------------|------|----------------------------------------------------------------|
|
||||
| `Identity` | `s` | Service identity, `name` or `name:id` |
|
||||
| `Name` | `s` | Program name (basename of the command) |
|
||||
| `State` | `s` | Current status, same vocabulary as `initctl status` |
|
||||
| `Pid` | `u` | Current PID, 0 when not running |
|
||||
| `RestartCount` | `u` | Restarts since the last stable run |
|
||||
| `Runlevels` | `u` | Allowed runlevels as a bitmask, bit N = runlevel N, bit 10 = S |
|
||||
| `Description` | `s` | The service's `description` string |
|
||||
| `Command` | `s` | Full command line, arguments included |
|
||||
| `Conditions` | `s` | Declared conditions, raw `.conf` form |
|
||||
| `Type` | `s` | Unit type: `service`, `task`, `run`, `sysv`, `tty`, `free` |
|
||||
| `Origin` | `s` | Source `.conf` file, empty for built-ins |
|
||||
| `Environment` | `s` | The service's `env` setting, raw |
|
||||
| `PidFile` | `s` | Declared PID file, raw (`!` prefix included) |
|
||||
| `User` | `s` | User the service runs as |
|
||||
| `Group` | `s` | Group the service runs as |
|
||||
| `Uptime` | `u` | Seconds since start, 0 when not running |
|
||||
| `ExitStatus` | `u` | Raw `waitpid(2)` status from the last exit |
|
||||
| `RestartsTotal` | `u` | Restarts over the service's lifetime |
|
||||
| `RestartMax` | `u` | Restart limit before the service is blocked |
|
||||
| `Starts` | `u` | Times started, for `manual-start` units |
|
||||
| `ManualStart` | `b` | `manual-start` set in the `.conf` |
|
||||
| `Forking` | `b` | Daemon forks to background |
|
||||
| `Started` | `b` | Run/task completed successfully |
|
||||
|
||||
On every state transition the object also emits the standard
|
||||
`org.freedesktop.DBus.Properties.PropertiesChanged` signal: `State`
|
||||
in the changed dictionary, `Pid` and `RestartCount` invalidated (call
|
||||
`Get` for fresh values).
|
||||
|
||||
The per-service surface lets generic tooling supply an object handle
|
||||
once and then invoke methods on it, instead of repeatedly passing the
|
||||
identity string.
|
||||
|
||||
`org.finit.Cond1`
|
||||
-----------------
|
||||
|
||||
Lives at **`/org/finit/cond`**. Exposes Finit's
|
||||
[condition system](conditions.md) to bus clients.
|
||||
|
||||
### Methods
|
||||
|
||||
| Method | In sig | Out sig | Priv. | Notes |
|
||||
|---------|--------|---------|-------|--------------------------------------------------------------|
|
||||
| `Get` | `s` | `s` | no | Returns `"on"`, `"off"`, or `"flux"` for the named condition |
|
||||
| `Set` | `s` | — | yes | Assert a `usr/<name>` condition |
|
||||
| `Clear` | `s` | — | yes | Deassert a `usr/<name>` condition |
|
||||
| `List` | — | `as` | no | Names of all known conditions |
|
||||
| `Dump` | — | `a(ss)` | no | `(name, state)` pairs for everything `List` returns |
|
||||
|
||||
Note: non-`usr/*` paths are rejected with `InvalidArgs` -- system
|
||||
conditions belong to Finit's state machine.
|
||||
|
||||
A service consuming such a condition:
|
||||
|
||||
service alarm {
|
||||
description = "Foo alarm"
|
||||
runlevel = "2345"
|
||||
conditions = { "usr/data-ready" }
|
||||
command = "alarm --arg foo"
|
||||
}
|
||||
|
||||
asserted from any bus client with `Cond1.Set string:"data-ready"`, see
|
||||
the examples below.
|
||||
|
||||
### Signals
|
||||
|
||||
| Signal | Body | Fires when |
|
||||
|--------------------|------------------------|---------------------------------------|
|
||||
| `ConditionChanged` | `ss` — name, new state | A condition is asserted or deasserted |
|
||||
|
||||
Authorization
|
||||
-------------
|
||||
|
||||
Privileged methods accept `root`, and any caller belonging to the group given
|
||||
to `--with-group` at build time. That is the same set the socket mode already
|
||||
admits, so the two gates agree instead of the socket letting the group in and
|
||||
every method turning it away.
|
||||
|
||||
On the **local** bus the kernel settles this at `connect()`: `SO_PEERCRED`
|
||||
gives Finit the caller's uid and `SO_PEERGROUPS` its group set, both straight
|
||||
from the kernel. Finit matches the group against `--with-group` itself, so
|
||||
the check never touches NSS -- `getpwuid`/`getgrouplist` can block on a slow
|
||||
LDAP or SSSD backend, and PID 1 must never block. Because the group set is
|
||||
the caller's real credentials, privilege escalation through the bus is
|
||||
impossible.
|
||||
|
||||
On the **system** bus one connection carries every caller, so `SO_PEERCRED`
|
||||
describes `dbus-daemon` rather than whoever asked. Finit asks the bus driver
|
||||
`GetConnectionUnixUser` about the message sender and holds the call until the
|
||||
answer arrives -- nothing blocks, the reply comes back through the same event
|
||||
loop as everything else. The broker does not report the caller's groups in
|
||||
that reply, so **privileged methods over the system bus are root-only**; group
|
||||
membership is honoured on the local bus only. Lifting that is future work,
|
||||
see `libink/README.md`.
|
||||
|
||||
Answers are cached per sender. A bus never reuses a unique name while it
|
||||
runs, so an answer holds for as long as that bus does; Finit empties the cache
|
||||
when the broker goes away, since a new one numbers its clients from scratch.
|
||||
A caller Finit cannot identify is refused, so the failure mode is a denial
|
||||
rather than an escalation.
|
||||
|
||||
When a privileged method is rejected the error name is exactly
|
||||
`org.freedesktop.DBus.Error.AccessDenied`, and the body carries a short reason
|
||||
string.
|
||||
|
||||
`initctl` integration
|
||||
---------------------
|
||||
|
||||
`initctl` transparently routes through D-Bus when the bus socket is present,
|
||||
and falls back to the legacy `INIT_SOCKET` transport otherwise. Concretely,
|
||||
the following subcommands use the bus first:
|
||||
|
||||
| Subcommand | Method |
|
||||
|----------------------------|--------------------------------------------------|
|
||||
| `initctl start` | `Manager1.Start(svc)` |
|
||||
| `initctl stop` | `Manager1.Stop(svc)` |
|
||||
| `initctl restart` | `Manager1.Restart(svc)` |
|
||||
| `initctl reload` | `Manager1.Reload()` |
|
||||
| `initctl reload S` | `Service1.Reload()` (per-svc) |
|
||||
| `initctl reboot` | `Manager1.Reboot(timeout)` |
|
||||
| `initctl halt` | `Manager1.Halt(timeout)` |
|
||||
| `initctl poweroff` | `Manager1.Poweroff(timeout)` |
|
||||
| `initctl suspend` | `Manager1.Suspend()` |
|
||||
| `initctl debug` | `Manager1.SetDebug()` |
|
||||
| `initctl signal` (or `kill`) | `Manager1.Signal(svc, signo)` |
|
||||
| `initctl runlevel` | `Properties.Get(Manager1.Runlevel/PrevRunlevel)` |
|
||||
| `initctl cond set/get/clear` | `Cond1.{Set,Get,Clear}`, `clr` is an alias |
|
||||
|
||||
Two `initctl` subcommands are pure D-Bus features without legacy equivalents:
|
||||
|
||||
* `initctl monitor` — subscribes to every signal on the local bus and prints
|
||||
one line per delivery (with timestamp, interface and member). Same idea as
|
||||
`dbus-monitor`, but scoped to Finit and with no need to pass `--address`.
|
||||
|
||||
* `initctl cond` emits the standard `Cond1.ConditionChanged` signal as a side
|
||||
effect, so subscribers observe user-driven state changes the same way they
|
||||
observe service-driven ones.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
The examples below use `dbus-send` and `dbus-monitor`, which ship as part of
|
||||
the [dbus][] reference implementation; they're widely packaged and don't pull
|
||||
in any extra runtime. Any tool that speaks D-Bus over an AF_UNIX socket works
|
||||
equally well — `gdbus`, Python's `jeepney`/`dasbus`, etc. — substitute their
|
||||
syntax for setting the bus address. The wire protocol is the compatibility
|
||||
surface: Finit's own **libink** is an internal implementation detail, external
|
||||
clients should use any standard D-Bus library.
|
||||
|
||||
When `org.finit` is registered on the system bus you can replace
|
||||
`--address=unix:path=/run/finit/bus` with `--system` in any example below.
|
||||
|
||||
List the running services:
|
||||
|
||||
```sh
|
||||
dbus-send --address=unix:path=/run/finit/bus \
|
||||
--type=method_call --print-reply --dest=org.finit \
|
||||
/org/finit/manager \
|
||||
org.finit.Manager1.ListServices
|
||||
```
|
||||
|
||||
Read the current runlevel via the Properties interface:
|
||||
|
||||
```sh
|
||||
dbus-send --address=unix:path=/run/finit/bus \
|
||||
--type=method_call --print-reply --dest=org.finit \
|
||||
/org/finit/manager \
|
||||
org.freedesktop.DBus.Properties.Get \
|
||||
string:org.finit.Manager1 string:Runlevel
|
||||
```
|
||||
|
||||
Subscribe to every state change on the manager object:
|
||||
|
||||
```sh
|
||||
dbus-monitor --address=unix:path=/run/finit/bus \
|
||||
"type='signal',interface='org.finit.Manager1'"
|
||||
```
|
||||
|
||||
Or use `initctl monitor`, which does the same without any address
|
||||
plumbing.
|
||||
|
||||
Restart a service by its object path:
|
||||
|
||||
```sh
|
||||
dbus-send --address=unix:path=/run/finit/bus \
|
||||
--type=method_call --dest=org.finit \
|
||||
/org/finit/service/sshd \
|
||||
org.finit.Service1.Restart
|
||||
```
|
||||
|
||||
Trigger a `usr/`-condition assertion that wakes any dependent service:
|
||||
|
||||
```sh
|
||||
dbus-send --address=unix:path=/run/finit/bus \
|
||||
--type=method_call --dest=org.finit \
|
||||
/org/finit/cond \
|
||||
org.finit.Cond1.Set string:"data-ready"
|
||||
```
|
||||
|
||||
The `--dest=org.finit` argument is informational on the local
|
||||
brokerless bus — Finit accepts any destination because there's no
|
||||
broker to route by name — but `dbus-send` requires it syntactically.
|
||||
|
||||
[dbus]: https://gitlab.freedesktop.org/dbus/dbus
|
||||
[D-Bus]: https://dbus.freedesktop.org/doc/dbus-specification.html
|
||||
+105
-46
@@ -1,80 +1,139 @@
|
||||
Distro Recommendations
|
||||
======================
|
||||
|
||||
By default Finit uses the following directories for configuration files:
|
||||
Finit supports two directory layouts for managing service configurations:
|
||||
|
||||
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/
|
||||
|-- finit.d/ -- Regular (enabled) services
|
||||
|-- finit.d/ -- All enabled services
|
||||
| |-- lighttpd.conf
|
||||
| `- *.conf
|
||||
|-- finit.conf -- Bootstrap tasks and services
|
||||
:
|
||||
```
|
||||
|
||||
To enable a service one simply drops a small configuration file in the
|
||||
`/etc/finit.d/` directory. This practice works with systems that
|
||||
keep disabled services elsewhere, or generates them as needed from some
|
||||
other tool.
|
||||
In this layout, you enable a service by placing its `.conf` file in
|
||||
`/etc/finit.d/` and disable it by removing the file. This works well for
|
||||
embedded systems or custom setups where services are managed by other tools
|
||||
or generated dynamically.
|
||||
|
||||
Distributions, however, may want a clearer separation of enabled and
|
||||
available (installed but not enabled) services. They may even want to
|
||||
customize the directories used, for brand labeling or uniformity.
|
||||
> [!NOTE] No tooling support
|
||||
> The `initctl enable/disable` commands **do not work** with this layout.
|
||||
> You must manually manage files in `/etc/finit.d/`.
|
||||
|
||||
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.
|
||||
## Distro Layout
|
||||
|
||||
To change the default configuration directory and configuration file
|
||||
names the Finit `configure` script offers the following two options at
|
||||
build time:
|
||||
Distributions typically want clearer separation between available (installed)
|
||||
and enabled services. Finit supports this through the `available/` and
|
||||
`enabled/` subdirectories:
|
||||
|
||||
```
|
||||
/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
|
||||
./configure --with-rcsd=/etc/init.d --with-config=/etc/init.d/init.conf
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Remember `--prefix` et al as well, the default is likely *not* what
|
||||
> you want. See the [build docs][1] for details.
|
||||
This changes the default `/etc/finit.d/` to `/etc/init.d/` and moves the
|
||||
bootstrap configuration file accordingly.
|
||||
|
||||
The resulting directory structure is depicted below. Please notice how
|
||||
`/etc/finit.conf` now resides in the same sub-directory as a non-symlink
|
||||
`/etc/init.d/init.conf`:
|
||||
> [!IMPORTANT] Remember to set `--prefix`
|
||||
> Remember to set `--prefix` and related options appropriately. The default
|
||||
> prefix is `/usr/local`, which is likely not what you want for a system
|
||||
> init. See the [build documentation][1] for details.
|
||||
|
||||
Example with custom paths:
|
||||
|
||||
```
|
||||
/etc/
|
||||
|-- init.d/
|
||||
| |-- available/ -- Regular (disabled) services
|
||||
| |-- available/ -- Installed services
|
||||
| | |-- httpd.conf
|
||||
| | |-- ntpd.conf
|
||||
| | `-- sshd.conf
|
||||
| |-- sshd.conf -- Symlink to available/sshd.conf
|
||||
| |-- enabled/ -- Enabled services (symlinks)
|
||||
| | `- sshd.conf -- Symlink to ../available/sshd.conf
|
||||
| `- init.conf -- Bootstrap tasks and services
|
||||
:
|
||||
```
|
||||
|
||||
To facilitate the task of managing configurations, be it a service,
|
||||
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`.
|
||||
Notice how both the service directory and bootstrap configuration file now
|
||||
use the custom `/etc/init.d/` path specified at build time.
|
||||
|
||||
[1]: build.md#configure
|
||||
|
||||
+135
-58
@@ -10,117 +10,194 @@ 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.
|
||||
> A block spans as many lines as it needs, so no continuation character is
|
||||
> called for. For the full syntax, see the [finit.conf(5)][] manual or the
|
||||
> [Configuration](config/index.md) section.
|
||||
|
||||
```ApacheConf
|
||||
# Fallback if /etc/hostname is missing
|
||||
host default
|
||||
hostname = "default"
|
||||
|
||||
# Runlevel to start after bootstrap, 'S', default: 2
|
||||
#runlevel 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
|
||||
# Global environment variables, be careful though with variables like
|
||||
# PATH, SHELL, LOGNAME, etc.
|
||||
#environment {
|
||||
# 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
|
||||
log {
|
||||
size = 100k
|
||||
count = 4
|
||||
}
|
||||
|
||||
# Services to be monitored and respawned as needed
|
||||
service [S12345] env:-/etc/conf.d/watchdog watchdog $WATCHDOG_OPTS $WATCHDOG_DEV -- System watchdog daemon
|
||||
service [S12345] env:-/etc/conf.d/syslog syslogd -n $SYSLOGD_OPTS -- System log daemon
|
||||
service [S12345] <pid/syslogd> env:-/etc/conf.d/klogd klogd -n $KLOGD_OPTS -- Kernel log daemon
|
||||
service [2345] env:-/etc/conf.d/lldpd lldpd -d $LLDPD_OPTS -- LLDP daemon (IEEE 802.1ab)
|
||||
service watchdog {
|
||||
description = "System watchdog daemon"
|
||||
runlevel = "S12345"
|
||||
envfile = "-/etc/conf.d/watchdog"
|
||||
command = "watchdog $WATCHDOG_OPTS $WATCHDOG_DEV"
|
||||
}
|
||||
service syslogd {
|
||||
description = "System log daemon"
|
||||
runlevel = "S12345"
|
||||
envfile = "-/etc/conf.d/syslog"
|
||||
command = "syslogd -n $SYSLOGD_OPTS"
|
||||
}
|
||||
service klogd {
|
||||
description = "Kernel log daemon"
|
||||
runlevel = "S12345"
|
||||
conditions = { "pid/syslogd" }
|
||||
envfile = "-/etc/conf.d/klogd"
|
||||
command = "klogd -n $KLOGD_OPTS"
|
||||
}
|
||||
service lldpd {
|
||||
description = "LLDP daemon (IEEE 802.1ab)"
|
||||
runlevel = "2345"
|
||||
envfile = "-/etc/conf.d/lldpd"
|
||||
command = "lldpd -d $LLDPD_OPTS"
|
||||
}
|
||||
|
||||
# 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
|
||||
# a dependency on a system default route (gateway) to be set. ntpd
|
||||
# does not respect SIGHUP, so Finit restarts it on reload instead.
|
||||
service ntpd {
|
||||
description = "NTP daemon"
|
||||
runlevel = "2345"
|
||||
conditions = { "net/route/default" }
|
||||
reload-signal = "none"
|
||||
log { file = "/var/log/ntpd.log" }
|
||||
command = "ntpd -n -l -I eth0"
|
||||
}
|
||||
|
||||
# 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
|
||||
# For multiple instances of the same service, add :ID to the block title.
|
||||
service merecat:80 {
|
||||
description = "Web server"
|
||||
runlevel = "2345"
|
||||
command = "merecat -n -p 80 /var/www"
|
||||
}
|
||||
service merecat:8080 {
|
||||
description = "Old web server"
|
||||
runlevel = "2345"
|
||||
command = "merecat -n -p 8080 /var/www"
|
||||
}
|
||||
|
||||
# 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
|
||||
#sysv keyboard-setup {
|
||||
# description = "Setting up preliminary keymap"
|
||||
# runlevel = "S"
|
||||
# command = "/etc/init.d/keyboard-setup"
|
||||
#}
|
||||
|
||||
# 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 --
|
||||
# Hidden from boot progress, using an empty description
|
||||
#sysv acpid {
|
||||
# description = ""
|
||||
# runlevel = "S"
|
||||
# command = "/etc/init.d/acpid"
|
||||
#}
|
||||
|
||||
# Run start scripts from this directory
|
||||
# runparts /etc/start.d
|
||||
#runparts = "/etc/start.d"
|
||||
|
||||
# Virtual consoles run BusyBox getty, keep kernel default speed
|
||||
tty [12345] /sbin/getty -L 0 /dev/tty1 linux nowait noclear
|
||||
tty [2345] /sbin/getty -L 0 /dev/tty2 linux nowait noclear
|
||||
tty [2345] /sbin/getty -L 0 /dev/tty3 linux nowait noclear
|
||||
tty tty1 {
|
||||
runlevel = "12345"
|
||||
command = "/sbin/getty -L 0 /dev/tty1 linux"
|
||||
nowait = true
|
||||
noclear = true
|
||||
}
|
||||
tty tty2 {
|
||||
runlevel = "2345"
|
||||
command = "/sbin/getty -L 0 /dev/tty2 linux"
|
||||
nowait = true
|
||||
noclear = true
|
||||
}
|
||||
tty tty3 {
|
||||
runlevel = "2345"
|
||||
command = "/sbin/getty -L 0 /dev/tty3 linux"
|
||||
nowait = true
|
||||
noclear = true
|
||||
}
|
||||
|
||||
# Use built-in getty for serial port and USB serial
|
||||
#tty [12345] /dev/ttyAMA0 noclear nowait
|
||||
#tty [12345] /dev/ttyUSB0 noclear
|
||||
#tty ttyAMA0 { runlevel = "12345" device = "/dev/ttyAMA0" noclear = true nowait = true }
|
||||
#tty ttyUSB0 { runlevel = "12345" device = "/dev/ttyUSB0" noclear = true }
|
||||
|
||||
# Just give me a shell, I need to debug this embedded system!
|
||||
#tty [12345] console noclear nologin
|
||||
#tty console { runlevel = "12345" device = "@console" noclear = true nologin = true }
|
||||
```
|
||||
|
||||
The `service` stanza, as well as `task`, `run` and others are described in
|
||||
The `service` block, 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)
|
||||
service NAME { <-- Supervised program (daemon)
|
||||
description = "Example daemon" <-- Optional description
|
||||
runlevel = "2345" <-- Optional runlevels
|
||||
conditions = { "net/route/default" } <-- Optional conditions
|
||||
envfile = "-/etc/default/daemon" <-- Optional env. file
|
||||
log { } <-- Redirect output to log
|
||||
command = "daemon ARGS" <-- Path to daemon, and its arguments
|
||||
}
|
||||
```
|
||||
|
||||
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:
|
||||
Only `command` is required, which makes simple cases short while leaving
|
||||
room for more advanced uses:
|
||||
|
||||
service /usr/sbin/sshd -D
|
||||
service sshd {
|
||||
command = "/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
|
||||
service nginx {
|
||||
description = "High performance HTTP server"
|
||||
conditions = { "net/route/default" }
|
||||
command = "nginx"
|
||||
}
|
||||
|
||||
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
|
||||
service ntpd {
|
||||
runlevel = "2345"
|
||||
conditions = { "pid/syslogd" }
|
||||
reload-signal = "none"
|
||||
log { }
|
||||
command = "ntpd -n -N -p pool.ntp.org"
|
||||
}
|
||||
|
||||
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.
|
||||
service syslogd {
|
||||
description = "Syslog daemon"
|
||||
runlevel = "S12345"
|
||||
command = "syslogd -n"
|
||||
}
|
||||
|
||||
Notice the empty `log` block, BusyBox `ntpd` uses `stderr` for logging
|
||||
when run in the foreground. With it 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
|
||||
service ntpd {
|
||||
runlevel = "2345"
|
||||
conditions = { "pid/syslogd", "net/route/default" }
|
||||
log { }
|
||||
command = "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.
|
||||
|
||||
+170
-26
@@ -1,6 +1,10 @@
|
||||
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.
|
||||
@@ -14,9 +18,9 @@ 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
|
||||
tty tty1 { runlevel = "12345" device = "/dev/tty1" term = "linux" nowait = true }
|
||||
tty ttyAMA0 { runlevel = "12345" device = "/dev/ttyAMA0" term = "vt100" noclear = true }
|
||||
tty getty { runlevel = "12345" command = "/sbin/getty -L /dev/ttyAMA0 vt100" }
|
||||
```
|
||||
|
||||
Users of embedded systems may want to enable automatic serial console
|
||||
@@ -25,7 +29,7 @@ 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
|
||||
tty console { runlevel = "12345" device = "@console" term = "linux" noclear = true }
|
||||
```
|
||||
|
||||
Notice the optional `noclear`, `nowait`, and `nologin` flags. The
|
||||
@@ -36,21 +40,21 @@ 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.
|
||||
minimal style as everything else in Finit. The `runlevel` setting
|
||||
applies to service, task, run, and tty blocks alike.
|
||||
|
||||
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`
|
||||
networking here. The configured `runlevel` from `/etc/finit.conf`
|
||||
is what Finit changes to after bootstrap, unless 'single' (or 'S') is
|
||||
given on the kernel cmdline, in which case runlevel 1 is started.
|
||||
|
||||
All services in runlevel S) are started first, followed by the desired
|
||||
All services in runlevel S 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.
|
||||
by using a `run` block with `runlevel = "S"`. 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**
|
||||
@@ -82,8 +86,17 @@ 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
|
||||
run ident {
|
||||
description = ""
|
||||
runlevel = "S"
|
||||
command = "/path/to/ident"
|
||||
}
|
||||
task foo-init {
|
||||
description = "Initializing Foo board"
|
||||
runlevel = "2"
|
||||
conditions = { "hw/model/foo" }
|
||||
command = "/path/to/foo-init"
|
||||
}
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
@@ -113,7 +126,7 @@ hook into the boot process or respond to various I/O.
|
||||
For more information, see the [Plugins](plugins.md) section.
|
||||
|
||||
|
||||
**Automatic Reload**
|
||||
**Automatic Reload**{ #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
|
||||
@@ -137,17 +150,20 @@ 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;'
|
||||
service nginx {
|
||||
runlevel = "2345"
|
||||
user = "www-data"
|
||||
group = "www-data"
|
||||
capabilities = { "^cap_net_bind_service" }
|
||||
command = "/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:
|
||||
The `capabilities` list uses the IAB (Inheritable, Ambient, Bounding) format:
|
||||
- `^` = Ambient (recommended) - capabilities survive exec()
|
||||
- `%` = Inheritable only - requires file capabilities
|
||||
- `!` = Bounding - block from acquiring capability
|
||||
@@ -155,13 +171,55 @@ The `caps:` directive uses the IAB (Inheritable, Ambient, Bounding) format:
|
||||
Multiple capabilities can be specified as comma-separated:
|
||||
|
||||
```conf
|
||||
caps:^cap_net_raw,^cap_net_admin,!cap_sys_admin
|
||||
capabilities = { "^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.
|
||||
|
||||
|
||||
**PAM Sessions**
|
||||
|
||||
A service can run inside a PAM session, so the `session` stack in
|
||||
`/etc/pam.d` applies to it, e.g. limits from `pam_limits`:
|
||||
|
||||
```conf
|
||||
service weston {
|
||||
user = "weston"
|
||||
pam = "weston-autologin"
|
||||
command = "/usr/bin/weston --continue-without-input"
|
||||
}
|
||||
```
|
||||
|
||||
Without a `user` the session is for root. Requires a build with PAM
|
||||
support, which is the default; see `--disable-pam`.
|
||||
|
||||
See the [PAM Sessions](config/pam.md) section for the pam.d file the
|
||||
example needs, and for how PAM and Finit settings interact.
|
||||
|
||||
|
||||
**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
|
||||
@@ -184,15 +242,19 @@ 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:
|
||||
declared as such in their service block like this:
|
||||
|
||||
service [...] <...> cgroup.root /path/to/foo args -- description
|
||||
service foo {
|
||||
cgroup root {}
|
||||
command = "/path/to/foo args"
|
||||
}
|
||||
|
||||
or
|
||||
Every block names the group it joins, so a second RT task says so too:
|
||||
|
||||
cgroup.root
|
||||
service [...] <...> /path/to/foo args -- description
|
||||
service [...] <...> /path/to/bar args -- description
|
||||
service bar {
|
||||
cgroup root {}
|
||||
command = "/path/to/bar args"
|
||||
}
|
||||
|
||||
See the [Cgroups](config/cgroups.md) section for more information, e.g.,
|
||||
how to configure per-group limits.
|
||||
@@ -207,4 +269,86 @@ commands for details.
|
||||
> 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
|
||||
```
|
||||
|
||||
`initctl` rides Finit's built-in [D-Bus API](dbus.md) when available,
|
||||
which is also open to any other bus client, including `dbus-send` and
|
||||
language bindings.
|
||||
|
||||
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
|
||||
|
||||
+21
-14
@@ -1,7 +1,7 @@
|
||||
Introduction
|
||||
============
|
||||
|
||||
{ align=right }
|
||||
{ align=right width=40% }
|
||||
|
||||
> Reverse engineered from the [EeePC fastinit][]
|
||||
> "gaps filled with frog DNA …"
|
||||
@@ -17,26 +17,32 @@ PID file monitoring, or [conditions](conditions.md).
|
||||
Features
|
||||
--------
|
||||
|
||||
* [Runlevels][5], defined per service
|
||||
* One-shot tasks, services (daemons), or [SysV init][4] start/stop scripts
|
||||
* Runparts and `/etc/rc.local` support
|
||||
* [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][]
|
||||
* Sourcing environment files
|
||||
* Conditions for network/process/custom dependencies
|
||||
* Readiness notification; PID files (native) for synchronizing system
|
||||
* 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
|
||||
* [Pre/Post script actions](config/service-wrappers.md)
|
||||
* Rudimentary [templating support](config/templating.md)
|
||||
* Tooling to enable/disable services
|
||||
* Built-in getty
|
||||
* [Tooling](initctl.md) to enable/disable services
|
||||
* [D-Bus API](dbus.md), `org.finit` control and signals for bus clients
|
||||
* [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, both configuration and monitoring in `initctl top`
|
||||
* Plugin support for customization
|
||||
* Proper rescue mode with bundled `sulogin` for protected maintenance shell
|
||||
* [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 to kernel ring buffer before `syslogd` has started, see the
|
||||
* [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`
|
||||
|
||||
@@ -64,6 +70,7 @@ and proposed extensions.
|
||||
[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
|
||||
|
||||
+32
-9
@@ -5,6 +5,11 @@ 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.
|
||||
|
||||
Since Finit v5, `initctl` talks to Finit over the built-in
|
||||
[D-Bus API](dbus.md) when the bus socket is available, falling back
|
||||
to the legacy `INIT_SOCKET` transport. The `monitor` command streams
|
||||
the `org.finit` signals until interrupted.
|
||||
|
||||
```
|
||||
Usage: initctl [OPTIONS] [COMMAND]
|
||||
|
||||
@@ -14,6 +19,7 @@ Options:
|
||||
-f, --force Ignore missing files and arguments, never prompt
|
||||
-h, --help This help text
|
||||
-j, --json JSON output in 'status' and 'cond' commands
|
||||
-n, --noerr Ignore error, e.g., already started/enabled/...
|
||||
-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
|
||||
@@ -26,15 +32,8 @@ Commands:
|
||||
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)
|
||||
show Show /etc/finit.conf
|
||||
reload Reload /etc/finit.conf (activate changes)
|
||||
|
||||
cond set <COND> Set (assert) user-defined conditions +usr/COND
|
||||
cond get <COND> Get status of user-defined condition, see $? and -v
|
||||
@@ -50,6 +49,7 @@ Commands:
|
||||
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
|
||||
monitor Stream D-Bus signals (service state, conditions) until ^C
|
||||
ident [NAME] Show matching identities for NAME, or all
|
||||
status <NAME>[:ID] Show service status, by name
|
||||
status Show status of services, default command
|
||||
@@ -65,8 +65,10 @@ Commands:
|
||||
halt Halt system
|
||||
poweroff Halt and power off system
|
||||
suspend Suspend system
|
||||
switch-root ROOT [INIT] Switch to new root filesystem (initramfs)
|
||||
|
||||
utmp show Raw dump of UTMP/WTMP db
|
||||
|
||||
```
|
||||
|
||||
For services *not* supporting `SIGHUP` the `<!>` notation in the .conf
|
||||
@@ -143,3 +145,24 @@ Apr 8 12:37:46 alpine authpriv.info dropbear[2300]: Exit (root) from <192.168.1
|
||||
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.
|
||||
|
||||
+534
-11
@@ -1,14 +1,537 @@
|
||||
keventd
|
||||
=======
|
||||
Bundled Device Manager
|
||||
======================
|
||||
|
||||
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.
|
||||
The kernel event daemon `keventd` is a built-in device manager bundled
|
||||
with Finit. It replaces the need for external device managers like
|
||||
mdev, mdevd, or udevd on systems where a lighter-weight solution is
|
||||
preferred, particularly on embedded systems.
|
||||
|
||||
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.
|
||||
It is enabled by default since Finit v5, and needs libblkid from
|
||||
util-linux (the `libblkid-dev` package, or whatever your distribution
|
||||
calls it) to read the filesystem UUID and label behind the
|
||||
`/dev/disk/by-uuid/` and `/dev/disk/by-label/` symlinks. To disable it
|
||||
and use an external device manager instead:
|
||||
|
||||
This daemon is planned to be extended with monitoring of other uevents,
|
||||
patches and ideas are welcome in the issue tracker.
|
||||
./configure --without-keventd
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
When started, keventd listens on a `NETLINK_KOBJECT_UEVENT` socket for
|
||||
kernel events and handles:
|
||||
|
||||
- **Device node creation**: creates and removes `/dev` nodes with
|
||||
correct permissions on device add/remove events
|
||||
- **udev rules**: matches events against rules read from
|
||||
`/lib/udev/rules.d/`, `/run/udev/rules.d/`, and `/etc/udev/rules.d/`,
|
||||
with a curated ruleset derived from eudev installed by default
|
||||
- **Persistent symlinks**: creates `by-id` and `by-path` symlinks under
|
||||
`/dev/disk/`, `/dev/input/`, and elsewhere, for stable device naming
|
||||
- **Firmware loading**: responds to kernel firmware requests by searching
|
||||
`/lib/firmware/` and writing firmware data to sysfs
|
||||
- **Module loading**: parses `MODALIAS` from uevents and spawns `modprobe`
|
||||
to load the appropriate kernel module
|
||||
- **Coldplug**: with the `-c` flag, walks `/sys/devices` and triggers
|
||||
add events for all devices present at boot
|
||||
- **Power supply monitoring**: tracks AC power status and provides the
|
||||
`sys/pwr/ac` condition
|
||||
- **Device conditions**: sets `dev/*` conditions in the Finit condition
|
||||
system when device nodes appear or disappear
|
||||
- **Netlink rebroadcast**: rebroadcasts processed uevents to netlink
|
||||
group 0x4 for [libudev-zero][] consumers (enabled by default)
|
||||
- **D-Bus interface**: `org.finit.Device1` -- settle, trigger, device
|
||||
info, rules reload, and queue state over its own bus socket
|
||||
|
||||
|
||||
Device Nodes
|
||||
------------
|
||||
|
||||
On receiving an `add` event with `MAJOR`, `MINOR`, and `DEVNAME`
|
||||
fields, keventd creates the corresponding device node in `/dev` using
|
||||
`mknod()`. Parent directories are created automatically (e.g.,
|
||||
`/dev/input/` for `/dev/input/event0`).
|
||||
|
||||
On `remove` events, the device node and its associated symlinks and
|
||||
conditions are cleaned up.
|
||||
|
||||
### Default Permissions
|
||||
|
||||
keventd applies permissions based on built-in rules that match on
|
||||
device subsystem and name:
|
||||
|
||||
| **Subsystem** | **Pattern** | **Mode** | **Owner:Group** |
|
||||
|---------------|--------------------------------------------|----------|-----------------|
|
||||
| block | sd*, vd*, nvme*, mmcblk*, loop*, dm-*, md* | 0660 | root:disk |
|
||||
| tty | tty[0-9]* | 0620 | root:tty |
|
||||
| tty | ttyS*, ttyUSB*, ttyACM* | 0660 | root:dialout |
|
||||
| input | event*, mouse*, mice | 0660 | root:root |
|
||||
| sound | * | 0660 | root:audio |
|
||||
| video4linux | * | 0660 | root:video |
|
||||
| drm | card*, render* | 0660 | root:video |
|
||||
| (any) | null, zero, full, random, urandom | 0666 | root:root |
|
||||
| (any) | console | 0600 | root:root |
|
||||
| (default) | | 0660 | root:root |
|
||||
|
||||
|
||||
udev Rules
|
||||
----------
|
||||
|
||||
Rules are read from `/lib/udev/rules.d/`, `/run/udev/rules.d/`, and
|
||||
`/etc/udev/rules.d/`, plus any directory passed with `-r`. Files need a
|
||||
`.rules` suffix. Like udev, all files sort together by filename,
|
||||
whichever directory they live in, and a file masks one of the same name
|
||||
in an earlier directory: `/etc/` overrides `/run/`, which overrides
|
||||
`/lib/`, and the `-r` directory overrides them all. A symlink to
|
||||
`/dev/null` in `/etc/udev/rules.d/` disables the `/lib/` file of the
|
||||
same name.
|
||||
|
||||
The syntax is the one described in [udev(7)][]. What follows is the
|
||||
subset keventd understands, not a second copy of the grammar. To pick up
|
||||
edited rules, call `RulesReload` on
|
||||
[`org.finit.Device1`](#d-bus-interface-orgfinitdevice1). `initctl reload`
|
||||
does not touch them.
|
||||
|
||||
### Match Keys
|
||||
|
||||
| **Key** | **Matches** |
|
||||
|---------------------------------------------------|--------------------------------------------------------------------------|
|
||||
| `ACTION` | `add`, `remove`, `change`, `move`, `bind`, `unbind`, `online`, `offline` |
|
||||
| `DEVPATH` | kernel device path, without the `/sys` prefix |
|
||||
| `KERNEL` | sysfs name of the device |
|
||||
| `NAME` | device node name |
|
||||
| `SUBSYSTEM`, `DRIVER` | subsystem and bound driver |
|
||||
| `ATTR{file}` | sysfs attribute of the device |
|
||||
| `SYSCTL{param}` | value under `/proc/sys/` |
|
||||
| `ENV{key}` | uevent property, including ones set by earlier rules |
|
||||
| `CONST{key}` | `arch`; `virt` reports `container` or nothing |
|
||||
| `TAG` | tag set by an earlier `TAG+=` |
|
||||
| `TEST{octal}` | file exists, optionally with the given permission bits |
|
||||
| `PROGRAM` | exit status of a program, output kept for `RESULT` and `%c` |
|
||||
| `RESULT` | output of the last `PROGRAM` |
|
||||
| `KERNELS`, `SUBSYSTEMS`, `DRIVERS`, `ATTRS{file}` | the device or any of its parents, see below |
|
||||
|
||||
Values match literally, as an `fnmatch()` glob, or as `a|b|c` alternatives.
|
||||
Both `==` and `!=` work everywhere.
|
||||
|
||||
`SECLABEL`, `OPTIONS`, and `TAGS` parse but do nothing. Rules using them load
|
||||
without complaint and the key is skipped, so `OPTIONS+="static_node=..."`,
|
||||
`link_priority=`, `string_escape=`, and `watch` have no effect, and a `TAGS==`
|
||||
match never succeeds.
|
||||
|
||||
### The Parent Chain
|
||||
|
||||
`ATTR{}` reads an attribute of the device the event fired for. `ATTRS{}` also
|
||||
looks at the parents, walking up the sysfs tree until one matches. For a
|
||||
keyboard behind a hub:
|
||||
|
||||
/sys/devices/.../usb2/ <- root hub
|
||||
usb2/2-1/ <- hub
|
||||
usb2/2-1/2-1.4/ <- keyboard, event fires here
|
||||
|
||||
`ATTRS{authorized_default}=="1"` finds no such attribute on the keyboard or
|
||||
the hub, reaches the root hub, and matches there. `KERNELS`, `SUBSYSTEMS`,
|
||||
and `DRIVERS` do the same for a parent's name, subsystem, and driver.
|
||||
|
||||
Each of these keys walks the chain on its own. udev requires all the parent
|
||||
keys in one rule to match on the *same* parent, so a rule pairing
|
||||
`SUBSYSTEMS=="usb"` with `ATTRS{idVendor}=="1d6b"` is looser here: the two may
|
||||
land on different ancestors. Where that matters, match on one attribute
|
||||
specific enough to identify the device by itself.
|
||||
|
||||
### Assignments
|
||||
|
||||
| **Key** | **Effect** |
|
||||
|-----------------------------|--------------------------------------------------------------------------|
|
||||
| `NAME=` | name of the device node |
|
||||
| `SYMLINK=`, `+=` | symlinks to create, space separated, relative to `/dev` |
|
||||
| `OWNER=`, `GROUP=`, `MODE=` | ownership and permissions of the node |
|
||||
| `ENV{key}=`, `+=`, `-=` | set, append to, or clear a property |
|
||||
| `TAG+=`, `-=` | tags for later `TAG==` matching |
|
||||
| `RUN+=` | program to run once the event is handled, `RUN{builtin}+=` for a builtin |
|
||||
| `IMPORT{type}` | `program`, `file`, `db`, `builtin`, `parent`, `cmdline` |
|
||||
| `ATTR{file}=` | write to a sysfs attribute |
|
||||
| `SYSCTL{param}=` | write to `/proc/sys/` |
|
||||
| `LABEL=`, `GOTO=` | skip ahead to a label |
|
||||
|
||||
`:=` locks `MODE`, `OWNER`, and `GROUP` against later rules the way udev
|
||||
does. On `NAME` and `ENV{}` it behaves like plain `=` and locks nothing,
|
||||
and `SYMLINK:=` is dropped without a word.
|
||||
|
||||
`IMPORT{builtin}` and `RUN{builtin}` can call `blkid`, `hwdb`,
|
||||
`input_id`, `kmod`, `net_id`, `path_id`, and `usb_id`.
|
||||
|
||||
### Substitutions
|
||||
|
||||
| **Long** | **Short** | **Expands to** |
|
||||
|--------------------|---------------|------------------------------------|
|
||||
| `$kernel` | `%k` | sysfs name of the device |
|
||||
| `$devpath` | `%p` | kernel device path |
|
||||
| `$name` | `%N`, `%D` | device node name |
|
||||
| `$major`, `$minor` | `%M`, `%m` | device numbers |
|
||||
| `$driver` | `%d` | bound driver |
|
||||
| `$attr{file}` | `%s{file}` | sysfs attribute of the device |
|
||||
| `$env{key}` | | uevent property |
|
||||
| `$result` | `%c`, `%c{N}` | `PROGRAM` output, or its Nth field |
|
||||
| `$root` | | `/dev` |
|
||||
| `$sys` | | `/sys` |
|
||||
| | `%n` | trailing digits of the sysfs name |
|
||||
| | `%b` | `major:minor` |
|
||||
|
||||
udev's `$id`, `$parent`, `$links`, and `%E{}` are not implemented, and `%b`
|
||||
here is the device number pair rather than udev's parent bus id. An unknown
|
||||
specifier is left in the string as written.
|
||||
|
||||
|
||||
Persistent Symlinks
|
||||
-------------------
|
||||
|
||||
Symlinks come from two places. A handful are built into keventd and are
|
||||
created for every device in the subsystem, whatever rules are loaded.
|
||||
|
||||
For block devices, under `/dev/disk/`:
|
||||
|
||||
- **by-id**: based on the device serial number and model, read from
|
||||
sysfs attributes (`/sys/.../device/vendor`, `model`, `serial`)
|
||||
- **by-path**: based on the device topology path
|
||||
|
||||
For input devices, under `/dev/input/`:
|
||||
|
||||
- **by-id**: based on the device name from sysfs
|
||||
- **by-path**: based on the physical device path
|
||||
|
||||
The rest come from `SYMLINK+=` in the udev rules, so what you get
|
||||
depends on the ruleset installed. The curated rules Finit ships add,
|
||||
among others:
|
||||
|
||||
| **Directory** | **Links** |
|
||||
|----------------|--------------------------------------------------------|
|
||||
| `/dev/disk/` | `by-uuid`, `by-label`, `by-partuuid`, `by-partlabel`, `by-diskseq`, and further `by-id` and `by-path` names for NVMe, virtio, MMC, WWN, and FireWire |
|
||||
| `/dev/input/` | longer `by-id` and `by-path` names than the built-in ones, down to the USB interface number |
|
||||
| `/dev/serial/` | `by-id`, `by-path` |
|
||||
| `/dev/snd/` | `by-id`, `by-path` |
|
||||
| `/dev/v4l/` | `by-id`, `by-path` |
|
||||
| `/dev/tape/` | `by-id`, `by-path` |
|
||||
| `/dev/dri/` | `by-path` |
|
||||
|
||||
They also set up a few fixed names: `/dev/rtc`, `/dev/cdrom`, and
|
||||
`/dev/virtio-ports/<name>`.
|
||||
|
||||
The `by-uuid` and `by-label` links are why keventd needs libblkid. The
|
||||
rules read the filesystem metadata off the device with
|
||||
`IMPORT{builtin}="blkid"`, and libblkid is what that builtin calls.
|
||||
|
||||
Built-in and rule-provided symlinks alike are tracked internally and
|
||||
removed when the corresponding device is unplugged.
|
||||
|
||||
|
||||
Firmware Loading
|
||||
----------------
|
||||
|
||||
When a kernel driver requests firmware (via `request_firmware()`), the
|
||||
kernel sends a uevent with a `FIRMWARE=` field. keventd handles this
|
||||
by:
|
||||
|
||||
1. Searching for the firmware file in order:
|
||||
- `/lib/firmware/updates/<kernel-version>/<name>`
|
||||
- `/lib/firmware/updates/<name>`
|
||||
- `/lib/firmware/<kernel-version>/<name>`
|
||||
- `/lib/firmware/<name>`
|
||||
2. Writing `1` to `/sys/<devpath>/loading` to signal start
|
||||
3. Copying the firmware data to `/sys/<devpath>/data`
|
||||
4. Writing `0` to `/sys/<devpath>/loading` on success (or `-1` on failure)
|
||||
|
||||
This is particularly important early in boot when drivers for graphics
|
||||
cards, network adapters, and other hardware need firmware before they
|
||||
can operate.
|
||||
|
||||
|
||||
Module Loading
|
||||
--------------
|
||||
|
||||
When a device add event includes a `MODALIAS` field, keventd spawns
|
||||
`modprobe -bq <modalias>` to load the matching kernel module. Module
|
||||
loading is done asynchronously (keventd does not wait for modprobe to
|
||||
complete) to avoid blocking other event processing.
|
||||
|
||||
|
||||
Coldplug
|
||||
--------
|
||||
|
||||
To handle devices that were present before keventd started, it supports
|
||||
a coldplug mode activated with the `-c` flag. This walks the entire
|
||||
`/sys/devices` tree and writes `add` to each `uevent` file, causing the
|
||||
kernel to re-emit add events for all existing devices.
|
||||
|
||||
This replaces the separate `coldplug` script previously used with mdev.
|
||||
|
||||
When `-c` is used, keventd defers its pidfile (and the `pid/keventd`
|
||||
condition Finit asserts from it) until the coldplug event queue has
|
||||
been fully drained. Services that depend on `<pid/keventd>` can
|
||||
therefore assume `/dev` is populated and persistent symlinks are live,
|
||||
without needing a separate `settle` step.
|
||||
|
||||
|
||||
Netlink Rebroadcast
|
||||
-------------------
|
||||
|
||||
The Linux kernel sends uevents to netlink multicast group 1 (bit 0) of
|
||||
`NETLINK_KOBJECT_UEVENT`. Only the device manager listens on this raw
|
||||
kernel group. Userspace consumers — applications using libudev —
|
||||
expect to receive processed events on a separate netlink group.
|
||||
|
||||
systemd/udevd established the convention of rebroadcasting processed
|
||||
events to a separate group, and [libudev-zero][], a daemonless drop-in
|
||||
replacement for libudev, listens on group `0x4` for these events.
|
||||
Without a device manager rebroadcasting, graphical applications,
|
||||
Wayland/X11 compositors, libinput, and anything else using libudev to
|
||||
monitor device hotplug will never see any events.
|
||||
|
||||
keventd rebroadcasts by default to netlink group 4 (`0x4`). A second
|
||||
netlink socket is created at startup, and after each uevent has been
|
||||
fully processed (device nodes created, symlinks set up, modules loaded),
|
||||
the original raw event is sent to the configured group(s).
|
||||
Rebroadcasting after processing ensures that device nodes and symlinks
|
||||
already exist by the time consumers receive the notification.
|
||||
|
||||
Use `-g GROUP` to override the default group mask, or `-G` to disable
|
||||
rebroadcast entirely. Bit 0 of the group mask is always forced off to
|
||||
prevent a feedback loop with the kernel's own multicast group.
|
||||
|
||||
### Background
|
||||
|
||||
The netlink uevent architecture uses separate multicast groups to
|
||||
isolate the kernel-to-device-manager channel from the device-manager-to-
|
||||
application channel:
|
||||
|
||||
| **Group** | **Bit** | **Purpose** |
|
||||
|-----------|---------|---------------------------------------------|
|
||||
| 1 | 0 | Kernel events (device manager listens here) |
|
||||
| 4 | 2 | Processed events (libudev consumers listen) |
|
||||
|
||||
This two-group design was established by systemd/udevd and is the de
|
||||
facto standard. [mdevd][] implements the same mechanism via its `-O`
|
||||
flag, and keventd follows the same convention.
|
||||
|
||||
For more details, see:
|
||||
|
||||
- [libudev-zero][] — daemonless replacement for libudev
|
||||
- [mdevd][] — mdev-compatible device manager with rebroadcast support
|
||||
|
||||
|
||||
Conditions
|
||||
----------
|
||||
|
||||
keventd provides conditions in two namespaces:
|
||||
|
||||
### Device Conditions (`dev/`)
|
||||
|
||||
When a device node is created, keventd asserts a corresponding condition
|
||||
in `/run/finit/cond/dev/`. This allows services to wait for specific
|
||||
devices:
|
||||
|
||||
service mdadm {
|
||||
description = "RAID monitor"
|
||||
runlevel = "2345"
|
||||
conditions = { "dev/sda" }
|
||||
command = "/usr/sbin/mdadm --monitor /dev/md0"
|
||||
}
|
||||
|
||||
service gps-daemon {
|
||||
description = "GPS daemon"
|
||||
runlevel = "2345"
|
||||
conditions = { "dev/ttyUSB0" }
|
||||
command = "/usr/sbin/gps-daemon"
|
||||
}
|
||||
|
||||
Network interfaces are not device nodes and do not live in the `dev/`
|
||||
namespace -- a `/dev/wan` node created by a user must not be confused
|
||||
with a `wan` interface. To wait for an interface, use the `netlink`
|
||||
plugin's `net/<iface>/exist` condition, plus `net/<iface>/up` (admin
|
||||
up) and `net/<iface>/running` (carrier present) to gate on link state:
|
||||
|
||||
service dhcpcd {
|
||||
description = "DHCP client"
|
||||
runlevel = "2345"
|
||||
conditions = { "net/wan/exist" }
|
||||
command = "/usr/sbin/dhcpcd"
|
||||
}
|
||||
|
||||
keventd provides the parallel `class/net/<iface>` condition, like for
|
||||
any other sysfs class device.
|
||||
|
||||
When the device is removed, the condition is cleared and Finit stops
|
||||
the dependent services.
|
||||
|
||||
### Class Conditions (`class/`)
|
||||
|
||||
Many devices live in sysfs without a `/dev/` node -- DSA switch ports,
|
||||
IIO sensors, LEDs, backlight, PHYs, regulators. For those, keventd
|
||||
asserts `class/<subsystem>/<sysname>` on every `add` event so services
|
||||
can still wait for them:
|
||||
|
||||
service blink-blue {
|
||||
description = "LED driver"
|
||||
runlevel = "2345"
|
||||
conditions = { "class/leds/blue" }
|
||||
command = "/usr/sbin/blink-blue"
|
||||
}
|
||||
|
||||
The condition is cleared on `remove`.
|
||||
|
||||
### Driver Conditions (`driver/`)
|
||||
|
||||
`driver/<name>` is asserted while the driver `<name>` is bound to at
|
||||
least one device, from the kernel's `bind`/`unbind` uevents. Use this
|
||||
to gate on slow-probing hardware whose readiness isn't marked by a
|
||||
class device or `/dev` node, such as a switch core or complex PHY:
|
||||
|
||||
service dsa-probe {
|
||||
description = "DSA topology probe"
|
||||
runlevel = "2345"
|
||||
conditions = { "driver/mt7530" }
|
||||
command = "/usr/sbin/dsa-probe"
|
||||
}
|
||||
|
||||
A driver bound to several devices keeps the condition asserted until
|
||||
the last device is unbound. To wait for one specific device instance,
|
||||
gate on what its probe creates instead: the `class/` condition or
|
||||
`/dev` node of the child device.
|
||||
|
||||
### Power Supply Conditions (`sys/pwr/`)
|
||||
|
||||
keventd monitors the `power_supply` subsystem and provides:
|
||||
|
||||
- `sys/pwr/ac` — asserted when AC power is connected
|
||||
|
||||
This is useful for preventing power-hungry services from running on
|
||||
battery:
|
||||
|
||||
service cron {
|
||||
description = "Cron daemon"
|
||||
runlevel = "2345"
|
||||
conditions = { "sys/pwr/ac", "pid/syslogd" }
|
||||
command = "cron -f"
|
||||
}
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
keventd [-cdGhnpSv] [-g GROUP] [-r DIR] [-t SECONDS]
|
||||
|
||||
Options:
|
||||
-c Run coldplug at startup
|
||||
-d Enable debug mode (foreground, verbose)
|
||||
-g GROUP Override netlink rebroadcast group (default: 4)
|
||||
-G Disable netlink rebroadcast entirely
|
||||
-h Show help text
|
||||
-n Run in foreground (no daemon)
|
||||
-p Passive mode: power supply events only
|
||||
-r DIR Extra rules directory, overrides the standard udev paths
|
||||
-S Settle mode: wait for kernel uevent queue to quiet, then exit
|
||||
-t SEC Settle timeout (default 30s, used with -S)
|
||||
-v Show version
|
||||
|
||||
In normal operation, Finit starts keventd automatically via its system
|
||||
configuration. The `-d` flag is useful for debugging device issues --
|
||||
it runs keventd in the foreground and logs all received uevents.
|
||||
|
||||
`keventd -S` is a one-shot command, not a flag to the running daemon.
|
||||
It is the `udevadm settle` equivalent for migration scenarios:
|
||||
|
||||
keventd -S -t 10 && start-graphical-session
|
||||
|
||||
With D-Bus support it asks the running keventd over
|
||||
[`Device1.Settle`](#d-bus-interface-orgfinitdevice1), which tracks the
|
||||
event queue where the events actually flow. When no bus answers --
|
||||
another device manager, or a build without D-Bus -- it falls back to
|
||||
polling `/sys/kernel/uevent_seqnum` until the kernel's sequence
|
||||
counter has been stable for 200ms, then exits zero. After the
|
||||
`-t SECONDS` timeout (default 30) it exits non-zero instead. The
|
||||
fallback works regardless of which device manager is active, or even
|
||||
if none is.
|
||||
|
||||
Prefer the condition-based model (`<dev/X>`, `<class/...>`,
|
||||
`<driver/...>`) over settle when you control the service definition --
|
||||
settle is racy with slow probes that fire after the queue appears
|
||||
quiet. It is provided for legacy boot scripts and init transitions
|
||||
where condition wiring isn't feasible.
|
||||
|
||||
Debug logging can also be toggled at runtime by sending `SIGUSR1`:
|
||||
|
||||
kill -USR1 $(pidof keventd)
|
||||
|
||||
|
||||
D-Bus Interface (`org.finit.Device1`)
|
||||
-------------------------------------
|
||||
|
||||
With D-Bus support (default, `--disable-dbus` opts out) keventd serves
|
||||
`org.finit.Device1` at `/org/finit/device` on its own brokerless bus,
|
||||
`unix:path=/run/keventd/bus`, the same way Finit serves
|
||||
[`org.finit`](dbus.md) on `/run/finit/bus`. There is no forwarding
|
||||
between the two -- clients that want both connect to both.
|
||||
|
||||
| Method | In sig | Out sig | Priv. | Notes |
|
||||
|---------------|--------|---------|-------|----------------------------------------------|
|
||||
| `Settle` | `u` | `b` | no | Wait until the event queue drains, timeout in seconds; `false` on timeout |
|
||||
| `Trigger` | `ss` | — | yes | Replay events: action, subsystem glob (empty = all) |
|
||||
| `Info` | `s` | `a{ss}` | no | `/run/udev/data` properties for a devpath |
|
||||
| `RulesReload` | — | `u` | yes | Re-read the rules directories, returns rule count |
|
||||
|
||||
| Property | Sig | Notes |
|
||||
|-------------------|-----|-------------------------------------------|
|
||||
| `QueueEmpty` | `b` | No device events in flight |
|
||||
| `SeqnumProcessed` | `t` | Highest kernel seqnum keventd has handled |
|
||||
|
||||
| Signal | Body | Fires when |
|
||||
|-------------------|-------------------------|---------------------------------|
|
||||
| `DeviceProcessed` | `ss` — devpath, action | An event has been fully handled: node, symlinks, database |
|
||||
|
||||
Example, wait up to ten seconds for the queue to drain:
|
||||
|
||||
```sh
|
||||
dbus-send --address=unix:path=/run/keventd/bus \
|
||||
--type=method_call --print-reply --dest=org.finit \
|
||||
/org/finit/device org.finit.Device1.Settle uint32:10
|
||||
```
|
||||
|
||||
In passive mode (`-p`) `Trigger` and `RulesReload` refuse -- device
|
||||
events are not handled here -- while `Settle` and the queue-state
|
||||
properties remain meaningful.
|
||||
|
||||
keventd's conditions are symlinks to Finit's `reconf` generation
|
||||
marker, so they read the current generation by construction and never
|
||||
enter `flux` -- like user-defined conditions, they need no reassert
|
||||
after `initctl reload`. Device state does not change because Finit
|
||||
re-read its configuration.
|
||||
|
||||
|
||||
Integration with Finit
|
||||
----------------------
|
||||
|
||||
keventd is a standalone daemon started by Finit as an internal service.
|
||||
It communicates with Finit exclusively through the filesystem-based
|
||||
condition system — creating and removing symlinks in `/run/finit/cond/`.
|
||||
|
||||
This means keventd can also be tested independently:
|
||||
|
||||
# Run in debug mode to see all kernel events
|
||||
keventd -d
|
||||
|
||||
# Run with coldplug to populate /dev from scratch
|
||||
keventd -c -n
|
||||
|
||||
# Run without rebroadcast (e.g., headless embedded system)
|
||||
keventd -c -G
|
||||
|
||||
Only one device manager should be active at a time. This is settled
|
||||
at build time: with the hotplug plugin enabled, Finit starts keventd
|
||||
in passive mode (`-p`), leaving device management to the udevd, mdevd,
|
||||
or mdev service from `system/10-hotplug.conf` and monitoring only
|
||||
power supply events. Without the hotplug plugin, keventd runs as the
|
||||
system device manager (`keventd -c`).
|
||||
|
||||
[libudev-zero]: https://github.com/illiliti/libudev-zero
|
||||
[mdevd]: https://skarnet.org/software/mdevd/
|
||||
[udev(7)]: https://man7.org/linux/man-pages/man7/udev.7.html
|
||||
|
||||
+21
-3
@@ -35,7 +35,15 @@ For your convenience a set of *optional* plugins are available:
|
||||
> the `/etc/fstab` file and in the Linux kernel config.
|
||||
|
||||
* *dbus.so*: Setup and start system message bus, D-Bus, at boot.
|
||||
_Optional plugin._
|
||||
Enabled by default, and a no-op on systems without a `dbus-daemon`.
|
||||
The daemon is declared in `20-dbus.conf` and its directories in
|
||||
`tmpfiles.d/dbus.conf`, both overridable from `/etc`; the plugin
|
||||
itself only handles what has to inspect the running system.
|
||||
|
||||
Not to be confused with Finit's built-in [D-Bus API](dbus.md): the
|
||||
plugin (`--disable-dbus-plugin`) starts the external system bus
|
||||
daemon, while the built-in support (`--disable-dbus`) is the
|
||||
`org.finit` interface served by Finit itself.
|
||||
|
||||
* *hook-scripts.so*: Trigger the execution of scripts from plugin hook
|
||||
points (see [Hooks](#hooks)). _Optional plugin._
|
||||
@@ -70,8 +78,8 @@ For your convenience a set of *optional* plugins are available:
|
||||
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
|
||||
Modules are by default loaded in runlevel `S` using a `task` block.
|
||||
Each module is named `modprobe.foo`, with an optional `:ID`. The
|
||||
runlevel can be changed per file using:
|
||||
|
||||
set runlevel 2345
|
||||
@@ -205,6 +213,16 @@ hook points:
|
||||
new runlevel have been been stopped. When the hook has completed,
|
||||
Finit 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
|
||||
|
||||
* `HOOK_NETWORK_DN`, `hook/net/down`: Called right after having changed
|
||||
|
||||
+5
-1
@@ -15,7 +15,11 @@ 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
|
||||
run udevadm {
|
||||
description = "Waiting for udev"
|
||||
runlevel = "S"
|
||||
command = "udevadm settle --timeout=120"
|
||||
}
|
||||
```
|
||||
|
||||
Finit has a built-in Getty for TTYs, but requires a working `/bin/login`
|
||||
|
||||
+36
-13
@@ -13,20 +13,37 @@ 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:
|
||||
`task`, or `tty`, set `runlevel` in 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
|
||||
service syslogd {
|
||||
description = "System log daemon"
|
||||
runlevel = "S12345"
|
||||
command = "syslogd -n -x"
|
||||
}
|
||||
run acpid {
|
||||
description = "Starting ACPI Daemon"
|
||||
runlevel = "S"
|
||||
command = "/etc/init.d/acpid start"
|
||||
}
|
||||
task kbd {
|
||||
description = "Preparing console"
|
||||
runlevel = "S"
|
||||
command = "/etc/init.d/kbd start"
|
||||
}
|
||||
service klogd {
|
||||
description = "Kernel log daemon"
|
||||
runlevel = "S12345"
|
||||
conditions = { "pid/syslogd" }
|
||||
command = "klogd -n -x"
|
||||
}
|
||||
|
||||
tty [12345] /dev/tty1
|
||||
tty [2] /dev/tty2
|
||||
tty [2] /dev/tty3
|
||||
tty [2] /dev/tty4
|
||||
tty [2] /dev/tty5
|
||||
tty [2] /dev/tty6
|
||||
tty tty1 { runlevel = "12345" device = "/dev/tty1" }
|
||||
tty tty2 { runlevel = "2" device = "/dev/tty2" }
|
||||
tty tty3 { runlevel = "2" device = "/dev/tty3" }
|
||||
tty tty4 { runlevel = "2" device = "/dev/tty4" }
|
||||
tty tty5 { runlevel = "2" device = "/dev/tty5" }
|
||||
tty tty6 { runlevel = "2" device = "/dev/tty6" }
|
||||
```
|
||||
|
||||
In this example syslogd is first started, in parallel, and then acpid is
|
||||
@@ -46,8 +63,14 @@ 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
|
||||
task foo {
|
||||
runlevel = "S"
|
||||
command = "echo \"foo\" | cat >/tmp/bar"
|
||||
}
|
||||
run secret {
|
||||
runlevel = "S"
|
||||
command = "echo \"$HOME\" >/tmp/secret"
|
||||
}
|
||||
```
|
||||
|
||||
Switching between runlevels can be done by calling init with a single
|
||||
|
||||
+4
-4
@@ -3,18 +3,18 @@ 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
|
||||
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/
|
||||
```aconf
|
||||
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`.
|
||||
No setting 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.
|
||||
|
||||
+30
-9
@@ -27,13 +27,22 @@ Finit can *not* start and monitor a daemon that:
|
||||
|
||||
### Forks to bg w/ PID file
|
||||
|
||||
There are two syntax variants, type 1 and type 2. The former is the
|
||||
traditional one used also for `sysv` start/stop scripts, and the latter
|
||||
is inspired by systemd, with a twist -- it lets Finit guess the pifdile
|
||||
to look for based on the standard path and the basename of the command.
|
||||
There are two variants. The former names the pidfile to watch, as for
|
||||
`sysv` start/stop scripts, and the latter is inspired by systemd, with a
|
||||
twist -- it lets Finit guess the pidfile based on the standard path and
|
||||
the basename of the command.
|
||||
|
||||
service pid:!/run/serv.pid serv -- Forking service, type 1
|
||||
service type:forking serv -- Forking service, type 2
|
||||
service serv {
|
||||
description = "Forking service, type 1"
|
||||
pidfile = "/run/serv.pid"
|
||||
command = "serv"
|
||||
}
|
||||
|
||||
service serv {
|
||||
description = "Forking service, type 2"
|
||||
type = "forking"
|
||||
command = "serv"
|
||||
}
|
||||
|
||||
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
|
||||
@@ -41,17 +50,29 @@ 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 {
|
||||
description = "Foreground service w/ PID file"
|
||||
command = "serv -n -p"
|
||||
}
|
||||
|
||||
### Runs in fg w/o PID file
|
||||
|
||||
Same as previous, but we tell Finit to create the PID file, because we
|
||||
need it to synchronize start/stop of a dependent service.
|
||||
|
||||
service pid:/run/serv.pid serv -n -- Foreground service w/o PID file
|
||||
service serv {
|
||||
description = "Foreground service w/o PID file"
|
||||
pidfile = "/run/serv.pid"
|
||||
pidfile-create = true
|
||||
command = "serv -n"
|
||||
}
|
||||
|
||||
### Runs in fg w/ custom PID file
|
||||
|
||||
service pid:/run/servy.pid serv -n -p -P /run/servy.pid -- Foreground service w/ custom PID file
|
||||
service serv {
|
||||
description = "Foreground service w/ custom PID file"
|
||||
pidfile = "/run/servy.pid"
|
||||
command = "serv -n -p -P /run/servy.pid"
|
||||
}
|
||||
|
||||
[1]: config/service-sync.md
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
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 mount-root {
|
||||
description = "Mounting root filesystem"
|
||||
runlevel = "S"
|
||||
command = "/bin/mount /dev/sda1 /mnt/root"
|
||||
}
|
||||
|
||||
# Switch to real root after mount completes
|
||||
run switch-root {
|
||||
description = "Switching to real root"
|
||||
runlevel = "S"
|
||||
command = "/sbin/initctl switch-root /mnt/root"
|
||||
}
|
||||
```
|
||||
|
||||
For more complex setups (LUKS, LVM, etc.):
|
||||
|
||||
```
|
||||
# Unlock LUKS volume
|
||||
# The tty setting is required so cryptsetup can prompt for a passphrase
|
||||
run cryptsetup {
|
||||
description = "Unlocking encrypted root"
|
||||
runlevel = "S"
|
||||
tty = "@console"
|
||||
command = "/sbin/cryptsetup open /dev/sda2 cryptroot"
|
||||
}
|
||||
|
||||
# Activate LVM
|
||||
run lvm {
|
||||
description = "Activating LVM volumes"
|
||||
runlevel = "S"
|
||||
command = "/sbin/lvm vgchange -ay"
|
||||
}
|
||||
|
||||
# Mount root
|
||||
run mount-root {
|
||||
description = "Mounting root"
|
||||
runlevel = "S"
|
||||
command = "/bin/mount /dev/vg0/root /mnt/root"
|
||||
}
|
||||
|
||||
# Switch root
|
||||
run switch-root {
|
||||
description = "Switching to real root"
|
||||
runlevel = "S"
|
||||
command = "/sbin/initctl switch-root /mnt/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 mdevd {
|
||||
description = "Device event daemon"
|
||||
runlevel = "S"
|
||||
notify = "s6"
|
||||
command = "/sbin/mdevd -D %n"
|
||||
}
|
||||
run coldplug {
|
||||
description = "Coldplug devices"
|
||||
runlevel = "S"
|
||||
conditions = { "service/mdevd/ready" }
|
||||
command = "/sbin/mdevd-coldplug"
|
||||
}
|
||||
|
||||
# Mount the real root filesystem (after devices are ready)
|
||||
run mount-root {
|
||||
description = "Mounting root"
|
||||
runlevel = "S"
|
||||
conditions = { "run/coldplug/success" }
|
||||
command = "/bin/mount /dev/sda1 /mnt/root"
|
||||
}
|
||||
|
||||
# Transition to runlevel 1 after all S tasks complete
|
||||
# The switch-root runs cleanly in runlevel 1
|
||||
run switch-root {
|
||||
description = "Switching to real root"
|
||||
runlevel = "1"
|
||||
command = "/sbin/initctl switch-root /mnt/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)
|
||||
+4
-4
@@ -1,10 +1,10 @@
|
||||
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
|
||||
A separate service is built and installed in `/libexec/finit/watchdogd`,
|
||||
unless disabled with `--without-watchdog`. 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
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
.deps/
|
||||
keventd
|
||||
Makefile
|
||||
Makefile.in
|
||||
@@ -0,0 +1,67 @@
|
||||
AM_CPPFLAGS = -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/src
|
||||
|
||||
pkglibexec_PROGRAMS = keventd
|
||||
|
||||
keventd_SOURCES = keventd.c keventd.h uevent.c \
|
||||
udevdb.c udevdb.h \
|
||||
sysfs.c sysfs.h \
|
||||
rules.c rules.h \
|
||||
builtin.c builtin.h \
|
||||
$(top_srcdir)/src/util.c $(top_srcdir)/src/util.h
|
||||
# Per-target flags exist even when their conditional is false, so
|
||||
# assign the base unconditionally and append under DBUS
|
||||
keventd_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
keventd_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||
# Silence noisy false positives from PATH_MAX-into-PATH_MAX sysfs path
|
||||
# concatenations; real concerns (e.g. USB strings into small buffers) are
|
||||
# handled via explicit checks where present. Matches systemd-udev policy.
|
||||
keventd_CFLAGS += -Wno-format-truncation
|
||||
keventd_CFLAGS += $(lite_CFLAGS)
|
||||
keventd_CFLAGS += $(uev_CFLAGS)
|
||||
keventd_CFLAGS += $(blkid_CFLAGS)
|
||||
keventd_LDADD = $(lite_LIBS)
|
||||
keventd_LDADD += $(uev_LIBS)
|
||||
keventd_LDADD += $(blkid_LIBS)
|
||||
|
||||
if DBUS
|
||||
keventd_SOURCES += dbus.c
|
||||
keventd_CPPFLAGS += -I$(top_srcdir)/libink
|
||||
keventd_LDADD += $(top_builddir)/libink/libink.la
|
||||
endif
|
||||
|
||||
# Curated udev rules derived from eudev 3.2.14 (GPL-2.0-or-later).
|
||||
# Installed to /lib/udev/rules.d/ so existing third-party rules and
|
||||
# local overrides under /etc/udev/rules.d/ coexist with standard udev
|
||||
# precedence. See .notes/curated-rules-manifest.md.
|
||||
if UDEV_RULES
|
||||
udevrulesdir = $(prefix)/lib/udev/rules.d
|
||||
dist_udevrules_DATA = \
|
||||
rules.d/50-udev-default.rules \
|
||||
rules.d/60-autosuspend.rules \
|
||||
rules.d/60-block.rules \
|
||||
rules.d/60-cdrom_id.rules \
|
||||
rules.d/60-drm.rules \
|
||||
rules.d/60-evdev.rules \
|
||||
rules.d/60-fido-id.rules \
|
||||
rules.d/60-input-id.rules \
|
||||
rules.d/60-persistent-alsa.rules \
|
||||
rules.d/60-persistent-input.rules \
|
||||
rules.d/60-persistent-storage.rules \
|
||||
rules.d/60-persistent-storage-tape.rules \
|
||||
rules.d/60-persistent-v4l.rules \
|
||||
rules.d/60-sensor.rules \
|
||||
rules.d/60-serial.rules \
|
||||
rules.d/64-btrfs.rules \
|
||||
rules.d/70-camera.rules \
|
||||
rules.d/70-joystick.rules \
|
||||
rules.d/70-memory.rules \
|
||||
rules.d/70-mouse.rules \
|
||||
rules.d/70-touchpad.rules \
|
||||
rules.d/75-net-description.rules \
|
||||
rules.d/75-probe_mtd.rules \
|
||||
rules.d/78-sound-card.rules \
|
||||
rules.d/80-drivers.rules \
|
||||
rules.d/80-net-name-slot.rules \
|
||||
rules.d/81-net-dhcp.rules
|
||||
endif
|
||||
+1529
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user