mirror of
https://github.com/troglobit/finit.git
synced 2026-10-12 10:12:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f32e4d4b30 | ||
|
|
eff87b3dc5 | ||
|
|
ea4821fd18 | ||
|
|
6285668dcd | ||
|
|
449bc7d12b | ||
|
|
ee867e7f3b | ||
|
|
b4c7ae9c8c | ||
|
|
95995a45cf | ||
|
|
823bb82b8c | ||
|
|
9a5bb46f78 | ||
|
|
950ca953f5 | ||
|
|
495c8c9eac | ||
|
|
2887795586 | ||
|
|
6a893f50ae | ||
|
|
5d08353284 | ||
|
|
a37037ded4 | ||
|
|
d331b72dfd | ||
|
|
3b21d35f23 | ||
|
|
62a694b8b7 | ||
|
|
eeba2960f9 | ||
|
|
91550c926b | ||
|
|
184525687c | ||
|
|
cdede817fd | ||
|
|
df42c2f6fe | ||
|
|
b53f2f4a60 | ||
|
|
5ff27c4fe2 | ||
|
|
e5fff5117d | ||
|
|
615cd5aac3 | ||
|
|
621d95a89e | ||
|
|
cd383167f9 | ||
|
|
cb2969002c | ||
|
|
1cf204e23d | ||
|
|
393834b253 | ||
|
|
4ca8256e18 | ||
|
|
280d91b9bf | ||
|
|
980152fd53 | ||
|
|
d994420d4d | ||
|
|
38f3ecf01f | ||
|
|
5cd0d05b31 | ||
|
|
62519c3638 | ||
|
|
27bb2deb1a | ||
|
|
a2c8e71f14 | ||
|
|
d1f56e7c2e | ||
|
|
a9fd0cbf02 | ||
|
|
be8c89ec00 | ||
|
|
4f53752693 | ||
|
|
393673222d | ||
|
|
a88f4524d5 | ||
|
|
3a02066a66 | ||
|
|
7e3981d1a3 | ||
|
|
ec2900e4dd | ||
|
|
d718a27abf | ||
|
|
db8027911c | ||
|
|
aef3b4117d | ||
|
|
6728b77aca | ||
|
|
a7c0b42965 | ||
|
|
667b6ecbbd | ||
|
|
b852878a4a | ||
|
|
940f1f7486 | ||
|
|
49c705b5ad | ||
|
|
5163e8a433 | ||
|
|
71e9603e4e | ||
|
|
c71102f44e | ||
|
|
9b9158a765 | ||
|
|
595e2b4e81 | ||
|
|
ae8e205343 | ||
|
|
00b33fbd42 | ||
|
|
841b06df37 | ||
|
|
522a06f864 | ||
|
|
fa14ed1649 | ||
|
|
64e41e066b | ||
|
|
2a71f35005 | ||
|
|
961a337a5e | ||
|
|
f0622a692e | ||
|
|
ef7042dd9d | ||
|
|
046ecfa329 | ||
|
|
47fbe49861 | ||
|
|
2f34315634 | ||
|
|
c8d6ad6546 | ||
|
|
3dfae3074e | ||
|
|
97bebe52c9 | ||
|
|
8e1845f57b | ||
|
|
6cd6769997 | ||
|
|
03884d3566 | ||
|
|
899925e249 | ||
|
|
efefa398ce | ||
|
|
1ee24c69bc | ||
|
|
b16a36980c | ||
|
|
c1b52bbc04 | ||
|
|
9461ad4d4d | ||
|
|
e2ef6e9c34 | ||
|
|
cdc8873f5b | ||
|
|
b82b205d92 | ||
|
|
39d879f240 | ||
|
|
9c1db9cab3 | ||
|
|
2f5c00f2bd | ||
|
|
dc36b313ff | ||
|
|
093fa0107a | ||
|
|
e8f5ec2579 | ||
|
|
62241668df | ||
|
|
ee67c08b64 | ||
|
|
41a14391a2 | ||
|
|
6eccca31b9 | ||
|
|
d497942a9f | ||
|
|
68c7352108 | ||
|
|
0d40e43c4b | ||
|
|
9867fd82df | ||
|
|
1c941fdfbb | ||
|
|
0ba67a72f8 | ||
|
|
09b9e26b2d | ||
|
|
d25c1d5564 | ||
|
|
d4358ed3f7 | ||
|
|
cc6ffa35fc | ||
|
|
55e9cb2f58 | ||
|
|
2641256254 | ||
|
|
473116f603 | ||
|
|
e18d63df4a | ||
|
|
4b1b3f6913 | ||
|
|
f6da5e4136 | ||
|
|
d1d5d39144 | ||
|
|
754358113f | ||
|
|
c24207516d | ||
|
|
2a23bce78d | ||
|
|
a19b82ea5f | ||
|
|
ed9590aef1 | ||
|
|
25683221cc | ||
|
|
9cc9e3ddbb | ||
|
|
654f8aeb19 | ||
|
|
e349abb897 | ||
|
|
3027a6755f | ||
|
|
5404aa6037 | ||
|
|
a319e32438 | ||
|
|
2eaf57fc67 | ||
|
|
88ec4a55cb | ||
|
|
0acbc60ec1 | ||
|
|
4362971c6a | ||
|
|
94c0d1b833 | ||
|
|
1e795d4e16 | ||
|
|
93a027ca23 | ||
|
|
5f3958fab4 | ||
|
|
1351b708fe | ||
|
|
e867e039bb | ||
|
|
1d1087a3b3 | ||
|
|
e91f1ea1b2 | ||
|
|
55d16edadc | ||
|
|
b79245ddb3 | ||
|
|
e706300b6d | ||
|
|
d08cbd77aa | ||
|
|
b070ae73a4 | ||
|
|
2c30eef9a1 | ||
|
|
31cdc113fc | ||
|
|
f6f813498b | ||
|
|
4c8baaf7c0 | ||
|
|
57ca937f27 | ||
|
|
d13e39e345 | ||
|
|
f52c141062 | ||
|
|
40042da8ff | ||
|
|
c251304146 | ||
|
|
c047e37a79 | ||
|
|
d2c57447f0 | ||
|
|
79e9dabc11 | ||
|
|
b04dc4d457 | ||
|
|
f86e7810be | ||
|
|
2018c82ea1 | ||
|
|
c27f3603e6 | ||
|
|
6f82b806ad | ||
|
|
cbb8935660 | ||
|
|
21ebbb942f | ||
|
|
988ecd95e3 | ||
|
|
3f3e70c686 | ||
|
|
073b040981 | ||
|
|
b1a058ccdd | ||
|
|
cbc7b8c3c7 | ||
|
|
13340e4200 | ||
|
|
0076c1f218 | ||
|
|
6fc71b7528 | ||
|
|
b42f1e99e2 | ||
|
|
afd6ad06a6 | ||
|
|
ea0bfaa2f3 | ||
|
|
5c3ec176c2 | ||
|
|
40425ee9ec | ||
|
|
424db825a3 | ||
|
|
b9cc4cd629 | ||
|
|
243b8f025b | ||
|
|
6c60b67588 | ||
|
|
910bb13711 | ||
|
|
add55cfc2a | ||
|
|
565820325b | ||
|
|
6bb4d67d92 | ||
|
|
534d50c03a | ||
|
|
9a42883a96 | ||
|
|
7c77e2c2b6 | ||
|
|
ea8c46cd30 | ||
|
|
fead3b0671 | ||
|
|
081990b49e | ||
|
|
6b89f8c6db | ||
|
|
373097040a | ||
|
|
a4ab75172c | ||
|
|
5cf9958957 | ||
|
|
b137e08e84 | ||
|
|
a1af8e8687 | ||
|
|
53c7ddcb22 | ||
|
|
3872077ff1 | ||
|
|
9e85c4f3d1 | ||
|
|
2531102623 | ||
|
|
33deada6f0 | ||
|
|
9d1506bb7e | ||
|
|
c3f115c9ec | ||
|
|
430d402b14 | ||
|
|
e011dac98b | ||
|
|
42b84d1ccb | ||
|
|
288105eac7 | ||
|
|
842b522e68 | ||
|
|
e6f36974c8 | ||
|
|
679b4df881 | ||
|
|
666cae6f49 | ||
|
|
be2ac1d1b1 | ||
|
|
266e5b30eb | ||
|
|
4e5d06b580 | ||
|
|
fe334135ce | ||
|
|
aef10fb5e7 | ||
|
|
86707c1f0b | ||
|
|
a28d5b3c09 | ||
|
|
550ae9c784 | ||
|
|
cd5b91680a | ||
|
|
221ab20898 | ||
|
|
96534789db | ||
|
|
26128dd788 | ||
|
|
799e992542 | ||
|
|
fa524eec60 | ||
|
|
6dced29b49 | ||
|
|
2ea613a42b | ||
|
|
985df20519 | ||
|
|
f6161b9be9 | ||
|
|
25c5014d3c | ||
|
|
b8b7b53d96 | ||
|
|
7707c4b8e6 | ||
|
|
437f95f00f | ||
|
|
099672fabb | ||
|
|
860515a716 | ||
|
|
c85551a42e | ||
|
|
79dc6e7472 | ||
|
|
06e456384c | ||
|
|
38f7d24a80 | ||
|
|
145c78ef3e | ||
|
|
dd437bf0a5 | ||
|
|
d82d119729 | ||
|
|
7f76202865 | ||
|
|
aee92751ac | ||
|
|
2ea7236d45 | ||
|
|
cedc04e1e3 | ||
|
|
edc6eb1747 | ||
|
|
be5ec94fdf | ||
|
|
23a13fe1b6 | ||
|
|
0168b765c1 | ||
|
|
01358a5a45 | ||
|
|
106516d12d | ||
|
|
ba858743e5 | ||
|
|
9fd860ef3c | ||
|
|
46ccdc3820 | ||
|
|
242fe54afd | ||
|
|
df5d296cd9 | ||
|
|
dc4630f214 | ||
|
|
ac07d3bac7 | ||
|
|
f641eef8f7 | ||
|
|
f17b5b3cd3 | ||
|
|
d945f4960b | ||
|
|
6a5a6ac62f | ||
|
|
a9ba4300ec | ||
|
|
7bb649f11a | ||
|
|
85ada0ac99 | ||
|
|
be343a3b34 | ||
|
|
0ac0e5c7d3 | ||
|
|
7f272768e4 | ||
|
|
7b74c9900f | ||
|
|
36f1a39b31 | ||
|
|
6d380082eb | ||
|
|
8d3917e9fa | ||
|
|
c3cd1a5bfa | ||
|
|
eaeddc36c2 | ||
|
|
4f40b65f0c | ||
|
|
f958aa504e | ||
|
|
3d1b95aa7a | ||
|
|
4bb67bc06f | ||
|
|
0929c93caf | ||
|
|
c0368d2b16 | ||
|
|
85a212ef93 | ||
|
|
12c3cb3dc0 | ||
|
|
16710e7ab5 | ||
|
|
b652aaf0cb | ||
|
|
30020263ba | ||
|
|
3cf5d36972 | ||
|
|
c9ae96bcf7 | ||
|
|
5955110e67 | ||
|
|
4191e15c77 | ||
|
|
d60baa2b80 | ||
|
|
a50bc331db | ||
|
|
eff4453de9 | ||
|
|
4cfc8fec0e | ||
|
|
c9e1c2f80f | ||
|
|
93039e40cc | ||
|
|
015a52a20d | ||
|
|
d53cc8bfe7 | ||
|
|
3c4eca60b7 | ||
|
|
c85e28b971 | ||
|
|
d373068619 | ||
|
|
997f3d7862 | ||
|
|
f12f53692e | ||
|
|
b921b8cf0f | ||
|
|
61781c72fe | ||
|
|
3b5cfc5ecf | ||
|
|
a42a789d29 | ||
|
|
d77c014723 | ||
|
|
23fca9c067 | ||
|
|
37eb1901f9 | ||
|
|
98c4e7764f | ||
|
|
d3e4463612 | ||
|
|
b812045d82 | ||
|
|
b1bcdc88e0 | ||
|
|
62c5a9d06d | ||
|
|
dcdc842336 | ||
|
|
12eaa3073a | ||
|
|
34875f57a5 | ||
|
|
f0bf1343b0 | ||
|
|
4e6b9514d5 | ||
|
|
3b495d7518 | ||
|
|
badf8701bf | ||
|
|
85fa0d4926 | ||
|
|
3de9643893 | ||
|
|
73629944c0 | ||
|
|
c97c83bfb6 | ||
|
|
19b18afac9 | ||
|
|
e3c424e129 | ||
|
|
c0716d7f63 | ||
|
|
d43af8c9c1 | ||
|
|
2825100f77 | ||
|
|
b1bee31d61 | ||
|
|
522276b80d | ||
|
|
7bc1470a1e | ||
|
|
ca32cb0dfc | ||
|
|
d59f55b90c | ||
|
|
02936de993 | ||
|
|
8ed223343d | ||
|
|
90f7ff1c23 | ||
|
|
a56220f158 | ||
|
|
d40b426c1b | ||
|
|
5342881bf4 | ||
|
|
c84c17ea8c | ||
|
|
f976b8261f | ||
|
|
10f4c7fa18 | ||
|
|
665d212bd6 | ||
|
|
9e6e653c57 | ||
|
|
bda4da71a6 | ||
|
|
a24fc941a6 | ||
|
|
f307ad060b | ||
|
|
1845b7be54 | ||
|
|
a260e157eb | ||
|
|
0641b1a73e | ||
|
|
9ba57f0c9d | ||
|
|
9c2f0b2dc8 | ||
|
|
d4bbebeb93 | ||
|
|
1a22b4f0aa | ||
|
|
9c4d5341ae | ||
|
|
b9d498e01c | ||
|
|
a1e38a3e40 | ||
|
|
c0ae7763a6 | ||
|
|
9f98b1d3d1 | ||
|
|
a7e2224f05 | ||
|
|
3bb1e41394 | ||
|
|
e437379939 | ||
|
|
3ad4f6ef4b | ||
|
|
4170a61d0b | ||
|
|
b3c5ab41e7 | ||
|
|
b3fad1077e | ||
|
|
522e1f57d7 | ||
|
|
d00a53dfbf | ||
|
|
ff86f29f41 | ||
|
|
3107027132 | ||
|
|
728db73b09 | ||
|
|
fcb8ec9967 | ||
|
|
5b8fe12502 | ||
|
|
6e24f2ff13 | ||
|
|
74d715243c | ||
|
|
d9993860cb | ||
|
|
6a6f3a8291 | ||
|
|
99a8cf3eb7 | ||
|
|
da95c7d80e | ||
|
|
a9f7f692a9 | ||
|
|
ce55f88a00 | ||
|
|
74a26f559d | ||
|
|
08144df5ea | ||
|
|
230c64927b | ||
|
|
d1e56f300d | ||
|
|
9842786453 | ||
|
|
6d0c679e05 | ||
|
|
5428dea5bf | ||
|
|
4e84ecae89 | ||
|
|
959c9fe5aa | ||
|
|
03d8ef9c8f | ||
|
|
084b4ce8d3 | ||
|
|
31cae6a56d | ||
|
|
1fd45c6f2e | ||
|
|
46995fe446 | ||
|
|
600b2874e6 | ||
|
|
b080b970b7 | ||
|
|
6106574e13 | ||
|
|
2385a1209b | ||
|
|
e8b942cf95 | ||
|
|
ac17d7f5a7 | ||
|
|
1edc4356a6 | ||
|
|
9f06a2db99 | ||
|
|
cfb3a9f2b9 | ||
|
|
8aba63a9e3 | ||
|
|
3d98ad293b | ||
|
|
156e86f395 | ||
|
|
d859ecd21d | ||
|
|
cbec78dbbc | ||
|
|
572291a1d9 | ||
|
|
280608f30e | ||
|
|
5c4146cfe4 | ||
|
|
30e3f5a33c | ||
|
|
2c12379a30 | ||
|
|
5f026c8149 | ||
|
|
90005235e8 | ||
|
|
6b688c4211 | ||
|
|
bdf5f8fc90 | ||
|
|
79f7a8ccfb | ||
|
|
3b19db04e3 | ||
|
|
93402b81d7 | ||
|
|
6dec4c9ca0 | ||
|
|
548acf27cf | ||
|
|
cd0bc57ca8 | ||
|
|
11a3318c02 | ||
|
|
2711b27971 | ||
|
|
05ac9c18c9 | ||
|
|
1a7092f545 | ||
|
|
8000d361b3 | ||
|
|
e3c8febe3b | ||
|
|
32ca117949 | ||
|
|
b966d031c8 | ||
|
|
905c2678a3 | ||
|
|
7d429bdbb1 |
@@ -0,0 +1,68 @@
|
|||||||
|
name: Bob the Builder
|
||||||
|
|
||||||
|
# Run on all branches, including all pull requests, except the 'dev'
|
||||||
|
# branch since that's where we run Coverity Scan (limited tokens/day)
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- '**'
|
||||||
|
- '!dev'
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- '**'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
# Verify we can build on latest Ubuntu with both gcc and clang
|
||||||
|
name: ${{ matrix.compiler }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
compiler: [gcc, clang]
|
||||||
|
fail-fast: false
|
||||||
|
env:
|
||||||
|
MAKEFLAGS: -j3
|
||||||
|
CC: ${{ matrix.compiler }}
|
||||||
|
steps:
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get -y update
|
||||||
|
sudo apt-get -y install pkg-config
|
||||||
|
wget https://github.com/troglobit/libuev/releases/download/v2.3.2/libuev-2.3.2.tar.xz
|
||||||
|
wget https://github.com/troglobit/libite/releases/download/v2.3.1/libite-2.3.1.tar.gz
|
||||||
|
tar xf libuev-2.3.2.tar.xz
|
||||||
|
tar xf libite-2.3.1.tar.gz
|
||||||
|
(cd libuev-2.3.2 && ./configure --prefix=/usr && make && sudo make install-strip)
|
||||||
|
(cd libite-2.3.1 && ./configure --prefix=/usr && make && sudo make install-strip)
|
||||||
|
sudo ldconfig
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Static Finit
|
||||||
|
run: |
|
||||||
|
./autogen.sh
|
||||||
|
./configure --prefix= --enable-static
|
||||||
|
make V=1
|
||||||
|
- name: Regular Finit
|
||||||
|
run: |
|
||||||
|
./configure --prefix= --enable-x11-common-plugin --with-watchdog --with-keventd
|
||||||
|
make clean
|
||||||
|
make V=1
|
||||||
|
- name: Install to ~/tmp and Inspect
|
||||||
|
run: |
|
||||||
|
DESTDIR=/tmp make install-strip
|
||||||
|
tree /tmp
|
||||||
|
ldd /tmp/sbin/finit
|
||||||
|
size /tmp/sbin/finit
|
||||||
|
ldd /tmp/sbin/initctl
|
||||||
|
size /tmp/sbin/initctl
|
||||||
|
ldd /tmp/sbin/reboot
|
||||||
|
size /tmp/sbin/reboot
|
||||||
|
/tmp/sbin/finit -h
|
||||||
|
/tmp/sbin/initctl -h
|
||||||
|
- name: Run Unit Tests
|
||||||
|
run: |
|
||||||
|
make -j1 distcheck
|
||||||
|
- name: Upload Test Results
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: finit-test-${{ matrix.compiler }}
|
||||||
|
path: test/*
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
name: Coverity Scan
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'dev'
|
||||||
|
|
||||||
|
env:
|
||||||
|
PROJECT_NAME: finit
|
||||||
|
CONTACT_EMAIL: troglobit@gmail.com
|
||||||
|
COVERITY_NAME: troglobit-finit
|
||||||
|
COVERITY_PROJ: troglobit%2Ffinit
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
coverity:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/cache@v2
|
||||||
|
id: coverity-toolchain-cache
|
||||||
|
with:
|
||||||
|
path: cov-analysis-linux64
|
||||||
|
key: ${{ runner.os }}-coverity
|
||||||
|
- name: Download Coverity Scan
|
||||||
|
if: steps.coverity-toolchain-cache.outputs.cache-hit != 'true'
|
||||||
|
env:
|
||||||
|
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
|
||||||
|
run: |
|
||||||
|
wget -q https://scan.coverity.com/download/cxx/linux64 \
|
||||||
|
--post-data "token=$TOKEN&project=${COVERITY_PROJ}" \
|
||||||
|
-O cov-analysis-linux64.tar.gz
|
||||||
|
mkdir cov-analysis-linux64
|
||||||
|
tar xzf cov-analysis-linux64.tar.gz --strip 1 -C cov-analysis-linux64
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get -y update
|
||||||
|
sudo apt-get -y install pkg-config
|
||||||
|
wget https://github.com/troglobit/libuev/releases/download/v2.3.2/libuev-2.3.2.tar.xz
|
||||||
|
wget https://github.com/troglobit/libite/releases/download/v2.3.1/libite-2.3.1.tar.gz
|
||||||
|
tar xf libuev-2.3.2.tar.xz
|
||||||
|
tar xf libite-2.3.1.tar.gz
|
||||||
|
(cd libuev-2.3.2 && ./configure --prefix=/usr && make && sudo make install-strip)
|
||||||
|
(cd libite-2.3.1 && ./configure --prefix=/usr && make && sudo make install-strip)
|
||||||
|
sudo ldconfig
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
./autogen.sh
|
||||||
|
./configure --prefix= --enable-x11-common-plugin --with-watchdog --with-keventd
|
||||||
|
export PATH=`pwd`/cov-analysis-linux64/bin:$PATH
|
||||||
|
cov-build --dir cov-int make
|
||||||
|
- name: Submit result to Coverity Scan
|
||||||
|
env:
|
||||||
|
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
|
||||||
|
run: |
|
||||||
|
tar czvf ${PROJECT_NAME}.tgz cov-int
|
||||||
|
curl \
|
||||||
|
--form project=${COVERITY_NAME} \
|
||||||
|
--form token=$TOKEN \
|
||||||
|
--form email=${CONTACT_EMAIL} \
|
||||||
|
--form file=@${PROJECT_NAME}.tgz \
|
||||||
|
--form version=trunk \
|
||||||
|
--form description="${PROJECT_NAME} $(git rev-parse HEAD)" \
|
||||||
|
https://scan.coverity.com/builds?project=${COVERITY_PROJ}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
name: Release General
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- '[0-9]+.[0-9]+'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
name: Create GitHub release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
outputs:
|
||||||
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
|
release_id: ${{ steps.create_release.outputs.id }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Extract ChangeLog entry ...
|
||||||
|
# Hack to extract latest entry for body_path below
|
||||||
|
run: |
|
||||||
|
awk '/-----*/{if (x == 1) exit; x=1;next}x' ChangeLog.md \
|
||||||
|
|head -n -1 > release.md
|
||||||
|
cat release.md
|
||||||
|
- name: Create release ...
|
||||||
|
id: create_release
|
||||||
|
uses: actions/create-release@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
tag_name: ${{ github.ref }}
|
||||||
|
release_name: Finit v${{ github.ref }}
|
||||||
|
body_path: release.md
|
||||||
|
draft: false
|
||||||
|
prerelease: false
|
||||||
|
tarball:
|
||||||
|
name: Build and upload release tarball
|
||||||
|
needs: release
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Installing dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get -y update
|
||||||
|
sudo apt-get -y install pkg-config
|
||||||
|
wget https://github.com/troglobit/libuev/releases/download/v2.3.2/libuev-2.3.2.tar.xz
|
||||||
|
wget https://github.com/troglobit/libite/releases/download/v2.3.1/libite-2.3.1.tar.gz
|
||||||
|
tar xf libuev-2.3.2.tar.xz
|
||||||
|
tar xf libite-2.3.1.tar.gz
|
||||||
|
(cd libuev-2.3.2 && ./configure --prefix=/usr && make && sudo make install-strip)
|
||||||
|
(cd libite-2.3.1 && ./configure --prefix=/usr && make && sudo make install-strip)
|
||||||
|
sudo ldconfig
|
||||||
|
- name: Creating Makefiles
|
||||||
|
run: |
|
||||||
|
./autogen.sh
|
||||||
|
./configure --prefix= --enable-x11-common-plugin --with-watchdog --with-keventd
|
||||||
|
- name: Building release
|
||||||
|
run: |
|
||||||
|
make release
|
||||||
|
ls -lF ../
|
||||||
|
mkdir -p artifacts/
|
||||||
|
mv ../*.tar.* artifacts/
|
||||||
|
- name: Uploading release artifacts
|
||||||
|
uses: skx/github-action-publish-binaries@release-0.15
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
releaseId: ${{ needs.release.outputs.release_id }}
|
||||||
|
args: artifacts/*
|
||||||
-62
@@ -1,62 +0,0 @@
|
|||||||
# Travis CI integration -- https://travis-ci.org/troglobit/finit
|
|
||||||
# Defaults to GNU GCC and autotools: ./configure && make && make test
|
|
||||||
language: c
|
|
||||||
|
|
||||||
# Use docker for quicker builds, it now allows https://docs.travis-ci.com/user/apt/
|
|
||||||
sudo: false
|
|
||||||
|
|
||||||
# Test build with both GCC and Clang (LLVM)
|
|
||||||
compiler:
|
|
||||||
- gcc
|
|
||||||
- clang
|
|
||||||
|
|
||||||
# The secure: declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
|
||||||
# via the "travis encrypt" command using the project repo's public key
|
|
||||||
env:
|
|
||||||
global:
|
|
||||||
- PKG_CONFIG_PATH=/tmp/lib/pkgconfig
|
|
||||||
- CFLAGS="-W -Wall -Wextra"
|
|
||||||
- secure: "eOiuHs02lG2Uv146K9dMqucGTWUJFEhpz1oAtwe+kPrRXsXWc20hYMO+DSpMgD05vSvNeQA6p7h7LdRFQ+/g/Obj27TsOE+RKkUvRAtdwzxnKVyii9C/nmML8cFw7rIA0VS8O9mAkVYeyDxNDupBp3e9DPCibhKPvqCvioTnyy4="
|
|
||||||
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
packages:
|
|
||||||
- tree
|
|
||||||
coverity_scan:
|
|
||||||
project:
|
|
||||||
name: "troglobit/finit"
|
|
||||||
description: "finit | Fast & Extensible init for Linux"
|
|
||||||
notification_email: troglobit@gmail.com
|
|
||||||
build_command_prepend: "./autogen.sh && ./configure --prefix=/tmp --disable-doc --disable-contrib --enable-watchdog --enable-fallback-shell"
|
|
||||||
build_command: "make"
|
|
||||||
branch_pattern: dev
|
|
||||||
|
|
||||||
install:
|
|
||||||
- wget https://github.com/troglobit/libuev/releases/download/v2.3.2/libuev-2.3.2.tar.xz
|
|
||||||
- wget https://github.com/troglobit/libite/releases/download/v2.3.1/libite-2.3.1.tar.gz
|
|
||||||
- tar xf libuev-2.3.2.tar.xz
|
|
||||||
- tar xf libite-2.3.1.tar.gz
|
|
||||||
- (cd libuev-2.3.2 && ./configure --prefix=/tmp && make && make install-strip)
|
|
||||||
- (cd libite-2.3.1 && ./configure --prefix=/tmp && make && make install-strip)
|
|
||||||
|
|
||||||
# Custom build script for the time being, no "make test" yet
|
|
||||||
script:
|
|
||||||
- ./autogen.sh
|
|
||||||
- ./configure --prefix=/tmp --enable-static
|
|
||||||
- make clean
|
|
||||||
- make V=1 -j5
|
|
||||||
- ./configure --prefix=/tmp --enable-x11-common-plugin --enable-fallback-shell --enable-watchdog
|
|
||||||
- cat config.log
|
|
||||||
- make clean
|
|
||||||
- make V=1 -j5
|
|
||||||
- make install-strip
|
|
||||||
- tree /tmp
|
|
||||||
- ldd /tmp/sbin/finit
|
|
||||||
- size /tmp/sbin/finit
|
|
||||||
- size /tmp/sbin/initctl
|
|
||||||
- size /tmp/sbin/reboot
|
|
||||||
- LD_LIBRARY_PATH=/tmp/lib /tmp/sbin/initctl -h
|
|
||||||
- unshare -V
|
|
||||||
- nsenter -V
|
|
||||||
- chroot --version
|
|
||||||
- 'LD_LIBRARY_PATH=/tmp/lib make distcheck || (cat finit-4.0-beta1/_build/sub/test/test-suite.log; exit 1)'
|
|
||||||
+217
-27
@@ -4,12 +4,175 @@ Change Log
|
|||||||
All relevant changes are documented in this file.
|
All relevant changes are documented in this file.
|
||||||
|
|
||||||
|
|
||||||
[4.0][UNRELEASED] - 2021-02-21
|
[4.2][] - 2022-01-16
|
||||||
------------------------------
|
--------------------
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
* Support for non-root users to use `initctl`, e.g. group wheel
|
||||||
|
* Support for new libite (-lite) header namespace
|
||||||
|
* RTC plugin now reset an invalid RTC time to the kernel default
|
||||||
|
time, 2000-01-01 00:00, prevents errors and is less crazy than
|
||||||
|
some systems coming with with <= Jan 1, 1970
|
||||||
|
* urandom plugin now use RNDADDENTROPY ioctl to seed kernel rng,
|
||||||
|
incrementing entropy count. Also, 32 kiB instead of 512 bytes are
|
||||||
|
now saved (and restored) on reboot. This should greatly improve
|
||||||
|
reliability of systems with none or poor HWRNG
|
||||||
|
* Kernel logging to console (loglevel >= 7, debug, when quiet mode is
|
||||||
|
not used) is now honored by Finit, regardless of the finit.debug
|
||||||
|
command line option
|
||||||
|
* Reduced default log level from `LOG_NOTICE` to `LOG_INFO`
|
||||||
|
* Wrapped all calls to mount(2) to add logging in case of failure
|
||||||
|
* New configure options to control fastboot (no fsck) and fsck fix
|
||||||
|
options, by Ming Liu, Atlas Copco
|
||||||
|
* Support for overriding default `/etc/nologin` file with an external
|
||||||
|
`#define`, by Ming Liu, Atlas Copco
|
||||||
|
* Support for overriding default `/var/run/dbus/pid` file with an
|
||||||
|
external `#define`, by Ming Liu, Atlas Copco
|
||||||
|
* Support for more service options to control respawn behavior of
|
||||||
|
crashing services, by Robert Andersson and Ming Liu, Atlas Copco
|
||||||
|
* Support for `initctl ident [NAME]` which lists all instances of
|
||||||
|
`NAME`, or all enabled system run/tasks and services
|
||||||
|
* Show number of total restarts and current respawn count for a
|
||||||
|
service in `initctl status foo`
|
||||||
|
* Crashing services no longer have the crash/restart counter reset as
|
||||||
|
soon as they have stabilized. Instead, a background timer will
|
||||||
|
slowly (every 300 sec) age (decrement) the counter. This will still
|
||||||
|
catch services that "rage quit", but also those that crash after a
|
||||||
|
longer period of activity
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Fix #180: user managed (`manual:yes`) services accidentally started
|
||||||
|
by `initctl reload`, regression introduced in Finit v4.0
|
||||||
|
* Fix #181: lots of typos all over the tree, by David Yang, Debian
|
||||||
|
* Fix #187: fix typos, incl. small cleanup, in doc/bootstrap.md
|
||||||
|
* Fix #188: support running on kernels that do not have cgroups v2.
|
||||||
|
When this is detect, all functions related to cgroups support in
|
||||||
|
Finit are disabled, *except* the .conf file parser. Hence, you
|
||||||
|
may get parse error if you have invalid cgroup configuration in
|
||||||
|
your Finit .conf files
|
||||||
|
* Fix #197: `initctl status foo` now shows a focused overview of all
|
||||||
|
matching instances; foo:1, foo:2 -- if only one instance matches the
|
||||||
|
command line argument, or if onle one instance exists, the detailed
|
||||||
|
view is shown, as before
|
||||||
|
* Fix #198: a few typos found by Tim Gates
|
||||||
|
* Fix #199: avoid using C++ reserved keywords
|
||||||
|
* Fix #201: memory leak in usr condition plugin, by Ming Liu, Atlas Copco
|
||||||
|
* Fix #203: ensure all filesystems listed in /proc/mounts are properly
|
||||||
|
unumounted on shutdown/reboot, by Robert Andersson, Atlas Copco
|
||||||
|
* Fix #210: resizing terminal (smaller) after boot causes empty lines
|
||||||
|
to be inserted between boot progress
|
||||||
|
* Fix #211: drop hard-coded 32 character limit in getty, now reads
|
||||||
|
`_SC_LOGIN_NAME_MAX` from `sysconf(3)`
|
||||||
|
* Fix #212: service PID file lost after inictl reload, visible from
|
||||||
|
the output from `initctl status foo`
|
||||||
|
|
||||||
|
|
||||||
|
[4.1][] - 2021-06-06
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
Bug fix release. Also disables handlers for `SIGINT` and `SIGPWR`, a
|
||||||
|
new set of `sys` conditions are instead generated which can be used to
|
||||||
|
trigger external programs.
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
* Change behavior on SIGUSR1 to be compatible with sysvinit and systemd.
|
||||||
|
Previously SIGUSR1 caused Finit to halt, like BusyBox init. This had
|
||||||
|
"interesting" side effects on Debian systems when coexisting with
|
||||||
|
sysvinit (upgrading/reinstalling causes scripts to `kill -USR1 1`)
|
||||||
|
* Change how `contrib/debian/install.sh` sets up a Grub boot entry for
|
||||||
|
finit. We now modify the $SUPPORTED_INITS variable in `10_linux`
|
||||||
|
* Disable default kernel ctrl-alt-delete handler and let Finit instead
|
||||||
|
catch `SIGINT` from kernel to be able to perform a proper reboot.
|
||||||
|
There is no default command for this, you need to set up a task that
|
||||||
|
triggers on `<sys/key/ctrlaltdel>` to issue `initctl reboot`
|
||||||
|
* Added keventd to provide `<sys/pwr/ac>` condition to Finit. keventd
|
||||||
|
is currently only responsible for monitoring `/sys/class/power_supply`
|
||||||
|
for changes to active AC mains power online status. Enable keventd
|
||||||
|
with `configure --with-keventd`
|
||||||
|
* For handling power fail events (from UPS and similar) a process may
|
||||||
|
send `SIGPWR` to PID 1. Finit no longer redirects this to `SIGUSR1`
|
||||||
|
(poweroff). There is no default command for this, you need to set up
|
||||||
|
a task that triggers on `<sys/pwr/fail>` to issue `initctl poweroff`
|
||||||
|
* Built-in Finit getty is now a standalone program
|
||||||
|
* Default termios for TTYs now enable `IUTF8` on input
|
||||||
|
* If `/bin/login` is not found, Finit now tries `sulogin` before it
|
||||||
|
falls back to an unauthenticated `/bin/sh`
|
||||||
|
* Dropped (broken) support for multiple consoles. Finit now follows
|
||||||
|
the default console selected by the kernel, `/dev/console`
|
||||||
|
* Dropped signal handlers for SIGSTOP/TSTP and SIGCONT
|
||||||
|
* Added support for `\n`, in addition to `\r`, in "Please press Enter"
|
||||||
|
prompt before starting getty
|
||||||
|
* Finit no longer parses `/proc/cmdline` for its options. Instead all
|
||||||
|
options are by default now read from `argv[]`, like a normal program,
|
||||||
|
this is also what the kernel does by default. Please note, this may
|
||||||
|
not work if your systems boots with an initramfs (ymmv), for such
|
||||||
|
cases, see `configure --enable-kernel-cmdline`
|
||||||
|
* The following plugins are now possible to disable (for containers):
|
||||||
|
`rtc.so`, `urandom.so`, you may also want to disable `hotplug.so`.
|
||||||
|
They are all enabled by default, as in Finit 4.0, but may be moved
|
||||||
|
to external tools or entries in `finit.conf` in Finit 5.0
|
||||||
|
* Added support for reading `PRETTY_NAME` from `/etc/os-release` to use
|
||||||
|
as heading in progress output, unless `--with-heading=GREET` is used.
|
||||||
|
* Added manual pages for finit(8), initctl(8), and finit.conf(5)
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Stricter interface name validation in netlink plugin, modeled after
|
||||||
|
the kernel. Suggested by Coverity Scan
|
||||||
|
* Fix problem of re-registering a service as a task. Previously, if a
|
||||||
|
fundamental change, like type, was made to an active service/run/task
|
||||||
|
it did not take. Only possible workaround was to remove from config
|
||||||
|
* initctl: drop warning when removing a non-existing usr condition
|
||||||
|
* initctl: drop confusing `errno 0` when timing out waiting for reply
|
||||||
|
* Ensure services in plugins and from Finit main belong to a cgroup
|
||||||
|
* Ensure init top-level cgroup remains a leaf group
|
||||||
|
* Fix tty parse error for detecting use of external getty
|
||||||
|
* Fix default `name:` and `:ID` for tty's, e.g. `ttyS0` now gives
|
||||||
|
`tty:S0` as expected. This was default for built-in getty already
|
||||||
|
* Fix max username (32 chars) in bundled Finit getty
|
||||||
|
* The `contrib/*/install.sh` scripts failed to run from tarball
|
||||||
|
* Finit no longer forcibly mounts; `/dev`, `/proc`, or `/sys`, instead
|
||||||
|
it checks first if they are already mounted (devtmpfs or container)
|
||||||
|
* Fix `/etc/fstab` parser to properly check for 'ro' to not remount the
|
||||||
|
root filesystem at boot. The wrong field was read, so a root mounted
|
||||||
|
by an initramfs, or by lxc for a container, had their root remounted
|
||||||
|
* Fix SIGCHLD handler, `waitpd()` may be interrupted by a signal
|
||||||
|
* Reset `starting` flag of services being stopped. When a service
|
||||||
|
is started and then stopped before it has created its pid file,
|
||||||
|
it could be left forever in the stopping state, unless we reset
|
||||||
|
the starting flag.
|
||||||
|
* Fix #170: detect loss of default route when interfaces go down. This
|
||||||
|
emulates the missing kernel netlink message to remove the condition
|
||||||
|
net/default/route to allow stopping dependent services
|
||||||
|
* Fix #171: restore automatic mount of `/dev/shm`, `/dev/pts`, `/run`
|
||||||
|
and `/tmp`, unless mounted already by `/etc/fstab`. This is what most
|
||||||
|
desktop systems expect PID 1 to do. Here we also make sure to mount
|
||||||
|
`/run/lock` as a tmpfs as well, with write perms for regular users,
|
||||||
|
this prevents regular users from filling up `/run` and causing DoS.
|
||||||
|
* Fix #173: netlink plugin runs out of socket buffer space;
|
||||||
|
|
||||||
|
finit[1]: nl_callback():recv(): No buffer space available
|
||||||
|
|
||||||
|
Fixed by adding support for resync with kernel on `ENOBUFS`. See
|
||||||
|
netlink(7) for details. As a spin-off the plugin now supports any
|
||||||
|
number of interfaces and routes on a system. On resync, the following
|
||||||
|
message is now logged, as a warning:
|
||||||
|
|
||||||
|
finit[1]: nl_callback():busy system, resynchronizing with kernel.
|
||||||
|
|
||||||
|
* Fix #174: loss of log messages using combo of prio and facility, e.g.,
|
||||||
|
`logit(LOG_CONSOLE | LOG_NOTICE, ...)`, by Jacques de Laval, Westermo
|
||||||
|
* Fix #175: ensure Finit does not acquire a controlling TTY when checking
|
||||||
|
if a device is a TTY before starting a getty. This fixes an old bug
|
||||||
|
where Ctrl-C after logout from a shell could cause PID 1 to get SIGINT,
|
||||||
|
which in turn could lead to a system reboot
|
||||||
|
|
||||||
|
|
||||||
|
[4.0][] - 2021-04-26
|
||||||
|
--------------------
|
||||||
|
|
||||||
This release became v4.0, and not v3.2, because of incompatible changes
|
This release became v4.0, and not v3.2, because of incompatible changes
|
||||||
to service conditions. There are other significant changes as well, so
|
to service conditions. There are other significant changes as well, so
|
||||||
make sure to read the whole changelog when upgrading.
|
make sure to read the whole change log when upgrading.
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
* The stand-alone `reboot` tool has been replaced with a symlink to
|
* The stand-alone `reboot` tool has been replaced with a symlink to
|
||||||
@@ -18,31 +181,53 @@ make sure to read the whole changelog when upgrading.
|
|||||||
with a fallback to sending signals as per traditional SysV init. The
|
with a fallback to sending signals as per traditional SysV init. The
|
||||||
`-f` (force) flag remains, where `reboot(2)` is called directly
|
`-f` (force) flag remains, where `reboot(2)` is called directly
|
||||||
* Introducing Finit progress 𝓜𝓸𝓭𝓮𝓻𝓷
|
* Introducing Finit progress 𝓜𝓸𝓭𝓮𝓻𝓷
|
||||||
|
* The `inictl cond set|clear COND` have changed completely. Constrained
|
||||||
|
to a flat `<usr/...>` namespace and automatically activated by a new
|
||||||
|
`usr.so` plugin that checks services for usr condition changes
|
||||||
* Removed built-in inetd super server. If you need this functionality,
|
* Removed built-in inetd super server. If you need this functionality,
|
||||||
use an external inetd, like xinetd, instead. A pull request for a
|
use an external inetd, like xinetd, instead. A pull request for a
|
||||||
stand-alone inetd, like watchdogd and getty, is most welcome!
|
stand-alone inetd, like watchdogd and getty, is most welcome!
|
||||||
* Incompatible `configure` script changes, i.e., you must give proper
|
* Incompatible `configure` script changes, i.e., no guessing `--prefix`
|
||||||
path arguments to the script, no more guessing just GNU defaults.
|
and other paths. Also, many options have been changed, renamed, or
|
||||||
There are examples in the documentation and the `contrib/` section
|
flipped defaults, or even dropped altogether. There are examples in
|
||||||
* Change service conditions from the non-obvious `<svc/path/to/foo>` to
|
the documentation and the `contrib/` section
|
||||||
`<pid/foo:id>`. This to hopefully make it clear that one service's
|
* Service conditions change from the non-obvious `<svc/path/to/foo>` to
|
||||||
'pid:!foo' pidfile is another service's `<pid/foo>` condition
|
`<pid/foo:id>`. Not only does this give simpler internal semantics,
|
||||||
* Initial support for cgroups, every service now runs in its own cgroup
|
it hopefully also makes it clear that one service's `pid:!foo` pidfile
|
||||||
https://twitter.com/b0rk/status/1214341831049252870?s=20
|
is another service's `<pid/foo>` condition, issue #143
|
||||||
|
* Initial support for cgroups v2:
|
||||||
|
- services runs in a cgroup named after their respective *.conf file
|
||||||
|
- top-level groups are; init, user, and system
|
||||||
|
- all top-level groups can be configured from finit *.conf files
|
||||||
|
- each service can tweak the cgroup settings
|
||||||
|
- Use `initctl [top|ps|cgroup]` commands to inspect runtime state
|
||||||
|
- https://twitter.com/b0rk/status/1214341831049252870?s=20
|
||||||
* Major refactor of Finit's `main()` function to be able to start the
|
* Major refactor of Finit's `main()` function to be able to start the
|
||||||
event loop earlier. This also facilitated factoring out functionality
|
event loop earlier. This also facilitated factoring out functionality
|
||||||
previously hard-coded in Finit, e.g., starting the bundled watchdogd,
|
previously hard-coded in Finit, e.g., starting the bundled watchdogd,
|
||||||
various distro packed udevd and other hotplugging tools
|
various distro packed udevd and other hotplugging tools
|
||||||
|
* A proper rescue mode has been added. It is started extremely early
|
||||||
|
and is protected with a bundled `suslogin`. Exiting rescue mode now
|
||||||
|
brings up the system as a normal boot, as one expects
|
||||||
* Support for `sysv` start/stop scripts as well as monitoring forking
|
* Support for `sysv` start/stop scripts as well as monitoring forking
|
||||||
services, stared using `sysv` or `service` stanza
|
services, stared using `sysv` or `service` stanza
|
||||||
* Support for custom `kill:DELAY`, default 3 sec.
|
* Support for custom `kill:DELAY`, default 3 sec.
|
||||||
* Support for custom `halt:SIGNAL`, default SIGTERM
|
* Support for custom `halt:SIGNAL`, default SIGTERM
|
||||||
|
* Support for `pre:script` and `post:script`, allows for setup and
|
||||||
|
teardown/cleanup before and after a service runs, issue #129
|
||||||
|
* Support for `env:file` in `/etc/default/foo` or `/etc/conf.d/foo`, see
|
||||||
|
the contrib section for examples that utilize this feature. Variables
|
||||||
|
expanded from env files, and the env files themselves, are tracked for
|
||||||
|
changes to see if a service .conf file is "dirty" and needs restart on
|
||||||
|
`initctl reload`
|
||||||
* Support for tracking custom PID files, using `pid:!/path/to/foo.pid`,
|
* Support for tracking custom PID files, using `pid:!/path/to/foo.pid`,
|
||||||
useful with new `sysv` or `service` which fork to background
|
useful with new `sysv` or `service` which fork to background
|
||||||
* Support starting run/task/services without absolute path, trust `$PATH`
|
* Support starting run/task/services without absolute path, trust `$PATH`
|
||||||
* Add support for `--disable-doc` and `--disable-contrib` to speed up
|
* Add support for `--disable-doc` and `--disable-contrib` to speed up
|
||||||
builds and work around issue with massively parallel builds
|
builds and work around issue with massively parallel builds
|
||||||
* Add support for `@console` also for external getty
|
* Support for `@console` also for external getty
|
||||||
|
* Support for `notty` option to built-in getty, for board bring-up
|
||||||
|
* Support for `rescue` option to built-in getty, for rescue shells
|
||||||
* Add `-b`, batch mode, for non-interactive use to `initctl`
|
* Add `-b`, batch mode, for non-interactive use to `initctl`
|
||||||
* Prefer udev to handle `/dev/` if mdev is also available
|
* Prefer udev to handle `/dev/` if mdev is also available
|
||||||
* Redirect dbus daemon output to syslog
|
* Redirect dbus daemon output to syslog
|
||||||
@@ -62,7 +247,7 @@ make sure to read the whole changelog when upgrading.
|
|||||||
- As long as a stepped service changes state we queue another step all
|
- As long as a stepped service changes state we queue another step all
|
||||||
event, because services may depend on each other
|
event, because services may depend on each other
|
||||||
* Require new libuEv API: `uev_init1()` to reduce event cache so that
|
* Require new libuEv API: `uev_init1()` to reduce event cache so that
|
||||||
the kernel can invalidate deleted events before enqueing to userspace
|
the kernel can invalidate deleted events before enqueuing to userspace
|
||||||
* Rename `hwclock.so` plugin to `rtc.so` since it now is stand-alone
|
* Rename `hwclock.so` plugin to `rtc.so` since it now is stand-alone
|
||||||
from the `hwclock` tool. Note: the kernel can also be set to load
|
from the `hwclock` tool. Note: the kernel can also be set to load
|
||||||
and store RTC to/from system clock at boot/halt as well, issue #110
|
and store RTC to/from system clock at boot/halt as well, issue #110
|
||||||
@@ -92,6 +277,8 @@ make sure to read the whole changelog when upgrading.
|
|||||||
* Always append `:ID` qualifier to conditions if set for a service
|
* Always append `:ID` qualifier to conditions if set for a service
|
||||||
* The IPC socket has moved from `/run/finit.sock` to `/run/finit/socket`
|
* The IPC socket has moved from `/run/finit.sock` to `/run/finit/socket`
|
||||||
officially only supported for use by the `initctl` tool
|
officially only supported for use by the `initctl` tool
|
||||||
|
* The IPC socket now uses `SOCK_SEQPACKET` instead of `SOCK_STREAM`.
|
||||||
|
Recommend using watchdogd v3.4, or later, which support this
|
||||||
* Improved support for modern `/etc/network/interfaces`, which has
|
* Improved support for modern `/etc/network/interfaces`, which has
|
||||||
include statements. No more native `ifup` of individual interfaces,
|
include statements. No more native `ifup` of individual interfaces,
|
||||||
Finit now calls `ifup -a`, or `ifdown -a`, delegating all details to
|
Finit now calls `ifup -a`, or `ifdown -a`, delegating all details to
|
||||||
@@ -109,16 +296,21 @@ make sure to read the whole changelog when upgrading.
|
|||||||
that do not have a watchdog
|
that do not have a watchdog
|
||||||
* Fix #100: Early condition handling may not work if `/var/run` does
|
* Fix #100: Early condition handling may not work if `/var/run` does
|
||||||
not yet exist (symlink to `/run`). Added compat layer for access
|
not yet exist (symlink to `/run`). Added compat layer for access
|
||||||
|
* Fix #101: Built-in inetd removed
|
||||||
|
* Fix #102: Start built-in watchdogd as a regular service
|
||||||
* Fix #103: Register multiple getty if `@console` resolves to >1 TTY,
|
* Fix #103: Register multiple getty if `@console` resolves to >1 TTY,
|
||||||
* Fix #105: Only remove /etc/nologin when moving from runlevel 0, 1, 6
|
* Fix #105: Only remove /etc/nologin when moving from runlevel 0, 1, 6
|
||||||
Fixed by Jonas Johansson, Westermo
|
Fixed by Jonas Johansson, Westermo
|
||||||
* Fix #109: Support for PID files in sub-directories to `/var/run`
|
* Fix #109: Support for PID files in sub-directories to `/var/run`
|
||||||
* Handle rename of PID files, by Robert Andersson, Atlas Copco
|
* Handle rename of PID files, by Robert Andersson, Atlas Copco
|
||||||
|
* Fix #110: automatic modprobe of RTC devices, built-in hwclock
|
||||||
* Fix #120: Redirect `stdin` to `/dev/null` for services by default
|
* Fix #120: Redirect `stdin` to `/dev/null` for services by default
|
||||||
* Fix #122: Switch to `nanosleep()` to achieve "signal safe" sleep,
|
* Fix #122: Switch to `nanosleep()` to achieve "signal safe" sleep,
|
||||||
fixed by Jacques de Laval, Westermo
|
fixed by Jacques de Laval, Westermo
|
||||||
* Fix #124: Lingering processes in process group when session leader
|
* Fix #124: Lingering processes in process group when session leader
|
||||||
exits. E.g., lingering `logit` processes when parent dies
|
exits. E.g., lingering `logit` processes when parent dies
|
||||||
|
* Fix #127: Show all runparts scripts as they start, like rc.local, fixed
|
||||||
|
by Jacques de Laval, Westermo
|
||||||
* Fix service name matching, e.g. for condition handling, may match with
|
* Fix service name matching, e.g. for condition handling, may match with
|
||||||
wrong service, by Jonas Holmberg, Westermo
|
wrong service, by Jonas Holmberg, Westermo
|
||||||
* Run all run-parts scripts using `/bin/sh -c foo` just like the standard
|
* Run all run-parts scripts using `/bin/sh -c foo` just like the standard
|
||||||
@@ -137,6 +329,8 @@ make sure to read the whole changelog when upgrading.
|
|||||||
* Provide service description for built-in watchdog daemon
|
* Provide service description for built-in watchdog daemon
|
||||||
* Fix #138: Handle `SIGPWR` like `SIGSUR2`, i.e., power off the system
|
* Fix #138: Handle `SIGPWR` like `SIGSUR2`, i.e., power off the system
|
||||||
* Drop the '%m' GNUism, for compat with older musl libc
|
* Drop the '%m' GNUism, for compat with older musl libc
|
||||||
|
* Fix #139: call `tzset()` on `initctl reload` to activate system
|
||||||
|
timezone changes (for logging)
|
||||||
|
|
||||||
|
|
||||||
[3.1][] - 2018-01-23
|
[3.1][] - 2018-01-23
|
||||||
@@ -375,7 +569,7 @@ Bug fix release.
|
|||||||
|
|
||||||
* Add support for status/show service by `name:id`
|
* Add support for status/show service by `name:id`
|
||||||
* Enforce terse mode after boot, if verbose mode is disabled
|
* Enforce terse mode after boot, if verbose mode is disabled
|
||||||
* Reenable verbose mode at reboot, if disabled at boot
|
* Re-enable verbose mode at reboot, if disabled at boot
|
||||||
* Update section mentioning BusyBox getty
|
* Update section mentioning BusyBox getty
|
||||||
* Update debugging documentation
|
* Update debugging documentation
|
||||||
* Allow debug to override terse mode
|
* Allow debug to override terse mode
|
||||||
@@ -430,7 +624,7 @@ handling and reconfiguration at runtime.
|
|||||||
* Clarify how to select different plugins with the configure script
|
* Clarify how to select different plugins with the configure script
|
||||||
* Improve urandom plugin for embedded systems w/o random seed
|
* Improve urandom plugin for embedded systems w/o random seed
|
||||||
* Add `--debug` flag to `initctl`
|
* Add `--debug` flag to `initctl`
|
||||||
* The runlevels listed for services in `initctl show` now hightlight the
|
* The runlevels listed for services in `initctl show` now highlight the
|
||||||
active runlevel.
|
active runlevel.
|
||||||
* Clarify in the README and in `initctl help` that the GW event to
|
* Clarify in the README and in `initctl help` that the GW event to
|
||||||
listen for in service declarations is `GW:UP`
|
listen for in service declarations is `GW:UP`
|
||||||
@@ -462,7 +656,7 @@ handling and reconfiguration at runtime.
|
|||||||
* Do not use `-Os` use `-O2` as default optimization level. Many cross
|
* Do not use `-Os` use `-O2` as default optimization level. Many cross
|
||||||
compiler toolchains are known to have problems with `-Os`
|
compiler toolchains are known to have problems with `-Os`
|
||||||
* Do not allow build VERSION to be overloaded by an environment variable
|
* Do not allow build VERSION to be overloaded by an environment variable
|
||||||
* Fix too small MAX arguments and too few argments in `svc_t` for
|
* Fix too small MAX arguments and too few arguments in `svc_t` for
|
||||||
reading currently running services with `initctl show`
|
reading currently running services with `initctl show`
|
||||||
* Unblock blocked signals after forking off a child
|
* Unblock blocked signals after forking off a child
|
||||||
|
|
||||||
@@ -580,7 +774,7 @@ The inetd release.
|
|||||||
turned out to not work so well after all. For instance, launching
|
turned out to not work so well after all. For instance, launching
|
||||||
TTYs in a background process completely blocked inetd services from
|
TTYs in a background process completely blocked inetd services from
|
||||||
even starting up listening sockets ... proper fork seems to work fine
|
even starting up listening sockets ... proper fork seems to work fine
|
||||||
though. This is the casue for *yanking* the [1.11] release, below.
|
though. This is the cause for *yanking* the [1.11] release, below.
|
||||||
* Trap segfaults caused by external plugins/callbacks in a sub-process.
|
* Trap segfaults caused by external plugins/callbacks in a sub-process.
|
||||||
This prevents a single programming mistake in by a 3rd party developer
|
This prevents a single programming mistake in by a 3rd party developer
|
||||||
from taking down the entire system.
|
from taking down the entire system.
|
||||||
@@ -676,7 +870,7 @@ Major bug fix release.
|
|||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
* Show `__FILE__` in `_d()` debug messages, useful for plugins with
|
* Show `__FILE__` in `_d()` debug messages, useful for plugins with
|
||||||
similarily named callbacks. Also, only in debug mode anyway
|
similarly named callbacks. Also, only in debug mode anyway
|
||||||
* Make sure to cleanup recorded PID when a service is lost. Required by
|
* Make sure to cleanup recorded PID when a service is lost. Required by
|
||||||
service plugins for their callbacks to work.
|
service plugins for their callbacks to work.
|
||||||
* Only clear screen when in verbose mode. Maybe this should be removed
|
* Only clear screen when in verbose mode. Maybe this should be removed
|
||||||
@@ -745,14 +939,14 @@ Major bug fix release.
|
|||||||
* Makefile fixes for installation, paths encoded wrong
|
* Makefile fixes for installation, paths encoded wrong
|
||||||
* Strip binaries + .so files, support for `$(CROSS)` toolchain strip
|
* Strip binaries + .so files, support for `$(CROSS)` toolchain strip
|
||||||
* Default install is now to `/sbin/finit` and `/usr/`
|
* Default install is now to `/sbin/finit` and `/usr/`
|
||||||
* Note change in `$PLUGIN_DIR` environemnt variable to `$plugindir`
|
* Note change in `$PLUGIN_DIR` environment variable to `$plugindir`
|
||||||
|
|
||||||
|
|
||||||
[1.2][] - 2012-09-27
|
[1.2][] - 2012-09-27
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
* Update README with section on building and enviroment variables
|
* Update README with section on building and environment variables
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
* Fix installation paths encoded in finit binary
|
* Fix installation paths encoded in finit binary
|
||||||
@@ -844,7 +1038,9 @@ Major bug fix release.
|
|||||||
|
|
||||||
* Initial release
|
* Initial release
|
||||||
|
|
||||||
[UNRELEASED]: https://github.com/troglobit/finit/compare/3.1...HEAD
|
[UNRELEASED]: https://github.com/troglobit/finit/compare/4.2...HEAD
|
||||||
|
[4.2]: https://github.com/troglobit/finit/compare/4.1...4.2
|
||||||
|
[4.1]: https://github.com/troglobit/finit/compare/4.0...4.1
|
||||||
[4.0]: https://github.com/troglobit/finit/compare/3.1...4.0
|
[4.0]: https://github.com/troglobit/finit/compare/3.1...4.0
|
||||||
[3.1]: https://github.com/troglobit/finit/compare/3.0...3.1
|
[3.1]: https://github.com/troglobit/finit/compare/3.0...3.1
|
||||||
[3.0]: https://github.com/troglobit/finit/compare/2.4...3.0
|
[3.0]: https://github.com/troglobit/finit/compare/2.4...3.0
|
||||||
@@ -876,9 +1072,3 @@ Major bug fix release.
|
|||||||
[0.2]: https://github.com/troglobit/finit/compare/0.1...0.2
|
[0.2]: https://github.com/troglobit/finit/compare/0.1...0.2
|
||||||
[libuEv]: https://github.com/troglobit/libuev
|
[libuEv]: https://github.com/troglobit/libuev
|
||||||
[dea3ae8]: https://github.com/troglobit/finit/commit/dea3ae8
|
[dea3ae8]: https://github.com/troglobit/finit/commit/dea3ae8
|
||||||
|
|
||||||
<!--
|
|
||||||
-- Local Variables:
|
|
||||||
-- mode: markdown
|
|
||||||
-- End:
|
|
||||||
-->
|
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
ACLOCAL_AMFLAGS = -I m4
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
SUBDIRS = plugins src test
|
SUBDIRS = man plugins src test
|
||||||
doc_DATA = README.md LICENSE contrib/finit.conf
|
doc_DATA = README.md LICENSE contrib/finit.conf
|
||||||
EXTRA_DIST = README.md LICENSE ChangeLog.md contrib/finit.conf
|
EXTRA_DIST = README.md LICENSE ChangeLog.md contrib/finit.conf
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
[![License Badge][]][License] [![Travis Status]][Travis] [![Coverity Status]][Coverity Scan]
|
[![License Badge][]][License] [![GitHub Status]][GitHub] [![Coverity Status]][Coverity Scan]
|
||||||
<img align="right" src="img/finit3.png" alt="Finit: Fast Init">
|
<img align="right" src="img/finit3.png" alt="Finit: Fast Init">
|
||||||
|
|
||||||
* [Introduction](#introduction)
|
* [Introduction](#introduction)
|
||||||
@@ -22,13 +22,30 @@
|
|||||||
Introduction
|
Introduction
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Finit is a simple alternative to [SysV init][4] and [systemd][6]. It
|
Fast init for Linux systems. Reverse engineered from the [EeePC
|
||||||
was reverse engineered from the [EeePC fastinit][] over ten years ago
|
fastinit][] over ten years ago by [Claudio Matsuoka][] — "gaps filled
|
||||||
by [Claudio Matsuoka][] — "gaps filled with frog DNA …"
|
with frog DNA …"
|
||||||
|
|
||||||

|

|
||||||
*Figure 1: Screenshot showing Finit booting [Alpine Linux](https://www.alpinelinux.org/).*
|
*Figure 1: Screenshot showing Finit booting [Alpine Linux](https://www.alpinelinux.org/).*
|
||||||
|
|
||||||
|
Features include:
|
||||||
|
|
||||||
|
* Runlevels, defined per service
|
||||||
|
* One-shot tasks, services (daemons), or [SysV init][4] start/stop scripts
|
||||||
|
* Runparts and `/etc/rc.local` support
|
||||||
|
* Process supervision similar to [systemd][]
|
||||||
|
* Sourcing environment files
|
||||||
|
* Conditions for network/process/custom dependencies
|
||||||
|
* Pre/Post script actions
|
||||||
|
* Tooling to enable/disable services
|
||||||
|
* Built-in getty
|
||||||
|
* Built-in watchdog, with support for hand-over to [watchdogd](https://troglobit.com/watchdogd.html)
|
||||||
|
* Built-in support for Debian/BusyBox `/etc/network/interfaces`
|
||||||
|
* Cgroups v2, both configuration and monitoring in `initctl top`
|
||||||
|
* Plugin support for customization
|
||||||
|
* Proper rescue mode with bundled `sulogin` for protected maintenance shell
|
||||||
|
|
||||||
Focus is on small and embedded systems, although Finit is fully usable
|
Focus is on small and embedded systems, although Finit is fully usable
|
||||||
on server and desktop systems as well. For working examples, see the
|
on server and desktop systems as well. For working examples, see the
|
||||||
[contrib/](contrib/) section with tutorials for:
|
[contrib/](contrib/) section with tutorials for:
|
||||||
@@ -58,10 +75,10 @@ runlevel 2
|
|||||||
log size=100k count=4
|
log size=100k count=4
|
||||||
|
|
||||||
# Services to be monitored and respawned as needed
|
# Services to be monitored and respawned as needed
|
||||||
service [S12345] watchdogd -L -f -- System watchdog daemon
|
service [S12345] env:-/etc/conf.d/watchdog watchdog $WATCHDOG_OPTS $WATCHDOG_DEV -- System watchdog daemon
|
||||||
service [S12345] syslogd -n -b 3 -D -- System log daemon
|
service [S12345] env:-/etc/conf.d/syslog syslogd -n $SYSLOGD_OPTS -- System log daemon
|
||||||
service [S12345] <pid/syslogd> klogd -n -- Kernel log daemon
|
service [S12345] <pid/syslogd> env:-/etc/conf.d/klogd klogd -n $KLOGD_OPTS -- Kernel log daemon
|
||||||
service [2345] lldpd -d -c -M1 -H0 -i -- LLDP daemon (IEEE 802.1ab)
|
service [2345] env:-/etc/conf.d/lldpd lldpd -d $LLDPD_OPTS -- LLDP daemon (IEEE 802.1ab)
|
||||||
|
|
||||||
# The BusyBox ntpd does not use syslog when running in the foreground
|
# 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
|
# So we use this trick to redirect stdout/stderr to a log file. The
|
||||||
@@ -76,24 +93,24 @@ service :80 [2345] merecat -n -p 80 /var/www -- Web server
|
|||||||
service :8080 [2345] merecat -n -p 8080 /var/www -- Old web server
|
service :8080 [2345] merecat -n -p 8080 /var/www -- Old web server
|
||||||
|
|
||||||
# Alternative method instead of below runparts, can also use /etc/rc.local
|
# Alternative method instead of below runparts, can also use /etc/rc.local
|
||||||
#task [S] /etc/init.d/keyboard-setup start -- Setting up preliminary keymap
|
#sysv [S] /etc/init.d/keyboard-setup -- Setting up preliminary keymap
|
||||||
#task [S] /etc/init.d/acpid start -- Starting ACPI Daemon
|
#sysv [S] /etc/init.d/acpid -- Starting ACPI Daemon
|
||||||
#task [S] /etc/init.d/kbd start -- Preparing console
|
#task [S] /etc/init.d/kbd -- Preparing console
|
||||||
|
|
||||||
# Run start scripts from this directory
|
# Run start scripts from this directory
|
||||||
# runparts /etc/start.d
|
# runparts /etc/start.d
|
||||||
|
|
||||||
# Virtual consoles run BusyBox getty, keep kernel default speed
|
# Virtual consoles run BusyBox getty, keep kernel default speed
|
||||||
tty [12345] /sbin/getty -L 0 /dev/tty1 linux
|
tty [12345] /sbin/getty -L 0 /dev/tty1 linux nowait noclear
|
||||||
tty [12345] /sbin/getty -L 0 /dev/tty2 linux
|
tty [2345] /sbin/getty -L 0 /dev/tty2 linux nowait noclear
|
||||||
tty [12345] /sbin/getty -L 0 /dev/tty3 linux
|
tty [2345] /sbin/getty -L 0 /dev/tty3 linux nowait noclear
|
||||||
|
|
||||||
# Use built-in getty for serial port and USB serial
|
# Use built-in getty for serial port and USB serial
|
||||||
tty [12345] /dev/ttyAMA0 noclear nowait
|
#tty [12345] /dev/ttyAMA0 noclear nowait
|
||||||
tty [12345] /dev/ttyUSB0 noclear
|
#tty [12345] /dev/ttyUSB0 noclear
|
||||||
|
|
||||||
# Just give me a shell, I need to debug this embedded system!
|
# Just give me a shell, I need to debug this embedded system!
|
||||||
tty [12345] @console noclear nologin
|
#tty [12345] console noclear nologin
|
||||||
```
|
```
|
||||||
|
|
||||||
The `service` stanza, as well as `task`, `run` and others are described
|
The `service` stanza, as well as `task`, `run` and others are described
|
||||||
@@ -102,10 +119,10 @@ some of the most common components needed to start a UNIX daemon:
|
|||||||
|
|
||||||
```
|
```
|
||||||
service [LVLS] <COND> log env:[-]/etc/default/daemon daemon ARGS -- Daemon daemon
|
service [LVLS] <COND> log env:[-]/etc/default/daemon daemon ARGS -- Daemon daemon
|
||||||
^ ^ ^ ^ ^ ^ ^ ^
|
^ ^ ^ ^ ^ ^ ^ ^
|
||||||
| | | | | | | `-- Optional description
|
| | | | | | | `---------- Optional description
|
||||||
| | | | | | `----------- Daemon arguments
|
| | | | | | `------------------ Daemon arguments
|
||||||
| | | | | `-------------------------- Path to daemon
|
| | | | | `------------------------- Path to daemon
|
||||||
| | | | `---------------------------------------------------- Optional env. file
|
| | | | `---------------------------------------------------- Optional env. file
|
||||||
| | | `-------------------------------------------------------- Redirect output to log
|
| | | `-------------------------------------------------------- Redirect output to log
|
||||||
| | `--------------------------------------------------------------- Optional conditions
|
| | `--------------------------------------------------------------- Optional conditions
|
||||||
@@ -117,13 +134,13 @@ Some components are optional: runlevel(s), condition(s) and description,
|
|||||||
making it easy to create simple start scripts and still possible for more
|
making it easy to create simple start scripts and still possible for more
|
||||||
advanced uses as well:
|
advanced uses as well:
|
||||||
|
|
||||||
service sshd -D
|
service /usr/sbin/sshd -D
|
||||||
|
|
||||||
Dependencies are handled using [conditions](doc/conditions.md). One of
|
Dependencies are handled using [conditions](doc/conditions.md). One of
|
||||||
the most common conditions is to wait for basic networking to become
|
the most common conditions is to wait for basic networking to become
|
||||||
available:
|
available:
|
||||||
|
|
||||||
service <net/route/default> nginx -- High performace HTTP server
|
service <net/route/default> nginx -- High performance HTTP server
|
||||||
|
|
||||||
Here is another example where we instruct Finit to not start BusyBox
|
Here is another example where we instruct Finit to not start BusyBox
|
||||||
`ntpd` until `syslogd` has started properly. Finit waits for `syslogd`
|
`ntpd` until `syslogd` has started properly. Finit waits for `syslogd`
|
||||||
@@ -232,8 +249,11 @@ For more information, see [doc/plugins.md](doc/plugins.md).
|
|||||||
By default, Finit monitors `/etc/finit.d/` and `/etc/finit.d/enabled/`
|
By default, Finit monitors `/etc/finit.d/` and `/etc/finit.d/enabled/`
|
||||||
registering any changes to `.conf` files. To activate a change the user
|
registering any changes to `.conf` files. To activate a change the user
|
||||||
must call `initctl reload`, which reloads all modified files, stops any
|
must call `initctl reload`, which reloads all modified files, stops any
|
||||||
removed services, starts new ones, and restarts any modified ones, with
|
removed services, starts new ones, and restarts any modified ones. If the
|
||||||
SIGHUP if the process supports it.
|
command line arguments of a service have changed, the process will be
|
||||||
|
terminated and then started again with the updated arguments. If the arguments
|
||||||
|
have not been modified and the process supports SIGHUP, the process will
|
||||||
|
receive a SIGHUP rather than being terminated and started.
|
||||||
|
|
||||||
For some use-cases the extra step of calling `initctl reload` creates an
|
For some use-cases the extra step of calling `initctl reload` creates an
|
||||||
unnecessary overhead, which can be removed at build-time using:
|
unnecessary overhead, which can be removed at build-time using:
|
||||||
@@ -241,6 +261,46 @@ unnecessary overhead, which can be removed at build-time using:
|
|||||||
configure --enable-auto-reload
|
configure --enable-auto-reload
|
||||||
|
|
||||||
|
|
||||||
|
**Cgroups**
|
||||||
|
|
||||||
|
Finit supports cgroups v2 and comes with the following default groups
|
||||||
|
in which services and user sessions are placed in:
|
||||||
|
|
||||||
|
/sys/fs/cgroup
|
||||||
|
|-- init/ # cpu.weight:100
|
||||||
|
|-- system/ # cpu.weight:9800
|
||||||
|
`-- user/ # cpu.weight:100
|
||||||
|
|
||||||
|
Finit itself and its helper scripts and services are placed in the
|
||||||
|
top-level leaf-node group `init/`, which also is _reserved_.
|
||||||
|
|
||||||
|
All run/task/service/sysv processes are placed in their own sub-group
|
||||||
|
in `system/`. The name of each sub-group is taken from the respective
|
||||||
|
`.conf` file from `/etc/finit.d`.
|
||||||
|
|
||||||
|
All getty/tty processes are placed in their own sub-group in `user/`.
|
||||||
|
The name of each sub-group is taken from the username.
|
||||||
|
|
||||||
|
A fourth group also exists, the `root` group. It is also _reserved_ and
|
||||||
|
primarily intended for RT tasks. If you have RT tasks they need to be
|
||||||
|
declared as such in their service stanza like this:
|
||||||
|
|
||||||
|
service [...] <...> cgroup.root /path/to/foo args -- description
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
cgroup.root
|
||||||
|
service [...] <...> /path/to/foo args -- description
|
||||||
|
service [...] <...> /path/to/bar args -- description
|
||||||
|
|
||||||
|
See [doc/config.md](doc/config.md#cgroups) for more information, e.g.,
|
||||||
|
how to configure per-group limits.
|
||||||
|
|
||||||
|
The `initctl` tool has three commands to help debug and optimize the
|
||||||
|
setup and monitoring of cgroups. See the `ps`, `top`, and `cgroup`
|
||||||
|
commands for details.
|
||||||
|
|
||||||
|
|
||||||
Runparts & /etc/rc.local
|
Runparts & /etc/rc.local
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
@@ -356,6 +416,9 @@ Options:
|
|||||||
-b, --batch Batch mode, no screen size probing
|
-b, --batch Batch mode, no screen size probing
|
||||||
-c, --create Create missing paths (and files) as needed
|
-c, --create Create missing paths (and files) as needed
|
||||||
-f, --force Ignore missing files and arguments, never prompt
|
-f, --force Ignore missing files and arguments, never prompt
|
||||||
|
-1, --once Only one lap in commands like 'top'
|
||||||
|
-p, --plain Use plain table headings, no ctrl chars
|
||||||
|
-q, --quiet Silent, only return status of command
|
||||||
-t, --no-heading Skip table headings
|
-t, --no-heading Skip table headings
|
||||||
-v, --verbose Verbose output
|
-v, --verbose Verbose output
|
||||||
-h, --help This help text
|
-h, --help This help text
|
||||||
@@ -375,17 +438,22 @@ Commands:
|
|||||||
disable <CONF> Disable .conf in /etc/finit.d/enabled
|
disable <CONF> Disable .conf in /etc/finit.d/enabled
|
||||||
reload Reload *.conf in /etc/finit.d (activate changes)
|
reload Reload *.conf in /etc/finit.d (activate changes)
|
||||||
|
|
||||||
cond show Show condition status
|
cond set <COND> Set (assert) user-defined condition +usr/COND
|
||||||
|
cond clear <COND> Clear (deassert) user-defined condition -usr/COND
|
||||||
|
cond status Show condition status, default cond command
|
||||||
cond dump Dump all conditions and their status
|
cond dump Dump all conditions and their status
|
||||||
|
|
||||||
log [NAME] Show ten last Finit, or NAME, messages from syslog
|
log [NAME] Show ten last Finit, or NAME, messages from syslog
|
||||||
start <NAME>[:ID] Start service by name, with optional ID
|
start <NAME>[:ID] Start service by name, with optional ID
|
||||||
stop <NAME>[:ID] Stop/Pause a running service by name
|
stop <NAME>[:ID] Stop/Pause a running service by name
|
||||||
|
reload <NAME>[:ID] Reload service by name (SIGHUP or restart)
|
||||||
restart <NAME>[:ID] Restart (stop/start) service by name
|
restart <NAME>[:ID] Restart (stop/start) service by name
|
||||||
status <NAME>[:ID] Show service status, by name
|
status <NAME>[:ID] Show service status, by name
|
||||||
status Show status of services, default command
|
status Show status of services, default command
|
||||||
|
|
||||||
|
cgroup List cgroup config overview
|
||||||
ps List processes based on cgroups
|
ps List processes based on cgroups
|
||||||
|
top Show top-like listing based on cgroups
|
||||||
|
|
||||||
runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot
|
runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot
|
||||||
reboot Reboot system
|
reboot Reboot system
|
||||||
@@ -399,13 +467,17 @@ file must be used to tell Finit to stop and start it on `reload` and
|
|||||||
`runlevel` changes. If `<>` holds more [conditions](doc/conditions.md),
|
`runlevel` changes. If `<>` holds more [conditions](doc/conditions.md),
|
||||||
these will also affect how a service is maintained.
|
these will also affect how a service is maintained.
|
||||||
|
|
||||||
**Note:** even though it is possible to start services not belonging in
|
> **Note:** even though it is possible to start services not belonging in
|
||||||
the current runlevel these services will not be respawned automatically
|
> the current runlevel these services will not be respawned automatically
|
||||||
by Finit if they exit (crash). Hence, if the runlevel is 2, the below
|
> by Finit if they exit (crash). Hence, if the runlevel is 2, the below
|
||||||
Dropbear SSH service will not be restarted if it is killed or exits.
|
> Dropbear SSH service will not be restarted if it is killed or exits.
|
||||||
|
|
||||||
|
The `status` command is the default, it displays a quick overview of all
|
||||||
|
monitored run/task/services. Here we call `initctl -p`, suitable for
|
||||||
|
scripting and documentation:
|
||||||
|
|
||||||
```
|
```
|
||||||
alpine:~# initctl
|
alpine:~# initctl -p
|
||||||
PID IDENT STATUS RUNLEVELS DESCRIPTION
|
PID IDENT STATUS RUNLEVELS DESCRIPTION
|
||||||
======================================================================
|
======================================================================
|
||||||
1506 acpid running [--2345----] ACPI daemon
|
1506 acpid running [--2345----] ACPI daemon
|
||||||
@@ -415,7 +487,7 @@ PID IDENT STATUS RUNLEVELS DESCRIPTION
|
|||||||
1512 ntpd running [--2345----] NTP daemon
|
1512 ntpd running [--2345----] NTP daemon
|
||||||
1473 syslogd running [S12345----] Syslog daemon
|
1473 syslogd running [S12345----] Syslog daemon
|
||||||
|
|
||||||
alpine:~# initctl -v
|
alpine:~# initctl -pv
|
||||||
PID IDENT STATUS RUNLEVELS COMMAND
|
PID IDENT STATUS RUNLEVELS COMMAND
|
||||||
======================================================================
|
======================================================================
|
||||||
1506 acpid running [--2345----] acpid -f
|
1506 acpid running [--2345----] acpid -f
|
||||||
@@ -430,6 +502,40 @@ The environment variables to each of the services above are read from,
|
|||||||
in the case of Alpine Linux, `/etc/conf.d/`. Other distributions may
|
in the case of Alpine Linux, `/etc/conf.d/`. Other distributions may
|
||||||
have other directories, e.g., Debian use `/etc/default/`.
|
have other directories, e.g., Debian use `/etc/default/`.
|
||||||
|
|
||||||
|
The `status` command takes an optional `NAME:ID` argument. Here we
|
||||||
|
check the status of `dropbear`, which only has one instance in this
|
||||||
|
system:
|
||||||
|
|
||||||
|
```
|
||||||
|
alpine:~# initctl -p status dropbear
|
||||||
|
Status : running
|
||||||
|
Identity : dropbear
|
||||||
|
Description : Dropbear SSH daemon
|
||||||
|
Origin : /etc/finit.d/enabled/dropbear.conf
|
||||||
|
Environment : -/etc/conf.d/dropbear
|
||||||
|
Condition(s):
|
||||||
|
Command : dropbear -R -F $DROPBEAR_OPTS
|
||||||
|
PID file : !/run/dropbear.pid
|
||||||
|
PID : 1485
|
||||||
|
User : root
|
||||||
|
Group : root
|
||||||
|
Uptime : 2 hour 46 min 56 sec
|
||||||
|
Runlevels : [--2345----]
|
||||||
|
Memory : 1.2M
|
||||||
|
CGroup : /system/dropbear cpu 0 [100, max] mem [--.--, max]
|
||||||
|
|- 1485 dropbear -R -F
|
||||||
|
|- 2634 dropbear -R -F
|
||||||
|
|- 2635 ash
|
||||||
|
`- 2652 initctl -p status dropbear
|
||||||
|
|
||||||
|
Apr 8 12:19:49 alpine authpriv.info dropbear[1485]: Not backgrounding
|
||||||
|
Apr 8 12:37:45 alpine authpriv.info dropbear[2300]: Child connection from 192.168.121.1:47834
|
||||||
|
Apr 8 12:37:46 alpine authpriv.notice dropbear[2300]: Password auth succeeded for 'root' from 192.168.121.1:47834
|
||||||
|
Apr 8 12:37:46 alpine authpriv.info dropbear[2300]: Exit (root) from <192.168.121.1:47834>: Disconnect received
|
||||||
|
Apr 8 15:02:11 alpine authpriv.info dropbear[2634]: Child connection from 192.168.121.1:48576
|
||||||
|
Apr 8 15:02:12 alpine authpriv.notice dropbear[2634]: Password auth succeeded for 'root' from 192.168.121.1:48576
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Requirements
|
Requirements
|
||||||
------------
|
------------
|
||||||
@@ -465,36 +571,34 @@ This project is based on the [original finit][] by [Claudio Matsuoka][]
|
|||||||
which was reverse engineered from syscalls of the [EeePC fastinit][] —
|
which was reverse engineered from syscalls of the [EeePC fastinit][] —
|
||||||
"gaps filled with frog DNA …"
|
"gaps filled with frog DNA …"
|
||||||
|
|
||||||
Finit is developed and maintained by [Joachim Wiberg][] at [GitHub][].
|
Finit is developed and maintained by [Joachim Wiberg][] at [GitHub][6].
|
||||||
Please file bug reports, clone it, or send pull requests for bug fixes
|
Please file bug reports, clone it, or send pull requests for bug fixes
|
||||||
and proposed extensions.
|
and proposed extensions.
|
||||||
|
|
||||||
|
|
||||||
[1]: https://en.wikipedia.org/wiki/Process_supervision
|
[1]: https://en.wikipedia.org/wiki/Process_supervision
|
||||||
[2]: http://cr.yp.to/daemontools.html
|
[2]: https://cr.yp.to/daemontools.html
|
||||||
[3]: http://smarden.org/runit/
|
[3]: https://smarden.org/runit/
|
||||||
[4]: http://en.wikipedia.org/wiki/Init
|
[4]: https://en.wikipedia.org/wiki/Init
|
||||||
[5]: http://en.wikipedia.org/wiki/Runlevel
|
[5]: https://en.wikipedia.org/wiki/Runlevel
|
||||||
[6]: https://www.freedesktop.org/wiki/Software/systemd/
|
[6]: https://github.com/troglobit/finit
|
||||||
[9]: https://github.com/troglobit/troglos
|
|
||||||
[RFC862]: https://tools.ietf.org/html/rfc862
|
[RFC862]: https://tools.ietf.org/html/rfc862
|
||||||
[RFC863]: https://tools.ietf.org/html/rfc863
|
[RFC863]: https://tools.ietf.org/html/rfc863
|
||||||
[RFC864]: https://tools.ietf.org/html/rfc864
|
[RFC864]: https://tools.ietf.org/html/rfc864
|
||||||
[RFC867]: https://tools.ietf.org/html/rfc867
|
[RFC867]: https://tools.ietf.org/html/rfc867
|
||||||
[RFC868]: https://tools.ietf.org/html/rfc868
|
[RFC868]: https://tools.ietf.org/html/rfc868
|
||||||
[init]: http://en.wikipedia.org/wiki/Init
|
[init]: https://en.wikipedia.org/wiki/Init
|
||||||
[upstart]: http://upstart.ubuntu.com/
|
[upstart]: https://upstart.ubuntu.com/
|
||||||
[systemd]: http://www.freedesktop.org/wiki/Software/systemd/
|
[systemd]: https://www.freedesktop.org/wiki/Software/systemd/
|
||||||
[openrc]: http://www.gentoo.org/proj/en/base/openrc/
|
[openrc]: https://www.gentoo.org/proj/en/base/openrc/
|
||||||
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
[run-parts(8)]: https://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
||||||
[original finit]: http://helllabs.org/finit/
|
[original finit]: http://helllabs.org/finit/
|
||||||
[EeePC fastinit]: https://web.archive.org/web/20071208212450/http://wiki.eeeuser.com/boot_process:the_boot_process
|
[EeePC fastinit]: https://web.archive.org/web/20071208212450/http://wiki.eeeuser.com/boot_process:the_boot_process
|
||||||
[Claudio Matsuoka]: https://github.com/cmatsuoka
|
[Claudio Matsuoka]: https://github.com/cmatsuoka
|
||||||
[Joachim Wiberg]: http://troglobit.com
|
[Joachim Wiberg]: https://troglobit.com
|
||||||
[GitHub]: https://github.com/troglobit/finit
|
|
||||||
[License]: https://en.wikipedia.org/wiki/MIT_License
|
[License]: https://en.wikipedia.org/wiki/MIT_License
|
||||||
[License Badge]: https://img.shields.io/badge/License-MIT-teal.svg
|
[License Badge]: https://img.shields.io/badge/License-MIT-teal.svg
|
||||||
[Travis]: https://travis-ci.org/troglobit/finit
|
[GitHub]: https://travis-ci.org/troglobit/finit
|
||||||
[Travis Status]: https://travis-ci.org/troglobit/finit.svg?branch=master
|
[GitHub Status]: https://travis-ci.org/troglobit/finit.svg?branch=master
|
||||||
[Coverity Scan]: https://scan.coverity.com/projects/3545
|
[Coverity Scan]: https://scan.coverity.com/projects/3545
|
||||||
[Coverity Status]: https://scan.coverity.com/projects/3545/badge.svg
|
[Coverity Status]: https://scan.coverity.com/projects/3545/badge.svg
|
||||||
|
|||||||
+66
-42
@@ -1,4 +1,4 @@
|
|||||||
AC_INIT(Finit, 4.0-rc2, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/finit.html)
|
AC_INIT(Finit, 4.2, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/finit.html)
|
||||||
AC_CONFIG_AUX_DIR(aux)
|
AC_CONFIG_AUX_DIR(aux)
|
||||||
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
|
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
|
||||||
AM_SILENT_RULES([yes])
|
AM_SILENT_RULES([yes])
|
||||||
@@ -8,9 +8,10 @@ AC_CONFIG_HEADER([config.h])
|
|||||||
AC_CONFIG_FILES([Makefile
|
AC_CONFIG_FILES([Makefile
|
||||||
contrib/Makefile
|
contrib/Makefile
|
||||||
contrib/alpine/Makefile contrib/alpine/finit.d/Makefile contrib/alpine/finit.d/available/Makefile
|
contrib/alpine/Makefile contrib/alpine/finit.d/Makefile contrib/alpine/finit.d/available/Makefile
|
||||||
contrib/debian/Makefile contrib/debian/finit.d/Makefile contrib/debian/finit.d/available/Makefile contrib/debian/grub.d/Makefile
|
contrib/debian/Makefile contrib/debian/finit.d/Makefile contrib/debian/finit.d/available/Makefile
|
||||||
contrib/void/Makefile contrib/void/finit.d/Makefile contrib/void/finit.d/available/Makefile
|
contrib/void/Makefile contrib/void/finit.d/Makefile contrib/void/finit.d/available/Makefile
|
||||||
doc/Makefile
|
doc/Makefile
|
||||||
|
man/Makefile
|
||||||
plugins/Makefile
|
plugins/Makefile
|
||||||
src/Makefile
|
src/Makefile
|
||||||
test/test.env
|
test/test.env
|
||||||
@@ -48,30 +49,25 @@ PKG_CHECK_MODULES([uev], [libuev >= 2.2.0])
|
|||||||
PKG_CHECK_MODULES([lite], [libite >= 2.2.0])
|
PKG_CHECK_MODULES([lite], [libite >= 2.2.0])
|
||||||
|
|
||||||
# Check for configured Finit features
|
# Check for configured Finit features
|
||||||
AC_ARG_ENABLE(emergency_shell,
|
|
||||||
AS_HELP_STRING([--enable-emergency-shell], [Experimental emergency fallback at boot.
|
|
||||||
Use only for debugging very early boot problems with Finit]),,[
|
|
||||||
enable_emergency_shell=no])
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(fallback_shell,
|
|
||||||
AS_HELP_STRING([--enable-fallback-shell], [Start a shell if no TTYs can start]),,[
|
|
||||||
enable_fallback_shell=no])
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(auto_reload,
|
AC_ARG_ENABLE(auto_reload,
|
||||||
AS_HELP_STRING([--enable-auto-reload], [Automatic reload on any .conf change]),,[
|
AS_HELP_STRING([--enable-auto-reload], [Automatic reload on any .conf change]),,[
|
||||||
enable_auto_reload=no])
|
enable_auto_reload=no])
|
||||||
|
|
||||||
AC_ARG_ENABLE(watchdog,
|
AC_ARG_ENABLE(kernel_cmdline,
|
||||||
AS_HELP_STRING([--enable-watchdog], [Enable built-in watchdog, uses /dev/watchdog]),,[
|
AS_HELP_STRING([--enable-kernel-cmdline], [Parse init args from /proc/cmdline (don't use!)]),,[
|
||||||
enable_watchdog=no])
|
enable_kernel_cmdline=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(fastboot,
|
||||||
|
AS_HELP_STRING([--enable-fastboot], [Skip fsck check on filesystems listed in /etc/fstab]),,[
|
||||||
|
enable_fastboot=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(fsckfix,
|
||||||
|
AS_HELP_STRING([--enable-fsckfix], [Run fsck fix mode (options: -yf) on filesystems listed in /etc/fstab]),,[
|
||||||
|
enable_fsckfix=no])
|
||||||
|
|
||||||
AC_ARG_ENABLE(redirect,
|
AC_ARG_ENABLE(redirect,
|
||||||
AS_HELP_STRING([--enable-redirect], [Redirect service output to /dev/null, default: no]),,[
|
AS_HELP_STRING([--disable-redirect], [Disable redirection of service output to /dev/null]),,[
|
||||||
enable_redirect_output=no])
|
enable_redirect=yes])
|
||||||
|
|
||||||
AC_ARG_ENABLE(logit,
|
|
||||||
AS_HELP_STRING([--disable-logit], [Disable logit, used for log redirection, default: enable]),,[
|
|
||||||
enable_logit=yes])
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(logrotate,
|
AC_ARG_ENABLE(logrotate,
|
||||||
AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp, default enabled]),,[
|
AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp, default enabled]),,[
|
||||||
@@ -94,10 +90,12 @@ AC_PLUGIN([resolvconf], [no], [Setup necessary files for resolvconf])
|
|||||||
AC_PLUGIN([x11-common], [no], [Console setup (for X)])
|
AC_PLUGIN([x11-common], [no], [Console setup (for X)])
|
||||||
AC_PLUGIN([netlink], [yes], [Basic netlink plugin for IFUP/IFDN and GW events. Can be replaced with externally built plugin that links with libnl or similar.])
|
AC_PLUGIN([netlink], [yes], [Basic netlink plugin for IFUP/IFDN and GW events. Can be replaced with externally built plugin that links with libnl or similar.])
|
||||||
AC_PLUGIN([hotplug], [yes], [Setup and start udev or mdev hotplug daemon])
|
AC_PLUGIN([hotplug], [yes], [Setup and start udev or mdev hotplug daemon])
|
||||||
|
AC_PLUGIN([rtc], [yes], [Save and restore RTC using hwclock])
|
||||||
|
AC_PLUGIN([urandom], [yes], [Setup and save random seed at boot/shutdown])
|
||||||
|
|
||||||
# Check for extra arguments or packages
|
# Check for extra arguments or packages
|
||||||
AC_ARG_WITH(heading,
|
AC_ARG_WITH(heading,
|
||||||
AS_HELP_STRING([--with-heading=GREET], [Display GREET instead of Finit version at boot]),
|
AS_HELP_STRING([--with-heading=GREET], [Heading for boot progress. Default: PRETTY_NAME from /etc/os-release, fallback to "Finit vX.YY"]),
|
||||||
[heading=$withval], [heading=yes])
|
[heading=$withval], [heading=yes])
|
||||||
|
|
||||||
AC_ARG_WITH(config,
|
AC_ARG_WITH(config,
|
||||||
@@ -116,6 +114,10 @@ AC_ARG_WITH(sysconfig,
|
|||||||
AS_HELP_STRING([--with-sysconfig=DIR], [System environment directory, sourced by .conf files, default /etc/default & /etc/conf.d]),
|
AS_HELP_STRING([--with-sysconfig=DIR], [System environment directory, sourced by .conf files, default /etc/default & /etc/conf.d]),
|
||||||
[sysconfig=$withval], [sysconfig=default])
|
[sysconfig=$withval], [sysconfig=default])
|
||||||
|
|
||||||
|
AC_ARG_WITH(group,
|
||||||
|
AS_HELP_STRING([--with-group=NAME], [Group for /run/finit/socket (initctl), default: root]),
|
||||||
|
[group=$withval], [group=root])
|
||||||
|
|
||||||
AC_ARG_WITH(hostname,
|
AC_ARG_WITH(hostname,
|
||||||
AS_HELP_STRING([--with-hostname=NAME], [If /etc/hostname is missing, default: noname]),
|
AS_HELP_STRING([--with-hostname=NAME], [If /etc/hostname is missing, default: noname]),
|
||||||
[hostname=$withval], [hostname=yes])
|
[hostname=$withval], [hostname=yes])
|
||||||
@@ -128,28 +130,32 @@ AC_ARG_WITH(random-seed,
|
|||||||
AS_HELP_STRING([--with-random-seed=FILE], [Save a random seed for /dev/urandom across reboots, default /var/lib/misc/random-seed]),
|
AS_HELP_STRING([--with-random-seed=FILE], [Save a random seed for /dev/urandom across reboots, default /var/lib/misc/random-seed]),
|
||||||
[random_seed=$withval], [random_seed=yes])
|
[random_seed=$withval], [random_seed=yes])
|
||||||
|
|
||||||
|
AC_ARG_WITH(keventd,
|
||||||
|
AS_HELP_STRING([--with-keventd], [Enable built-in keventd, default: no]),, [with_keventd=no])
|
||||||
|
|
||||||
|
AC_ARG_WITH(watchdog,
|
||||||
|
AS_HELP_STRING([--with-watchdog=[DEV]], [Enable built-in watchdog, default: /dev/watchdog]),
|
||||||
|
[watchdog=$withval], [with_watchdog=no watchdog=])
|
||||||
|
|
||||||
### Enable features ###########################################################################
|
### Enable features ###########################################################################
|
||||||
|
|
||||||
# Create config.h from selected features and fallback defautls
|
# Create config.h from selected features and fallback defaults
|
||||||
AS_IF([test "x$enable_emergency_shell" = "xyes"], [
|
|
||||||
AC_DEFINE(EMERGENCY_SHELL, 1, [Fork off init and let PID 1 wait and start /bin/sh if init crashes.])])
|
|
||||||
|
|
||||||
AS_IF([test "x$enable_fallback_shell" = "xyes"], [
|
|
||||||
AC_DEFINE(FALLBACK_SHELL, 1, [Start /bin/sh on console if no TTYs.])])
|
|
||||||
|
|
||||||
AS_IF([test "x$enable_auto_reload" = "xyes"], [
|
AS_IF([test "x$enable_auto_reload" = "xyes"], [
|
||||||
AC_DEFINE(AUTO_RELOAD, 1, [Finit automatically does `initctl reload` on any .conf change])])
|
AC_DEFINE(AUTO_RELOAD, 1, [Finit automatically does `initctl reload` on any .conf change])])
|
||||||
|
|
||||||
AS_IF([test "x$enable_watchdog" = "xyes"], [
|
AS_IF([test "x$enable_kernel_cmdline" = "xyes"], [
|
||||||
AC_DEFINE(BUILTIN_WATCHDOG, 1, [Enable built-in watchdog, kicks on /dev/watchdog])])
|
AC_DEFINE(KERNEL_CMDLINE, 1, [Dumpster diving after init args from /proc/cmdline])])
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_fastboot" = "xyes"], [
|
||||||
|
AC_DEFINE(FAST_BOOT, 1, [Skip fsck check on filesystems listed in /etc/fstab])])
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_fsckfix" = "xyes"], [
|
||||||
|
AC_DEFINE(FSCK_FIX, 1, [Run fsck fix mode (options: -yf) on filesystems listed in /etc/fstab])])
|
||||||
|
|
||||||
AS_IF([test "x$enable_redirect" = "xyes"], [
|
AS_IF([test "x$enable_redirect" = "xyes"], [
|
||||||
AC_DEFINE(REDIRECT_OUTPUT, 1, [Enable redirection of service output to /dev/null])])
|
AC_DEFINE(REDIRECT_OUTPUT, 1, [Enable redirection of service output to /dev/null])])
|
||||||
|
|
||||||
### Disable features ###########################################################################
|
### Disable features ###########################################################################
|
||||||
AS_IF([test "x$enable_logit" != "xno"], [
|
|
||||||
AC_DEFINE(LOGIT_ENABLED, 1, [Enable logit tool, used for log redirection by Finit])])
|
|
||||||
|
|
||||||
AS_IF([test "x$enable_logrotate" != "xno"], [
|
AS_IF([test "x$enable_logrotate" != "xno"], [
|
||||||
AC_DEFINE(LOGROTATE_ENABLED, 1, [Enable built-in rotation of /var/log/wtmp et al.])])
|
AC_DEFINE(LOGROTATE_ENABLED, 1, [Enable built-in rotation of /var/log/wtmp et al.])])
|
||||||
|
|
||||||
@@ -183,9 +189,13 @@ AS_IF([test "x$with_sysconfig" != "xno"], [
|
|||||||
[System environment, default /etc/default & /etc/conf.d])])])
|
[System environment, default /etc/default & /etc/conf.d])])])
|
||||||
|
|
||||||
AS_IF([test "x$with_heading" != "xno"], [
|
AS_IF([test "x$with_heading" != "xno"], [
|
||||||
AS_IF([test "x$heading" = "xyes"], [
|
AS_IF([test "x$heading" = "xyes"], [heading=""])
|
||||||
heading="$PACKAGE_NAME v$PACKAGE_VERSION"])])
|
AC_DEFINE_UNQUOTED(INIT_OSHEADING, "$heading", [Displayed by Finit at boot, defaults to /etc/os-release PRETTY_NAME])])
|
||||||
AC_DEFINE_UNQUOTED(INIT_HEADING, "$heading", [Displayed by Finit at boot])
|
|
||||||
|
AS_IF([test "x$with_group" != "xno"], [
|
||||||
|
AS_IF([test "x$group" = "xyes"], [
|
||||||
|
group=root])])
|
||||||
|
AC_DEFINE_UNQUOTED(DEFGROUP, "$group", [For /run/finit/socket])
|
||||||
|
|
||||||
AS_IF([test "x$with_hostname" != "xno"], [
|
AS_IF([test "x$with_hostname" != "xno"], [
|
||||||
AS_IF([test "x$hostname" = "xyes"], [
|
AS_IF([test "x$hostname" = "xyes"], [
|
||||||
@@ -204,10 +214,19 @@ AS_IF([test "x$with_random_seed" != "xno"], [
|
|||||||
AC_EXPAND_DIR(random_path, "$random_seed")
|
AC_EXPAND_DIR(random_path, "$random_seed")
|
||||||
AC_DEFINE_UNQUOTED(RANDOMSEED, "$random_path", [Improve random at boot by seeding it with sth from before.])])
|
AC_DEFINE_UNQUOTED(RANDOMSEED, "$random_path", [Improve random at boot by seeding it with sth from before.])])
|
||||||
|
|
||||||
|
AS_IF([test "x$with_keventd" != "xno"], [with_keventd=yes])
|
||||||
|
|
||||||
|
AS_IF([test "x$with_watchdog" != "xno"], [
|
||||||
|
AS_IF([test "x$watchdog" = "xyes"], [
|
||||||
|
watchdog=/dev/watchdog])
|
||||||
|
with_watchdog=yes
|
||||||
|
AC_DEFINE_UNQUOTED(WDT_DEVNODE, "$watchdog", [Built-in watchdog device node])], [
|
||||||
|
watchdog=])
|
||||||
|
|
||||||
# Control build with automake flags
|
# Control build with automake flags
|
||||||
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
||||||
AM_CONDITIONAL(WATCHDOGD, [test "x$enable_watchdog" = "xyes"])
|
AM_CONDITIONAL(KEVENTD, [test "x$with_keventd" != "xno"])
|
||||||
AM_CONDITIONAL(LOGIT, [test "x$enable_logit" = "xyes"])
|
AM_CONDITIONAL(WATCHDOGD, [test "x$with_watchdog" != "xno"])
|
||||||
AM_CONDITIONAL(DOC, [test "x$enable_doc" = "xyes"])
|
AM_CONDITIONAL(DOC, [test "x$enable_doc" = "xyes"])
|
||||||
AM_CONDITIONAL(CONTRIB, [test "x$enable_contrib" = "xyes"])
|
AM_CONDITIONAL(CONTRIB, [test "x$enable_contrib" = "xyes"])
|
||||||
|
|
||||||
@@ -226,6 +245,9 @@ AC_DEFINE_UNQUOTED(RESCUE_CONF, "$rescue_conf", [Finit rescue mode .conf])
|
|||||||
AC_EXPAND_DIR(sample_conf, "$libdir/finit/sample.conf")
|
AC_EXPAND_DIR(sample_conf, "$libdir/finit/sample.conf")
|
||||||
AC_DEFINE_UNQUOTED(SAMPLE_CONF, "$sample_conf", [Finit sameple.conf for initctl create])
|
AC_DEFINE_UNQUOTED(SAMPLE_CONF, "$sample_conf", [Finit sameple.conf for initctl create])
|
||||||
|
|
||||||
|
AS_IF([test "$heading" = ""], [heading="<DEFAULT>"])
|
||||||
|
AS_IF([test "$heading" = "no"], [heading="<NONE>"])
|
||||||
|
|
||||||
# Generate all files
|
# Generate all files
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|
||||||
@@ -253,12 +275,14 @@ Behavior:
|
|||||||
Optional features:
|
Optional features:
|
||||||
Install doc/..........: $enable_doc
|
Install doc/..........: $enable_doc
|
||||||
Install contrib/......: $enable_contrib
|
Install contrib/......: $enable_contrib
|
||||||
Built-in watchdogd....: $enable_watchdog
|
Built-in keventd......: $with_keventd
|
||||||
|
Built-in watchdogd....: $with_watchdog $watchdog
|
||||||
Built-in logrotate....: $enable_logrotate
|
Built-in logrotate....: $enable_logrotate
|
||||||
Scripting tool logit..: $enable_logit
|
Skip fsck check.......: $enable_fastboot
|
||||||
Emergency shell.......: $enable_emergency_shell
|
Run fsck fix mode.....: $enable_fsckfix
|
||||||
Fallback shell........: $enable_fallback_shell
|
Redirect output.......: $enable_redirect
|
||||||
Default hostname......: $hostname
|
Default hostname......: $hostname
|
||||||
|
Default group.........: $group
|
||||||
Default runlevel......: $runlevel
|
Default runlevel......: $runlevel
|
||||||
|
|
||||||
------------- Compiler version --------------
|
------------- Compiler version --------------
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
SUBDIRS = finit.d
|
SUBDIRS = finit.d
|
||||||
docsdir := @docdir@/contrib/alpine
|
docsdir := @docdir@/contrib/alpine
|
||||||
docs_DATA = README.md finit.conf alpine-release build.sh install.sh rc.local
|
docs_DATA = README.md finit.conf build.sh install.sh rc.local
|
||||||
EXTRA_DIST = $(docs_DATA)
|
EXTRA_DIST = $(docs_DATA)
|
||||||
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
3.6.2
|
|
||||||
@@ -17,8 +17,8 @@ PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig ./configure \
|
|||||||
--prefix=/usr --exec-prefix= \
|
--prefix=/usr --exec-prefix= \
|
||||||
--sysconfdir=/etc --localstatedir=/var \
|
--sysconfdir=/etc --localstatedir=/var \
|
||||||
--enable-dbus-plugin --enable-x11-common-plugin \
|
--enable-dbus-plugin --enable-x11-common-plugin \
|
||||||
--enable-alsa-utils-plugin --enable-watchdog \
|
--enable-alsa-utils-plugin --with-watchdog \
|
||||||
--with-heading="Alpine Linux 3.13"
|
--with-keventd
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "*** Building ..."
|
echo "*** Building ..."
|
||||||
|
|||||||
@@ -5,6 +5,22 @@
|
|||||||
# Default is 2
|
# 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
|
||||||
|
|
||||||
|
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
|
||||||
|
# Finit upon receiving SIGINT (from the kernel).
|
||||||
|
#task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
|
||||||
|
|
||||||
|
# Task to run if the kernel gets a power fail condition is pressed.
|
||||||
|
# Asserted by Finit upon receiving SIGPWR (from the kernel).
|
||||||
|
#task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
|
||||||
|
|
||||||
## Bootstrap services and tasks
|
## Bootstrap services and tasks
|
||||||
# Can be listed here or in /etc/finit.d/*.conf
|
# Can be listed here or in /etc/finit.d/*.conf
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
docsdir := @docdir@/contrib/alpine/finit.d/available
|
docsdir := @docdir@/contrib/alpine/finit.d/available
|
||||||
docs_DATA = acpid.conf crond.conf dropbear.conf getty.conf keymap.conf \
|
docs_DATA = acpid.conf crond.conf dropbear.conf getty.conf keymap.conf \
|
||||||
lxdm.conf modules.conf ntpd.conf klogd.conf syslog.conf \
|
lxdm.conf modules.conf ntpd.conf syslog.conf watchdog.conf
|
||||||
watchdog.conf
|
|
||||||
EXTRA_DIST = $(docs_DATA)
|
EXTRA_DIST = $(docs_DATA)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
# Consoles to start getty on when system is up
|
# Consoles to start getty on when system is up
|
||||||
tty [12345] /dev/tty1 noclear nowait
|
tty [12345] /dev/ttyS0 noclear
|
||||||
tty [2345] /dev/tty2 noclear nowait
|
tty [12345] /dev/tty1 noclear nowait
|
||||||
tty [2345] /dev/tty3 noclear nowait
|
tty [2345] /dev/tty2 noclear nowait
|
||||||
|
tty [2345] /dev/tty3 noclear nowait
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
# Start klogd as soon as possible, after syslogd, should always run
|
|
||||||
service [S12345] <pid/syslogd> env:-/etc/conf.d/klogd klogd -n $KLOGD_OPTS -- Kernel log daemon
|
|
||||||
@@ -4,3 +4,4 @@
|
|||||||
#module evdev
|
#module evdev
|
||||||
#module mousedev
|
#module mousedev
|
||||||
#module 8139cp
|
#module 8139cp
|
||||||
|
module softdog
|
||||||
|
|||||||
@@ -1,2 +1,4 @@
|
|||||||
# Start syslogd as soon as possible, should always run
|
# Start syslogd as soon as possible, should always run
|
||||||
service [S12345] env:-/etc/conf.d/syslog syslogd -n $SYSLOGD_OPTS -- Syslog daemon
|
# 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
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ if [ "x`id -u`" != "x0" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Adjust base directory
|
# Adjust base directory
|
||||||
if [ -e alpine-release ]; then
|
grep -q alpine Makefile 2>/dev/null
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
cd ../..
|
cd ../..
|
||||||
elif [ ! -e autogen.sh ]; then
|
elif [ ! -e configure.ac ]; then
|
||||||
echo "*** Please run this script from the Finit base directory."
|
echo "*** Please run this script from the Finit base directory."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -4,5 +4,5 @@
|
|||||||
#
|
#
|
||||||
# Each line is run in sequence.
|
# Each line is run in sequence.
|
||||||
#
|
#
|
||||||
# NOTE: Remeber to set the executable bit!
|
# NOTE: Remember to set the executable bit!
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
SUBDIRS = finit.d grub.d
|
SUBDIRS = finit.d
|
||||||
docsdir := @docdir@/contrib/debian
|
docsdir := @docdir@/contrib/debian
|
||||||
docs_DATA = README.md finit.conf os-release build.sh install.sh
|
docs_DATA = README.md finit.conf build.sh install.sh
|
||||||
EXTRA_DIST = $(docs_DATA)
|
EXTRA_DIST = $(docs_DATA)
|
||||||
|
|||||||
@@ -20,29 +20,42 @@ tools pre-systemd work as intended.
|
|||||||
|
|
||||||
root@debian:~# apt install initscripts console-setup
|
root@debian:~# apt install initscripts console-setup
|
||||||
|
|
||||||
|
> **Note:** as of Debian 11 (Bullseye), libuev and libite are part of
|
||||||
|
> the main section of Debian. So just install the -dev packages :)
|
||||||
|
|
||||||
The following script can then be used to configure, build, install and
|
The following script can then be used to configure, build, install and
|
||||||
set up your system to run Finit:
|
set up your system to run Finit:
|
||||||
|
|
||||||
user@debian:~/finit$ contrib/debian/build.sh
|
user@debian:~/finit$ contrib/debian/build.sh
|
||||||
|
|
||||||
However, since `/sbin/init` already exists on your system, the script
|
However, since `/sbin/init` already exists on your system, the script
|
||||||
creates another entry in your GRUB config, in `/etc/grub.d/40_custom`,
|
creates another entry in your GRUB config by updating `$SUPPORTED_INITS`
|
||||||
where `init=/sbin/finit` is added to your kernel line. It is of course
|
in `/etc/grub.d/10_inux` and run `update-grub`. On reboot you will find
|
||||||
also possible to change the default init to Finit, if you do you can
|
a (finit) entry in the "Advanced options for Debian GNU/Linux" section.
|
||||||
remove the custom Grub entry:
|
It is of course also possible to change the default init to Finit:
|
||||||
|
|
||||||
user@debian:~/finit# cd /sbin
|
user@debian:~/finit# cd /sbin
|
||||||
user@debian:/sbin# sudo rm init
|
user@debian:/sbin# sudo mv init oldinit
|
||||||
user@debian:/sbin# sudo ln -s finit init
|
user@debian:/sbin# sudo ln -s finit init
|
||||||
|
|
||||||
Before rebooting, check the default [/etc/finit.conf](finit.conf) and
|
Before rebooting, check the default [/etc/finit.conf](finit.conf) and
|
||||||
`/etc/finit.d/*.conf` files. The build + install script above provides
|
`/etc/finit.d/*.conf` files. The build + install script above provides
|
||||||
a few sample `.conf` files. See `initctl list` after boot for a list of
|
a few sample `.conf` files. See `initctl ls` after boot for a list of
|
||||||
enabled and available services.
|
enabled and available services, you can then use `enable` and `disable`
|
||||||
|
comands to `initctl`, followed by `reload` to activate your changes.
|
||||||
|
|
||||||
You can also use a standard [/etc/rc.local](rc.local) for one-shot tasks
|
You can also use a standard [/etc/rc.local](rc.local) for one-shot tasks
|
||||||
and initialization like keyboard language etc.
|
and initialization like keyboard language etc.
|
||||||
|
|
||||||
|
> **NOTE:** X Window system, you may need to `sudo apt install elogind`
|
||||||
|
> (Bullseye and later), followed by `initctl reload` to activate it (it
|
||||||
|
> is enabled by default), and logout/login again. The elogind daemon
|
||||||
|
> ensures a regular non-root user can start and interact with an X
|
||||||
|
> session, otherwise keyboard and mouse won't work. When you're happy,
|
||||||
|
> you can enable the lightdm.conf, change the default runlevel to 3, and
|
||||||
|
> presto! you have a desktop again.
|
||||||
|
|
||||||
|
|
||||||
Have fun!
|
Have fun!
|
||||||
/Joachim ツ
|
/Joachim ツ
|
||||||
|
|
||||||
|
|||||||
@@ -25,9 +25,8 @@ echo
|
|||||||
--prefix=/usr --exec-prefix= \
|
--prefix=/usr --exec-prefix= \
|
||||||
--sysconfdir=/etc --localstatedir=/var \
|
--sysconfdir=/etc --localstatedir=/var \
|
||||||
--enable-dbus-plugin --enable-x11-common-plugin \
|
--enable-dbus-plugin --enable-x11-common-plugin \
|
||||||
--enable-alsa-utils-plugin \
|
--enable-alsa-utils-plugin --with-keventd \
|
||||||
--with-random-seed=/var/lib/urandom/random-seed \
|
--with-random-seed=/var/lib/urandom/random-seed
|
||||||
--with-heading="Debian GNU/Linux"
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo
|
echo
|
||||||
|
|||||||
@@ -5,6 +5,22 @@
|
|||||||
# Default is 2
|
# 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
|
||||||
|
|
||||||
|
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
|
||||||
|
# Finit upon receiving SIGINT (from the kernel).
|
||||||
|
#task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
|
||||||
|
|
||||||
|
# Task to run if the kernel gets a power fail condition is pressed.
|
||||||
|
# Asserted by Finit upon receiving SIGPWR (from the kernel).
|
||||||
|
#task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
|
||||||
|
|
||||||
## Bootstrap services and tasks
|
## Bootstrap services and tasks
|
||||||
# Can be listed here or in /etc/finit.d/*.conf
|
# Can be listed here or in /etc/finit.d/*.conf
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
SUBDIRS = available
|
SUBDIRS = available
|
||||||
docsdir := @docdir@/contrib/debian/finit.d
|
docsdir := @docdir@/contrib/debian/finit.d
|
||||||
d_LINKS = console-setup.conf getty.conf keyboard-setup.conf \
|
d_LINKS = acpid.conf apparmor.conf avahi-daemon.conf \
|
||||||
modules.conf rsyslogd.conf sshd.conf
|
bluetooth.conf console-setup.conf elogind.conf \
|
||||||
|
getty.conf keyboard-setup.conf modules.conf \
|
||||||
|
plymouth-quit.conf rsyslogd.conf sshd.conf
|
||||||
|
|
||||||
install-exec-hook:
|
install-exec-hook:
|
||||||
@$(MKDIR_P) $(DESTDIR)$(docsdir)/available
|
@$(MKDIR_P) $(DESTDIR)$(docsdir)/available
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
docsdir := @docdir@/contrib/debian/finit.d/available
|
docsdir := @docdir@/contrib/debian/finit.d/available
|
||||||
docs_DATA = acpid.conf console-setup.conf getty.conf keyboard-setup.conf \
|
docs_DATA = acpid.conf apparmor.conf avahi-daemon.conf bluetooth.conf \
|
||||||
lightdm.conf modules.conf rsyslogd.conf sntpd.conf \
|
console-setup.conf elogind.conf getty.conf \
|
||||||
sshd.conf syslogd.conf xdm.conf
|
keyboard-setup.conf lightdm.conf modules.conf sntpd.conf \
|
||||||
|
plymouth-quit.conf rsyslogd.conf sshd.conf syslogd.conf \
|
||||||
|
xdm.conf
|
||||||
EXTRA_DIST = $(docs_DATA)
|
EXTRA_DIST = $(docs_DATA)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
task [2345] <sys/pwr/ac,pid/syslogd> halt:usr1 env:-/etc/default/anacron anacron -d -q $ANACRON_ARGS -- Anacron jobs
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
sysv [S] /etc/init.d/apparmor -- AppArmor initialization
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
service [2345] env:-/etc/default/avahi-daemon avahi-daemon -s $AVAHI_DAEMON_OPTS -- Avahi mDNS/DNS-SD Stack
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# To ignore errors like "org.freedesktop.hostname1", update the env file with
|
||||||
|
# "--noplugin=hostname", i.e. append to BLUETOOTHD_OPTS
|
||||||
|
service [2345] log:null env:-/etc/default/bluetooth /usr/libexec/bluetooth/bluetoothd -n $BLUETOOTHD_OPTS -- Bluetooth service
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
service [2345] <sys/pwr/ac,pid/syslogd> env:-/etc/default/cron cron -f $EXTRA_OPTS -- Background job processing daemon
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# On some systems, bootstrap can be really quick and cause elogind
|
||||||
|
# to not start before a user has managed to log in. To prevent
|
||||||
|
# this, add <pid/elogind> as condition to your TTYs in getty.conf
|
||||||
|
service [2345] <pid/syslogd> /lib/elogind/elogind -- Login manager
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
# Consoles to start getty on when system is up
|
# Consoles to start getty on when system is up
|
||||||
tty [12345] /dev/tty1 linux noclear nowait
|
tty [12345] /dev/tty1 linux noclear nowait
|
||||||
tty [2345] /dev/tty2 linux noclear nowait
|
tty [2345] /dev/tty2 linux nowait
|
||||||
tty [2345] /dev/tty3 linux noclear nowait
|
tty [2345] /dev/tty3 linux nowait
|
||||||
|
tty [2345] /dev/tty4 linux nowait
|
||||||
|
tty [2345] /dev/tty5 linux nowait
|
||||||
|
tty [2345] /dev/tty6 linux nowait
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# Need to stop plymouth, or it'll block stdin on tty1
|
||||||
|
task [S] /usr/bin/plymouth quit -- Stopping Plymouth Boot Screen
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
exec tail -n +3 $0
|
|
||||||
# This file provides an easy way to add custom menu entries. Simply type the
|
|
||||||
# menu entries you want to add after this comment. Be careful not to change
|
|
||||||
# the 'exec tail' line above.
|
|
||||||
|
|
||||||
menuentry '$MENU with Finit' --class $TYPE --class gnu-linux --class gnu --class os --user {
|
|
||||||
insmod gzio
|
|
||||||
insmod part_msdos
|
|
||||||
insmod ext2
|
|
||||||
search --no-floppy --fs-uuid --set=root $BOOT
|
|
||||||
linux /vmlinuz root=UUID=$ROOT ro quiet init=/sbin/finit
|
|
||||||
initrd /initrd.img
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
docsdir := @docdir@/contrib/debian/grub.d
|
|
||||||
docs_DATA = 40_custom
|
|
||||||
EXTRA_DIST = $(docs_DATA)
|
|
||||||
@@ -8,10 +8,10 @@ if [ "x`id -u`" != "x0" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Adjust base directory
|
# Adjust base directory
|
||||||
grep -q Debian os-release 2>/dev/null
|
grep -q debian Makefile 2>/dev/null
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
cd ../..
|
cd ../..
|
||||||
elif [ ! -e autogen.sh ]; then
|
elif [ ! -e configure.ac ]; then
|
||||||
echo "*** Please run this script from the Finit base directory."
|
echo "*** Please run this script from the Finit base directory."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@@ -23,7 +23,7 @@ echo "/sbin/finit - PID 1"
|
|||||||
echo "/lib/finit/plugins/* - All enabled Finit plugins"
|
echo "/lib/finit/plugins/* - All enabled Finit plugins"
|
||||||
echo "/etc/finit.conf - Finit configuration file"
|
echo "/etc/finit.conf - Finit configuration file"
|
||||||
echo "/etc/finit.d/ - Finit services"
|
echo "/etc/finit.d/ - Finit services"
|
||||||
echo "/etc/grub.d/40_custom - Add menu entry to the Grub boot loader"
|
echo "/etc/grub.d/10_linux - Add Finit to Grub's SUPPORTED_INITS"
|
||||||
echo
|
echo
|
||||||
read -p "Do you want to continue (y/N)? " yorn
|
read -p "Do you want to continue (y/N)? " yorn
|
||||||
echo
|
echo
|
||||||
@@ -38,12 +38,18 @@ if [ "x$yorn" = "xy" -o "x$yorn" = "xY" ]; then
|
|||||||
cp -va finit.d /etc/
|
cp -va finit.d /etc/
|
||||||
|
|
||||||
echo "*** Setting up a GRUB boot entry ..."
|
echo "*** Setting up a GRUB boot entry ..."
|
||||||
MENU=`grep gnu-linux /boot/grub/grub.cfg |head -1 |sed "s/menuentry '\([^']*\).*/\1/"`
|
fn=/etc/grub.d/10_linux
|
||||||
TYPE=`grep gnu-linux /boot/grub/grub.cfg |head -1 |sed "s/.*' --class \([a-z]*\).*/\1/"`
|
if [ -e $fn ]; then
|
||||||
BOOT=`grep set=root /boot/grub/grub.cfg |head -1 |sed 's/.* \([a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*\).*/\1/'`
|
if `grep SUPPORTED_INITS $fn |head -1 |grep -q finit`; then
|
||||||
ROOT=`grep root=UUID /boot/grub/grub.cfg |head -1 |sed 's/.*UUID=\([a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*\).*/\1/'`
|
echo "Already installed, done."
|
||||||
cat grub.d/40_custom | sed "s,\$BOOT,$BOOT,;s,\$ROOT,$ROOT,;s,\$TYPE,$TYPE,;s,\$MENU,$MENU," >/etc/grub.d/40_custom
|
else
|
||||||
update-grub
|
echo "Adding Finit to list of SUPPORTED_INITS ..."
|
||||||
|
sed -i 's/SUPPORTED_INITS="[^"]*/& finit:\/sbin\/finit/' $fn
|
||||||
|
update-grub
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Cannot find $fn, you'll have to set up your bootloader on your own."
|
||||||
|
fi
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "*** Done"
|
echo "*** Done"
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
PRETTY_NAME="Debian GNU/Linux 8 (jessie)"
|
|
||||||
NAME="Debian GNU/Linux"
|
|
||||||
VERSION_ID="8"
|
|
||||||
VERSION="8 (jessie)"
|
|
||||||
ID=debian
|
|
||||||
HOME_URL="http://www.debian.org/"
|
|
||||||
SUPPORT_URL="http://www.debian.org/support"
|
|
||||||
BUG_REPORT_URL="https://bugs.debian.org/"
|
|
||||||
+37
-2
@@ -8,6 +8,18 @@ module evdev
|
|||||||
module loop
|
module loop
|
||||||
module psmouse
|
module psmouse
|
||||||
|
|
||||||
|
# Top-level cgroups and their default settings. All groups mandatory
|
||||||
|
# but more can be added, max 8 groups in total currently. The cgroup
|
||||||
|
# 'root' is also available, reserved for RT processes. Settings are
|
||||||
|
# as-is, only one shorthand 'mem.' exists, other than that it's the
|
||||||
|
# cgroup v2 controller default names.
|
||||||
|
cgroup init cpu.weight:100
|
||||||
|
cgroup user cpu.weight:100
|
||||||
|
cgroup system cpu.weight:9700 cpu.max:50000
|
||||||
|
|
||||||
|
# Example extra cgroup
|
||||||
|
cgroup maint cpu.weight:100
|
||||||
|
|
||||||
# Runlevel to start after bootstrap, runlevel 'S'
|
# Runlevel to start after bootstrap, runlevel 'S'
|
||||||
runlevel 2
|
runlevel 2
|
||||||
|
|
||||||
@@ -16,13 +28,21 @@ network service networking start
|
|||||||
|
|
||||||
# Max file size for each log file: 100 kiB, rotate max 4 copies:
|
# 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 => 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
|
# Virtual consoles to start getty on
|
||||||
tty /dev/tty1
|
tty /dev/tty1
|
||||||
tty /dev/tty2
|
tty /dev/tty2
|
||||||
tty /dev/tty3
|
tty /dev/tty3
|
||||||
|
|
||||||
|
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
|
||||||
|
# Finit upon receiving SIGINT (from the kernel).
|
||||||
|
task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
|
||||||
|
|
||||||
|
# Task to run if the kernel gets a power fail condition is pressed.
|
||||||
|
# Asserted by Finit upon receiving SIGPWR (from the kernel).
|
||||||
|
task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
|
||||||
|
|
||||||
# Alternative method instead of runparts
|
# Alternative method instead of runparts
|
||||||
#task [S] /etc/init.d/keyboard-setup start -- Setting up preliminary keymap
|
#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/acpid start -- Starting ACPI Daemon
|
||||||
@@ -30,9 +50,24 @@ tty /dev/tty3
|
|||||||
#run [2] /etc/init.d/networking start -- Start networking
|
#run [2] /etc/init.d/networking start -- Start networking
|
||||||
|
|
||||||
# Services to be monitored and respawned as needed
|
# 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] <pid/syslogd> klogd -n -- Kernel logging server
|
||||||
service [2345] syslogd -n -- Syslog server
|
service [2345] syslogd -n -- Syslog server
|
||||||
service [3] gdm -- GNOME Display Manager
|
|
||||||
|
# gdm in the system cgroup (default when read from it's own .conf file)
|
||||||
|
cgroup.system
|
||||||
|
service [3] cgroup:cpu.weight:250,mem.max:10M gdm -- GNOME Display Manager
|
||||||
|
|
||||||
|
# Start SSH daemon with opts from /etc/default/ssh (if available), move
|
||||||
|
# to user cgroup with cpu.weight:250. Default for services is system
|
||||||
|
# group. Default weight in user group is 100 (above). Max length of
|
||||||
|
# cgroup argument is (currently) 63 chars.
|
||||||
|
#
|
||||||
|
# Notice alternative syntax where current cgroup is only set for this
|
||||||
|
# particular service.
|
||||||
|
service [2345] cgroup.user:cpu.weight:250,mem.max:10M env:-/etc/default/ssh /usr/sbin/sshd -D $SSHD_OPTS -- OpenSSH daemon
|
||||||
|
|
||||||
# The BusyBox ntpd does not use syslog when running in the foreground
|
# 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
|
# So we use this trick to redirect stdout/stderr to a log file. The
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
SUBDIRS = finit.d
|
SUBDIRS = finit.d
|
||||||
docsdir := @docdir@/contrib/void
|
docsdir := @docdir@/contrib/void
|
||||||
docs_DATA = README.md finit.conf build.sh install.sh rc.local xbps
|
docs_DATA = README.md finit.conf build.sh install.sh rc.local
|
||||||
EXTRA_DIST = $(docs_DATA)
|
EXTRA_DIST = $(docs_DATA)
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig ./configure \
|
|||||||
--prefix=/usr --exec-prefix= \
|
--prefix=/usr --exec-prefix= \
|
||||||
--sysconfdir=/etc --localstatedir=/var \
|
--sysconfdir=/etc --localstatedir=/var \
|
||||||
--enable-dbus-plugin --enable-x11-common-plugin \
|
--enable-dbus-plugin --enable-x11-common-plugin \
|
||||||
--enable-alsa-utils-plugin --enable-watchdog \
|
--enable-alsa-utils-plugin --with-watchdog \
|
||||||
--with-heading="Void Linux"
|
--with-keventd
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "*** Building ..."
|
echo "*** Building ..."
|
||||||
|
|||||||
@@ -5,5 +5,22 @@
|
|||||||
# Default is 2
|
# 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
|
||||||
|
|
||||||
|
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
|
||||||
|
# Finit upon receiving SIGINT (from the kernel).
|
||||||
|
#task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
|
||||||
|
|
||||||
|
# Task to run if the kernel gets a power fail condition is pressed.
|
||||||
|
# Asserted by Finit upon receiving SIGPWR (from the kernel).
|
||||||
|
#task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
|
||||||
|
|
||||||
## Bootstrap services and tasks
|
## Bootstrap services and tasks
|
||||||
# Can be listed here or in /etc/finit.d/*.conf
|
# Can be listed here or in /etc/finit.d/*.conf
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
docsdir := @docdir@/contrib/void/finit.d/available
|
docsdir := @docdir@/contrib/void/finit.d/available
|
||||||
docs_DATA = acpid.conf crond.conf dhcpcd.conf dmeventd.conf getty.conf \
|
docs_DATA = acpid.conf crond.conf dhcpcd.conf dmeventd.conf getty.conf \
|
||||||
keymap.conf klogd.conf lxdm.conf modules.conf ntpd.conf \
|
keymap.conf lxdm.conf modules.conf ntpd.conf \
|
||||||
sshd.conf syslogd.conf uuidd.conf
|
sshd.conf syslog.conf uuidd.conf
|
||||||
EXTRA_DIST = $(docs_DATA)
|
EXTRA_DIST = $(docs_DATA)
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
# Start klogd as soon as possible, should always run
|
|
||||||
service [S12345] <pid/syslogd> klogd -n -- Kernel log daemon
|
|
||||||
@@ -4,3 +4,4 @@
|
|||||||
#module evdev
|
#module evdev
|
||||||
#module mousedev
|
#module mousedev
|
||||||
#module 8139cp
|
#module 8139cp
|
||||||
|
module softdog
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# 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
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
# Start syslogd as soon as possible, should always run
|
|
||||||
service [S12345] syslogd -n -- Syslog daemon
|
|
||||||
@@ -8,9 +8,10 @@ if [ "x`id -u`" != "x0" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Adjust base directory
|
# Adjust base directory
|
||||||
if [ -e xbps ]; then
|
grep -q void Makefile 2>/dev/null
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
cd ../..
|
cd ../..
|
||||||
elif [ ! -e autogen.sh ]; then
|
elif [ ! -e configure.ac ]; then
|
||||||
echo "*** Please run this script from the Finit base directory."
|
echo "*** Please run this script from the Finit base directory."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -4,4 +4,4 @@
|
|||||||
#
|
#
|
||||||
# Each line is run in sequence.
|
# Each line is run in sequence.
|
||||||
#
|
#
|
||||||
# NOTE: Remeber to set the executable bit!
|
# NOTE: Remember to set the executable bit!
|
||||||
|
|||||||
+18
-6
@@ -19,19 +19,31 @@ Some of these are also registered in the issue tracker on GitHub.
|
|||||||
* Add new (complimentary) .svc file format to slowly migrate away
|
* Add new (complimentary) .svc file format to slowly migrate away
|
||||||
from the very terse one-liner format currently used
|
from the very terse one-liner format currently used
|
||||||
* Allow running as non-pid1 => read .conf and RCSD form cmdline
|
* Allow running as non-pid1 => read .conf and RCSD form cmdline
|
||||||
* When a process dies, and Finit does not restart it, we should collect
|
|
||||||
a `siginfo_t` from the SIGCHLD signal and supply to the user in case
|
|
||||||
`initctl status <process>` is called to debug the issue.
|
|
||||||
* Add `finit.conf` support for UPS notification (SIGPWR) to start a task
|
* Add `finit.conf` support for UPS notification (SIGPWR) to start a task
|
||||||
using, e.g. <sys/power/{ok,fail,low}> conditions. More info in sig.c
|
using, e.g. <sys/power/{ok,fail,low}> conditions. More info in sig.c
|
||||||
|
|
||||||
|
As of Finit v4.1 SIGPWR generates <sys/power/fail> condition and it
|
||||||
|
is up to a task to check why and take appropriate action.
|
||||||
* Add `finit.conf` support for ctrl-alt-delete (SIGINT) and kbrequest,
|
* Add `finit.conf` support for ctrl-alt-delete (SIGINT) and kbrequest,
|
||||||
i.e. KeyboardSignal, (SIGWINCH) behavior. Using conditions to a task,
|
i.e. KeyboardSignal, (SIGWINCH) behavior. Using conditions to a task,
|
||||||
e.g, <sys/key/ctrlaltdel> and <sys/key/signal> like SIGPWR handling.
|
e.g, <sys/key/ctrlaltdel> and <sys/key/signal> like SIGPWR handling.
|
||||||
* Write man pages for finit and `finit.conf`, steal from the excellent
|
|
||||||
`pimd` man pages ...
|
As of Finit v4.1 SIGINT generates <sys/key/ctrlaltdel>, but there is
|
||||||
* Add support for timed shutdown in Finit, including cancelled shutdown
|
no check if the signal actually originates from the kernel. To get
|
||||||
|
this verification, a new libuEv release is needed. As of June 6 -21
|
||||||
|
that functionality is not yet released.
|
||||||
|
|
||||||
|
|
||||||
|
Initctl
|
||||||
|
-------
|
||||||
|
|
||||||
|
* Add support for timed shutdown in Finit, including cancelled shutdown:
|
||||||
|
|
||||||
|
shutdown -h 03:35 "foobar was here"
|
||||||
|
|
||||||
* Add support for JSON output, or similar, from `initctl show`, e.g.
|
* Add support for JSON output, or similar, from `initctl show`, e.g.
|
||||||
`initctl show --json`
|
`initctl show --json`
|
||||||
|
* Add support for `-s` to redirect all output to syslog, for scripting
|
||||||
|
|
||||||
|
|
||||||
Init
|
Init
|
||||||
|
|||||||
+15
-14
@@ -9,12 +9,16 @@ Bootstrap
|
|||||||
6. Load all `.so` plugins
|
6. Load all `.so` plugins
|
||||||
7. Call `fsck` on file systems listed in `/etc/fstab`
|
7. Call `fsck` on file systems listed in `/etc/fstab`
|
||||||
8. Populate `/dev` using either udev or mdev, depending on system type
|
8. Populate `/dev` using either udev or mdev, depending on system type
|
||||||
9. Parse `/etc/finit.conf` and all `/etc/finit.d/*.conf` files
|
9. Parse `/etc/finit.conf`
|
||||||
10. Start built-in watchdog, if enabled
|
10. Start built-in watchdog, if enabled and `WDT_DEVNODE` exists. This
|
||||||
11. Set hostname
|
means any WDT that requires a kernel module need to be either
|
||||||
|
compiled into the kernel, or insmod'ed in `/etc/finit.conf`
|
||||||
|
11. Load all `/etc/finit.d/*.conf` files and set hostname
|
||||||
12. Remount `/` read-write if `/` is listed in `/etc/fstab` without `ro`
|
12. Remount `/` read-write if `/` is listed in `/etc/fstab` without `ro`
|
||||||
13. Call 1st level hooks, `HOOK_ROOTFS_UP`
|
13. Call 1st level hooks, `HOOK_ROOTFS_UP`
|
||||||
14. Mount all file systems listed in `/etc/fstab` and swap, if available
|
14. Mount all file systems listed in `/etc/fstab` and swap, if available.
|
||||||
|
On mount error `HOOK_MOUNT_ERROR` is called. After mount, regardless
|
||||||
|
of error, `HOOK_MOUNT_POST` is called
|
||||||
15. Enable SysV init signals
|
15. Enable SysV init signals
|
||||||
16. Call 2nd level hooks, `HOOK_BASEFS_UP`
|
16. Call 2nd level hooks, `HOOK_BASEFS_UP`
|
||||||
17. Cleanup stale files from `/tmp/*` et al, handled by `bootmisc` plugin
|
17. Cleanup stale files from `/tmp/*` et al, handled by `bootmisc` plugin
|
||||||
@@ -34,18 +38,15 @@ Bootstrap
|
|||||||
24. Call 4th level hooks, `HOOK_SVC_UP`
|
24. Call 4th level hooks, `HOOK_SVC_UP`
|
||||||
25. Call `/etc/rc.local`, if it exists and is an executable shell script
|
25. Call `/etc/rc.local`, if it exists and is an executable shell script
|
||||||
26. Call 5th level (last) hooks, `HOOK_SYSTEM_UP`
|
26. Call 5th level (last) hooks, `HOOK_SYSTEM_UP`
|
||||||
27. Start all configured TTYs, or a fallback shell on `/dev/console`
|
27. Start all configured TTYs
|
||||||
|
|
||||||
In (19) and (22) tasks and services defined in `/etc/finit.conf` and
|
In (19) and (23) tasks and services defined in `/etc/finit.conf` and
|
||||||
`/etc/sysctl.d/*.conf` are started. Remember, all `service` and `task`
|
`/etc/finit.d/*.conf` are started.
|
||||||
stanzas are started in parallel and `run` in sequence, and in the order
|
|
||||||
listed. Hence, to emulate a SysV `/etc/init.d/rcS` one could write a
|
|
||||||
long `finit.conf` with only `run` statements.
|
|
||||||
|
|
||||||
Notice the five hook points that are called at various point in the
|
Notice the seven hook points that are called at various point in the
|
||||||
bootstrap process. This is where plugins can extend the boot in any way
|
bootstrap process. This is where plugins can extend the boot in any
|
||||||
they please. There are other hook points, e.g. `HOOK_MOUNT_ERROR`, for
|
way they please. There are other hook points available, for more on
|
||||||
more on this see [plugins.md](plugins.md).
|
this, see [plugins.md](plugins.md).
|
||||||
|
|
||||||
For instance, at `HOOK_BASEFS_UP` a plugin could read an XML file from a
|
For instance, at `HOOK_BASEFS_UP` a plugin could read an XML file from a
|
||||||
USB stick, convert/copy its contents to the system's `/etc/` directory,
|
USB stick, convert/copy its contents to the system's `/etc/` directory,
|
||||||
|
|||||||
+23
-16
@@ -27,7 +27,7 @@ optional plugins to enable. It depends on two external libraries:
|
|||||||
PKG_CONFIG_LIBDIR=/usr/local/lib/pkgconfig ./configure
|
PKG_CONFIG_LIBDIR=/usr/local/lib/pkgconfig ./configure
|
||||||
|
|
||||||
The configure script checks for all dependencies, including the correct
|
The configure script checks for all dependencies, including the correct
|
||||||
version of the above mentioned libraries. Currently requried versions:
|
version of the above mentioned libraries. Currently required versions:
|
||||||
|
|
||||||
- libite v2.2.0
|
- libite v2.2.0
|
||||||
- libuEv v2.2.0
|
- libuEv v2.2.0
|
||||||
@@ -53,6 +53,10 @@ Below are a few of the main switches to configure:
|
|||||||
built-ins (.o files) and all external libraries, except the C library
|
built-ins (.o files) and all external libraries, except the C library
|
||||||
will be linked statically.
|
will be linked statically.
|
||||||
|
|
||||||
|
* `--enable-kernel-cmdline`: Enable Finit pre-4.1 parsing of init args from
|
||||||
|
`/proc/cmdline`, this is not recommended since Finit may be running as the
|
||||||
|
init for container apps that can see the host's `/proc` filesystem
|
||||||
|
|
||||||
* `--enable-alsa-utils-plugin`: Enable the optional `alsa-utils.so` sound plugin.
|
* `--enable-alsa-utils-plugin`: Enable the optional `alsa-utils.so` sound plugin.
|
||||||
|
|
||||||
* `--enable-dbus-plugin`: Enable the optional D-Bus `dbus.so` plugin.
|
* `--enable-dbus-plugin`: Enable the optional D-Bus `dbus.so` plugin.
|
||||||
@@ -70,16 +74,16 @@ Example
|
|||||||
First, unpack the archive:
|
First, unpack the archive:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ tar xf finit-3.0.tar.xz
|
$ tar xf finit-4.1.tar.gz
|
||||||
$ cd finit-3.0/
|
$ cd finit-4.1/
|
||||||
```
|
```
|
||||||
|
|
||||||
Then configure, build and install:
|
Then configure, build and install:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ ./configure --prefix=/usr --exec-prefix= \
|
$ ./configure --prefix=/usr --exec-prefix= \
|
||||||
--sysconfdir=/etc --localstatedir=/var \
|
--sysconfdir=/etc --localstatedir=/var \
|
||||||
--with-heading="Alpine Linux 3.13" --with-hostname=alpine
|
--with-keventd --with-watchdog
|
||||||
$ make
|
$ make
|
||||||
.
|
.
|
||||||
.
|
.
|
||||||
@@ -87,13 +91,13 @@ $ make
|
|||||||
$ DESTDIR=/tmp/finit make install
|
$ DESTDIR=/tmp/finit make install
|
||||||
```
|
```
|
||||||
|
|
||||||
In this example the [finit-3.0.tar.xz][1] archive is unpacked to the
|
In this example the [finit-4.1.tar.gz][1] archive is unpacked to the
|
||||||
user's home directory, configured, built and installed to a temporary
|
user's home directory, configured, built and installed to a temporary
|
||||||
staging directory. The environment variable `DESTDIR` controls the
|
staging directory. The environment variable `DESTDIR` controls the
|
||||||
destination directory when installing, very useful for building binary
|
destination directory when installing, very useful for building binary
|
||||||
standalone packages.
|
standalone packages.
|
||||||
|
|
||||||
Finit 3.0 and later can detect if it runs on an embedded system, or a
|
Finit 4.1 and later can detect if it runs on an embedded system, or a
|
||||||
system that use BusyBox tools instead of udev & C:o. On such systems
|
system that use BusyBox tools instead of udev & C:o. On such systems
|
||||||
`mdev` instead of `udev` is used. However, remember to also change the
|
`mdev` instead of `udev` is used. However, remember to also change the
|
||||||
Linux config to:
|
Linux config to:
|
||||||
@@ -153,21 +157,24 @@ kernel messages and add `debug` to enable Finit debug messages.
|
|||||||
append="init=/sbin/finit debug"
|
append="init=/sbin/finit debug"
|
||||||
```
|
```
|
||||||
|
|
||||||
To debug startup issues, in particular issues with getty/login, try
|
To debug startup issues, in particular issues with getty/login, add
|
||||||
`configure --enable-fallback-shell`. When no TTYs are detected, and
|
the following to your Finit .conf file:
|
||||||
Finit is configured with this option, Finit will try to start a bare
|
|
||||||
`/bin/sh` on the boot console. Remember, this is only for debugging
|
tty [12345789] notty noclear
|
||||||
and would leave your production system potentially wide open.
|
|
||||||
|
The `notty` option ensures reusing the stdin/stdout set up by the
|
||||||
|
kernel. Remember, this is only for debugging and would leave your
|
||||||
|
production system potentially wide open.
|
||||||
|
|
||||||
There is also a rescue shell available, in case Finit crashes and the
|
There is also a rescue shell available, in case Finit crashes and the
|
||||||
kernel usually reboots: `configure --enable-emergency-shell`. However,
|
kernel usually reboots: `configure --enable-emergency-shell`. However,
|
||||||
the behavior of Finit is severely limited when this is enabled, so use
|
the behavior of Finit is severely limited when this is enabled, so use
|
||||||
it only for debugging start up issues when Finit crashes.
|
it only for debugging start up issues when Finit crashes.
|
||||||
|
|
||||||
**NOTE:** Neither of these two configure options should be enabled on
|
**NOTE:** Neither of these options should be enabled on production
|
||||||
production systems since they can potentially give a user root access.
|
systems since they can potentially give a user root access.
|
||||||
|
|
||||||
|
|
||||||
[1]: ftp://troglobit.com/finit/finit-3.0.tar.xz
|
[1]: ftp://troglobit.com/finit/finit-4.1.tar.gz
|
||||||
[libuEv]: https://github.com/troglobit/libuev
|
[libuEv]: https://github.com/troglobit/libuev
|
||||||
[libite]: https://github.com/troglobit/libite
|
[libite]: https://github.com/troglobit/libite
|
||||||
|
|||||||
+10
-6
@@ -6,6 +6,8 @@ passed on the Linux kernel command line. Not limited to Finit.
|
|||||||
|
|
||||||
The `bool` setting is one of `on, off, true false, 1, 0`.
|
The `bool` setting is one of `on, off, true false, 1, 0`.
|
||||||
|
|
||||||
|
> **NOTE:** remember to use `--` to separate kernel parameters from
|
||||||
|
> parameters to init. E.g., `init=/sbin/finit -- finit.debug rescue`
|
||||||
|
|
||||||
* `debug`: Enable kernel debug. Debug messages are printed to the
|
* `debug`: Enable kernel debug. Debug messages are printed to the
|
||||||
console until Finit starts up.
|
console until Finit starts up.
|
||||||
@@ -30,17 +32,19 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
|
|||||||
* `quiet`: Suppress kernel logging to console, except for warnings and
|
* `quiet`: Suppress kernel logging to console, except for warnings and
|
||||||
errors.
|
errors.
|
||||||
|
|
||||||
* `rescue`: Start Finit rescue mode; no network, no `fsck` of file
|
* `rescue`: Start rescue/maintenance mode. If your system comes with
|
||||||
systems in `/etc/fstab`, no `/etc/rc.local`, no `runparts`. The
|
the bundled `sulogin` program (Finit, or from util-linux/Busybox),
|
||||||
configuration is read from `/lib/finit/rescue.conf`, and can be
|
you will be given a root login to a maintenance shell. However, if
|
||||||
modified by the operator.
|
`sulogin` is missing, the file `/lib/finit/rescue.conf` is read and
|
||||||
|
the system booted in a limited fallback mode. See [config.md][]
|
||||||
|
for more information.
|
||||||
|
|
||||||
* `single`, or `S`: Single user mode, runlevel 1, in Finit. Useful to
|
* `single`, or `S`: Single user mode, runlevel 1, in Finit. Useful to
|
||||||
debug problems with the regular runlevel. All services and TTYs in
|
debug problems with the regular runlevel. All services and TTYs in
|
||||||
`[1]` will be started, so a `tty [1] @console nologin` configuration
|
`[1]` will be started, so a `tty [1] @console nologin` configuration
|
||||||
presents you with a root console without login.
|
presents you with a root console without login.
|
||||||
|
|
||||||
For more on kernel boot paramaters, see the man page [bootparam(7)][].
|
For more on kernel boot parameters, see the man page [bootparam(7)][].
|
||||||
|
|
||||||
|
|
||||||
|
[config.md][]: config.md#rescue-mode
|
||||||
[bootparam(7)]: https://www.man7.org/linux/man-pages/man7/bootparam.7.html
|
[bootparam(7)]: https://www.man7.org/linux/man-pages/man7/bootparam.7.html
|
||||||
|
|||||||
+41
-8
@@ -45,7 +45,31 @@ being created.
|
|||||||
Triggering
|
Triggering
|
||||||
----------
|
----------
|
||||||
|
|
||||||
Conditions can only be triggered by built-in plugins.
|
Conditions are mainly triggered (asserted) by built-in plugins, e.g.,
|
||||||
|
`netlink.so` and `pidfile.so`, see below for built-in conditions. Finit
|
||||||
|
also supports user-defined conditions, sometimes referred to as static
|
||||||
|
or one-shot conditions. They live in the `<usr/...` namespace and are
|
||||||
|
constrained to a flat hierarchy without any sub-directories, unlike the
|
||||||
|
pidfile plugin, for instance.
|
||||||
|
|
||||||
|
User-defined conditions are controlled using the `initctl cond set` and
|
||||||
|
`initctl cond clear` commands:
|
||||||
|
|
||||||
|
initctl cond set foo
|
||||||
|
initctl cond clear foo
|
||||||
|
|
||||||
|
The purpose of user-defined conditions is to be able to start or stop
|
||||||
|
services, or run/task jobs, on external site-dependent stimuli.
|
||||||
|
Example:
|
||||||
|
|
||||||
|
service [2345] <usr/foo> alarm --arg foo -- Foo alarm
|
||||||
|
|
||||||
|
For convenience, prefixing with `usr/` is allowed, but any other slashes
|
||||||
|
or period characters are disallowed. E.g., to trigger the `Foo alarm`,
|
||||||
|
the same as above, can also be achieved like this:
|
||||||
|
|
||||||
|
initctl cond set usr/foo
|
||||||
|
initctl cond clear usr/foo
|
||||||
|
|
||||||
Conditions retain their current state until the next reconfiguration or
|
Conditions retain their current state until the next reconfiguration or
|
||||||
runlevel change. At that point all set conditions transition into the
|
runlevel change. At that point all set conditions transition into the
|
||||||
@@ -57,16 +81,21 @@ unchanged) state of it.
|
|||||||
> **Note:** For `pid/` conditions it is expected that services "touch"
|
> **Note:** For `pid/` conditions it is expected that services "touch"
|
||||||
> or recreate their PID file on `SIGHUP`.
|
> or recreate their PID file on `SIGHUP`.
|
||||||
|
|
||||||
|
Static (one-shot) conditions, like `usr/`, never enter the `flux` state.
|
||||||
|
|
||||||
|
|
||||||
Built-in Conditions
|
Built-in Conditions
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
Finit comes with a `pidfile` and `netlink` plugin. When enabled, the
|
Finit comes with a set of plugins for conditions: `pidfile`, `netlink`,
|
||||||
`pidfile` plugin watches `/var/run/` (recursively) for PID files created
|
`sys`, and `usr`. The `pidfile` plugin (recursively) watches `/run/`
|
||||||
by the monitored services, and sets a corresponding condition in the
|
(recursively) for PID files created by the monitored services, and sets
|
||||||
`pid/` namespace. Similarily, the `netlink` plugin provides basic
|
a corresponding condition in the `pid/` namespace. Similarly, the
|
||||||
conditions for when an interface is brought up/down and when a default
|
`netlink` plugin provides basic conditions for when an interface is
|
||||||
route (gateway) is set, in the `net/` namespace.
|
brought up/down and when a default route (gateway) is set, in the `net/`
|
||||||
|
namespace. The `sys` and `usr` plugins monitor are passive condition
|
||||||
|
monitors where the action is provided by `keventd`, signal handlers,
|
||||||
|
and in the case of `usr`, the end-user via the `initctl` tool
|
||||||
|
|
||||||
With the example listed above, finit does not start the `/sbin/netd`
|
With the example listed above, finit does not start the `/sbin/netd`
|
||||||
daemon until `setupd` and `zebra` has started *and* created their PID
|
daemon until `setupd` and `zebra` has started *and* created their PID
|
||||||
@@ -85,6 +114,10 @@ Built-in conditions:
|
|||||||
- `net/<IFNAME>/exist`
|
- `net/<IFNAME>/exist`
|
||||||
- `net/<IFNAME>/up`
|
- `net/<IFNAME>/up`
|
||||||
- `net/<IFNAME>/running`
|
- `net/<IFNAME>/running`
|
||||||
|
- `sys/pwr/ac`
|
||||||
|
- `sys/pwr/fail`
|
||||||
|
- `sys/key/ctrlaltdel`
|
||||||
|
- `usr/foo`
|
||||||
|
|
||||||
**Note:** `up` means administratively up, the interface flag `IFF_UP`.
|
**Note:** `up` means administratively up, the interface flag `IFF_UP`.
|
||||||
`running` is the `IFF_RUNNING` flag, meaning operatively up. The
|
`running` is the `IFF_RUNNING` flag, meaning operatively up. The
|
||||||
@@ -147,7 +180,7 @@ PID IDENT STATUS CONDITION (+ ON, ~ FLUX, - OFF)
|
|||||||
|
|
||||||
Here we can see that `netd` is allowed to run since both its conditions
|
Here we can see that `netd` is allowed to run since both its conditions
|
||||||
are in the `on` state, as indicated by the `+`-prefix. `udhcpc` however
|
are in the `on` state, as indicated by the `+`-prefix. `udhcpc` however
|
||||||
is not allowed to run since `net/vlan1/exist` condition is not satsifed.
|
is not allowed to run since `net/vlan1/exist` condition is not satisfied.
|
||||||
As indicated by the `-`-prefix.
|
As indicated by the `-`-prefix.
|
||||||
|
|
||||||
To fake interface `vlan1` suddenly appearing, and test what happens to
|
To fake interface `vlan1` suddenly appearing, and test what happens to
|
||||||
|
|||||||
+277
-44
@@ -2,7 +2,9 @@ Configuration
|
|||||||
=============
|
=============
|
||||||
|
|
||||||
* [Introduction](#introduction)
|
* [Introduction](#introduction)
|
||||||
|
* [Service Environment](#service-environment)
|
||||||
* [Service Wrapper Scripts](#service-wrapper-scripts)
|
* [Service Wrapper Scripts](#service-wrapper-scripts)
|
||||||
|
* [Cgroups](#cgroups)
|
||||||
* [Configuration File Syntax](#configuration-file-syntax)
|
* [Configuration File Syntax](#configuration-file-syntax)
|
||||||
* [Hostname](#hostname)
|
* [Hostname](#hostname)
|
||||||
* [Kernel Modules](#kernel-modules)
|
* [Kernel Modules](#kernel-modules)
|
||||||
@@ -19,9 +21,12 @@ Configuration
|
|||||||
* [TTYs and Consoles](#ttys-and-consoles)
|
* [TTYs and Consoles](#ttys-and-consoles)
|
||||||
* [Non-privileged Services](#non-privileged-services)
|
* [Non-privileged Services](#non-privileged-services)
|
||||||
* [Redirecting Output](#redirecting-output)
|
* [Redirecting Output](#redirecting-output)
|
||||||
|
* [Rescue Mode](#rescue-mode)
|
||||||
* [Limitations](#limitations)
|
* [Limitations](#limitations)
|
||||||
* [/etc/finit.conf](#etcfinitconf)
|
* [/etc/finit.conf](#etcfinitconf)
|
||||||
* [/etc/finit.d](#etcfinitd)
|
* [/etc/finit.d](#etcfinitd)
|
||||||
|
* [Watchdog](#watchdog)
|
||||||
|
* [keventd](#keventd)
|
||||||
|
|
||||||
|
|
||||||
Introduction
|
Introduction
|
||||||
@@ -35,16 +40,16 @@ Linux distributions -- each package can provide its own "script" file.
|
|||||||
- `/etc/finit.d/*.conf`: snippets, usually one service per file
|
- `/etc/finit.d/*.conf`: snippets, usually one service per file
|
||||||
|
|
||||||
Not all configuration directives are available in `/etc/finit.d/*.conf`
|
Not all configuration directives are available in `/etc/finit.d/*.conf`
|
||||||
and some directives are only available at bootstrap, runlevel `S`, see
|
and some directives are only available at [bootstrap][], runlevel `S`,
|
||||||
the section [Limitations](#limitations) below for details.
|
see the section [Limitations](#limitations) below for details.
|
||||||
|
|
||||||
To add a new service, simply drop a `.conf` file in `/etc/finit.d` and
|
To add a new service, drop a `.conf` file in `/etc/finit.d` and run
|
||||||
run `initctl reload`. (It is also possible to `SIGHUP` to PID 1, or
|
`initctl reload`. (It is also possible to `SIGHUP` to PID 1, or call
|
||||||
call `finit q`, but that has been deprecated with the `initctl` tool).
|
`finit q`, but that has been deprecated with the `initctl` tool). Finit
|
||||||
Finit monitors all known active `.conf` files, so if you want to force
|
monitors all known active `.conf` files, so if you want to force a
|
||||||
a restart of any service you can simply touch its corresponding `.conf`
|
restart of any service you can touch its corresponding `.conf` file in
|
||||||
file in `/etc/finit.d` and call `initctl reload`. Finit handle any
|
`/etc/finit.d` and call `initctl reload`. Finit handle any and all
|
||||||
and all conditions and dependencies between services automatically.
|
conditions and dependencies between services automatically.
|
||||||
|
|
||||||
It is also possible to drop `.conf` files in `/etc/finit.d/available/`
|
It is also possible to drop `.conf` files in `/etc/finit.d/available/`
|
||||||
and use `initctl enable` to enable a service `.conf` file. This may be
|
and use `initctl enable` to enable a service `.conf` file. This may be
|
||||||
@@ -54,7 +59,7 @@ files for a package and let the user decide when to enable a service.
|
|||||||
On `initctl reload` the following is checked for all services:
|
On `initctl reload` the following is checked for all services:
|
||||||
|
|
||||||
- If a service's `.conf` file has been removed, or its conditions are no
|
- If a service's `.conf` file has been removed, or its conditions are no
|
||||||
longer satisifed, the service is stopped.
|
longer satisfied, the service is stopped.
|
||||||
- If the file is modified, or a service it depends on has been reloaded,
|
- If the file is modified, or a service it depends on has been reloaded,
|
||||||
the service is reloaded (stopped and started).
|
the service is reloaded (stopped and started).
|
||||||
- If a new service is added it is automatically started — respecting
|
- If a new service is added it is automatically started — respecting
|
||||||
@@ -128,6 +133,67 @@ example employs a wrapper script in `/etc/start.d`.
|
|||||||
> instead of sending SIGHUP at restart/reload events.
|
> instead of sending SIGHUP at restart/reload events.
|
||||||
|
|
||||||
|
|
||||||
|
Cgroups
|
||||||
|
-------
|
||||||
|
|
||||||
|
There are three major cgroup configuration directives:
|
||||||
|
|
||||||
|
1. Global top-level group: init, system, user, or a custom group
|
||||||
|
2. Selecting a top-level group for a set of run/task/services
|
||||||
|
3. Per run/task/service limits
|
||||||
|
|
||||||
|
Top-level group configuration.
|
||||||
|
|
||||||
|
# Top-level cgroups and their default settings. All groups mandatory
|
||||||
|
# but more can be added, max 8 groups in total currently. The cgroup
|
||||||
|
# 'root' is also available, reserved for RT processes. Settings are
|
||||||
|
# as-is, only one shorthand 'mem.' exists, other than that it's the
|
||||||
|
# cgroup v2 controller default names.
|
||||||
|
cgroup init cpu.weight:100
|
||||||
|
cgroup user cpu.weight:100
|
||||||
|
cgroup system cpu.weight:9800
|
||||||
|
|
||||||
|
Adding an extra cgroup `maint/` will require you to adjust the weight of
|
||||||
|
the above three. We leave `init/` and `user/` as-is reducing weight of
|
||||||
|
`system/` to 9700.
|
||||||
|
|
||||||
|
cgroup system cpu.weight:9700
|
||||||
|
|
||||||
|
# Example extra cgroup 'maint'
|
||||||
|
cgroup maint cpu.weight:100
|
||||||
|
|
||||||
|
By default, the `system/` cgroup is selected for almost everything. The
|
||||||
|
`init/` cgroup is reserved for PID 1 itself and its closest relatives.
|
||||||
|
The `user/` cgroup is for local TTY logins spawned by getty.
|
||||||
|
|
||||||
|
To select a different top-level cgroup, e.g. `maint/`, one can either
|
||||||
|
define it for a group of run/task/service directives in a `.conf` or per
|
||||||
|
each stanza:
|
||||||
|
|
||||||
|
cgroup.maint
|
||||||
|
service [...] <...> /path/to/foo args -- description
|
||||||
|
service [...] <...> /path/to/bar args -- description
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
service [...] <...> cgroup.maint /path/to/foo args -- description
|
||||||
|
|
||||||
|
The latter form also allows per-stanza limits on the form:
|
||||||
|
|
||||||
|
service [...] <...> cgroup.maint:cpu.max:10000,mem.max:655360 /path/to/foo args -- description
|
||||||
|
|
||||||
|
Notice the comma separation and the `mem.` exception to the rule: every
|
||||||
|
cgroup setting maps directly to cgroup v2 syntax. I.e., `cpu.max` maps
|
||||||
|
to the file `/sys/fs/cgroup/maint/foo/cpu.max`. There is no filtering,
|
||||||
|
except for expanding the shorthand `mem.` to `memory.`, if the file is
|
||||||
|
not available, either the cgroup controller is not available in your
|
||||||
|
Linux kernel, or the name is misspelled.
|
||||||
|
|
||||||
|
> Linux cgroups and details surrounding values are not explained in the
|
||||||
|
> Finit documentation. The Linux admin-guide cover this well:
|
||||||
|
> <https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html>
|
||||||
|
|
||||||
|
|
||||||
Configuration File Syntax
|
Configuration File Syntax
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
@@ -140,7 +206,7 @@ the contents of that file is used.
|
|||||||
|
|
||||||
Deprecated. We recommend using `/etc/hostname` instead.
|
Deprecated. We recommend using `/etc/hostname` instead.
|
||||||
|
|
||||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||||
|
|
||||||
|
|
||||||
### Kernel Modules
|
### Kernel Modules
|
||||||
@@ -158,7 +224,7 @@ BusyBox mdev tool, add to `/etc/mdev.conf`:
|
|||||||
|
|
||||||
$MODALIAS=.* root:root 0660 @modprobe -b "$MODALIAS"
|
$MODALIAS=.* root:root 0660 @modprobe -b "$MODALIAS"
|
||||||
|
|
||||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||||
|
|
||||||
|
|
||||||
### Networking
|
### Networking
|
||||||
@@ -171,7 +237,7 @@ Deprecated. We recommend using dedicated task/run stanzas per runlevel,
|
|||||||
or `/etc/network/interfaces` if you have a system with `ifupdown`, like
|
or `/etc/network/interfaces` if you have a system with `ifupdown`, like
|
||||||
Debian, Ubuntu, Linux Mint, or an embedded BusyBox system.
|
Debian, Ubuntu, Linux Mint, or an embedded BusyBox system.
|
||||||
|
|
||||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||||
|
|
||||||
|
|
||||||
### Resource Limits
|
### Resource Limits
|
||||||
@@ -205,13 +271,13 @@ stanzas can share the same rlimits if they are in the same .conf.
|
|||||||
|
|
||||||
**Syntax:** `runlevel <N>`
|
**Syntax:** `runlevel <N>`
|
||||||
|
|
||||||
Defines the system runlevel to go to after bootstrap (S) has completed.
|
The system runlevel to go to after [bootstrap][] (S) has completed. `N`
|
||||||
N is the runlevel number 0-9, where 6 is reserved for reboot and 0 for
|
is the runlevel number 0-9, where 6 is reserved for reboot and 0 for
|
||||||
halt.
|
halt.
|
||||||
|
|
||||||
Default: 2
|
Default: 2
|
||||||
|
|
||||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||||
|
|
||||||
|
|
||||||
### One-shot Commands (sequence)
|
### One-shot Commands (sequence)
|
||||||
@@ -266,8 +332,11 @@ by declaring the PID file to look for: `pid:!/path/to/pidfile.pid`.
|
|||||||
**Syntax:** `service [LVLS] <COND> /path/to/daemon ARGS -- Optional description`
|
**Syntax:** `service [LVLS] <COND> /path/to/daemon ARGS -- Optional description`
|
||||||
|
|
||||||
Service, or daemon, to be monitored and automatically restarted if it
|
Service, or daemon, to be monitored and automatically restarted if it
|
||||||
exits prematurely. Finit tries to restart services that die 10 times
|
exits prematurely. Finit tries to restart services that die, by
|
||||||
before giving up, then you have to `initctl restart NAME` it manually.
|
default 10 times before giving up and marking them as *crashed*.
|
||||||
|
After which they have to be manually restarted with `initctl restart
|
||||||
|
NAME`. The limits controling this are configurable, see the options
|
||||||
|
below.
|
||||||
|
|
||||||
For daemons that support it, we recommend appending `--foreground`,
|
For daemons that support it, we recommend appending `--foreground`,
|
||||||
`--no-background`, `-n`, `-F`, or similar command line argument to
|
`--no-background`, `-n`, `-F`, or similar command line argument to
|
||||||
@@ -324,6 +393,21 @@ optional `name` argument:
|
|||||||
|
|
||||||
name:<service-name>
|
name:<service-name>
|
||||||
|
|
||||||
|
As mentioned previously, services are automatically restarted, this is
|
||||||
|
configurable with the following options:
|
||||||
|
|
||||||
|
* `restart:NUM` -- number of times Finit tries to restart a crashing
|
||||||
|
service, default: 10. When this limit is reached the service is
|
||||||
|
marked *crashed* and must be restarted manually with `initctl`
|
||||||
|
* `restart_sec:SEC` -- number of seconds before Finit tries to restart
|
||||||
|
a crashing service, default: 2 seconds for the first five retries,
|
||||||
|
then back-off to 5 seconds. The maximum of this configured value
|
||||||
|
and the above (2 and 5) will be used
|
||||||
|
* `norestart` -- dont restart on failures, same as `restart:0`
|
||||||
|
* `oncrash:reboot` -- when all retries have failed, and the service
|
||||||
|
has *crashed*, if this option is set the system is rebooted.
|
||||||
|
Note, future releases may include other `oncrash:` actions
|
||||||
|
|
||||||
When stopping a service (run/task/sysv/service), either manually or
|
When stopping a service (run/task/sysv/service), either manually or
|
||||||
when moving to another runlevel, Finit starts by sending `SIGTERM`, to
|
when moving to another runlevel, Finit starts by sending `SIGTERM`, to
|
||||||
allow the process to shut down gracefully. If the process has not
|
allow the process to shut down gracefully. If the process has not
|
||||||
@@ -333,6 +417,28 @@ process using a different signal, use the option `halt:SIGNAL`, e.g.,
|
|||||||
use the option `kill:SEC`, e.g., `kill:10` to wait 10 seconds before
|
use the option `kill:SEC`, e.g., `kill:10` to wait 10 seconds before
|
||||||
sending `SIGKILL`.
|
sending `SIGKILL`.
|
||||||
|
|
||||||
|
Services support `pre:script` and `post:script` actions as well. These
|
||||||
|
run as the same `@USER:GROUP` as the service itself, with any `env:file`
|
||||||
|
sourced. The scripts must use an absolute path, but are executed from
|
||||||
|
the `$HOME` of the given user. The scripts are not called with any
|
||||||
|
argument (currently), but both get the `SERVICE_IDENT=foo` environment
|
||||||
|
variable set. Here `foo` denotes the identity of the service, which if
|
||||||
|
there are multiple services named `foo`, may be `foo:1`, or any unique
|
||||||
|
identifier specified in the .conf file. The `post:script` is called
|
||||||
|
with an additional set of environment variables:
|
||||||
|
|
||||||
|
- `EXIT_CODE=[exited,signal]`: set to one of `exited` or `signal`
|
||||||
|
- `EXIT_STATUS=[num,SIGNAME]`: set to one of exit status code from
|
||||||
|
the program, if it exited normally, or the signal name (`HUP`,
|
||||||
|
`TERM`, etc.) if it exited due to signal
|
||||||
|
|
||||||
|
The scripts have a default execution time of 3 seconds before they are
|
||||||
|
SIGKILLed, this can be adjusted using the above `kill:SEC` syntax.
|
||||||
|
|
||||||
|
> **Note:** the `pre:script` _must_ be idempotent, because a service
|
||||||
|
> can transition between READY and HALTED states any number
|
||||||
|
> of times before going to RUNNING.
|
||||||
|
|
||||||
|
|
||||||
### Run-parts Scripts
|
### Run-parts Scripts
|
||||||
|
|
||||||
@@ -341,7 +447,7 @@ sending `SIGKILL`.
|
|||||||
Call [run-parts(8)][] on `DIR` to run start scripts. All executable
|
Call [run-parts(8)][] on `DIR` to run start scripts. All executable
|
||||||
files, or scripts, in the directory are called, in alphabetic order.
|
files, or scripts, in the directory are called, in alphabetic order.
|
||||||
The scripts in this directory are executed at the very end of runlevel
|
The scripts in this directory are executed at the very end of runlevel
|
||||||
`S`, bootstrap.
|
`S`, [bootstrap][].
|
||||||
|
|
||||||
It can be beneficial to use `S01name`, `S02othername`, etc. if there
|
It can be beneficial to use `S01name`, `S02othername`, etc. if there
|
||||||
is a dependency order between the scripts. Symlinks to existing
|
is a dependency order between the scripts. Symlinks to existing
|
||||||
@@ -351,7 +457,10 @@ Similar to the `/etc/rc.local` shell script, make sure that all your
|
|||||||
services and programs either terminate or start in the background or
|
services and programs either terminate or start in the background or
|
||||||
you will block Finit.
|
you will block Finit.
|
||||||
|
|
||||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||||
|
|
||||||
|
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
||||||
|
|
||||||
|
|
||||||
### Including Finit Configs
|
### Including Finit Configs
|
||||||
|
|
||||||
@@ -377,24 +486,40 @@ size limit is reached.
|
|||||||
|
|
||||||
### TTYs and Consoles
|
### TTYs and Consoles
|
||||||
|
|
||||||
**Syntax:** `tty [LVLS] <DEV> [BAUD] [noclear] [nowait] [nologin] [TERM]`
|
**Syntax:** `tty [LVLS] <COND> DEV [BAUD] [noclear] [nowait] [nologin] [TERM]`
|
||||||
`tty [LVLS] <CMD> <ARGS> [noclear] [nowait]`
|
`tty [LVLS] <COND> CMD <ARGS> [noclear] [nowait]`
|
||||||
|
`tty [LVLS] <COND> [notty] [rescue]`
|
||||||
|
|
||||||
The first variant of this option uses the built-in getty on the given
|
The first variant of this option uses the built-in getty on the given
|
||||||
TTY device DEV, in the given runlevels. The DEV may be the special
|
TTY device DEV, in the given runlevels. DEV may be the special keyword
|
||||||
keyword `@console`, or `console`, useful on embedded systems.
|
`@console`, which is expanded from `/sys/class/tty/console/active`,
|
||||||
|
useful on embedded systems.
|
||||||
|
|
||||||
The default baud rate is 0, i.e., keep kernel default.
|
The default baud rate is 0, i.e., keep kernel default.
|
||||||
|
|
||||||
|
> The `tty` stanza inherits runlevel, condition (and other feature)
|
||||||
|
> parsing from the `service` stanza. So TTYs can run in one or many
|
||||||
|
> runlevels and depend on any condition supported by Finit. This is
|
||||||
|
> useful e.g. to depend on `<pid/elogind>` before starting a TTY.
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
tty [12345] /dev/ttyAMA0 115200 noclear vt220
|
tty [12345] /dev/ttyAMA0 115200 noclear vt220
|
||||||
|
|
||||||
The second `tty` syntax variant is for using an external getty, like
|
The second `tty` syntax variant is for using an external getty, like
|
||||||
agetty or the BusyBox getty.
|
agetty or the BusyBox getty.
|
||||||
|
|
||||||
By default both variants *clear* the TTY and *wait* for the user to
|
The third variant is for board bringup and the `rescue` boot mode. No
|
||||||
press enter before starting getty.
|
device node is required in this variant, the same output that the kernel
|
||||||
|
uses is reused for stdio. If the `rescue` option is omitted, a shell is
|
||||||
|
started (`nologin`, `noclear`, and `nowait` are implied), if the rescue
|
||||||
|
option is set the bundled `/libexec/finit/sulogin` is started to present
|
||||||
|
a bare-bones root login prompt. If the root (uid:0, gid:0) user does
|
||||||
|
not have a password set, no rescue is possible. For more information,
|
||||||
|
see the [Rescue Mode](#rescue-mode) section.
|
||||||
|
|
||||||
|
By default, the first two syntax variants *clear* the TTY and *wait* for
|
||||||
|
the user to press enter before starting getty.
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
@@ -423,16 +548,23 @@ uses `ttyS0`, `ttyAMA0`, `ttyMXC0`, or anything else. Finit figures
|
|||||||
it out by querying sysfs: `/sys/class/tty/console/active`. The speed
|
it out by querying sysfs: `/sys/class/tty/console/active`. The speed
|
||||||
can be omitted to keep the kernel default.
|
can be omitted to keep the kernel default.
|
||||||
|
|
||||||
|
> Most systems get by fine by just using `console`, which will evaluate
|
||||||
|
> to `/dev/console`. If you have to use `@console` to get any output,
|
||||||
|
> you may have some issue with your kernel config.
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
tty [12345] @console noclear vt220
|
tty [12345] @console noclear vt220
|
||||||
|
|
||||||
On really bare bones systems Finit offers a fallback shell, which
|
On really bare bones systems, or for board bringup, Finit can give you a
|
||||||
should not be enabled on production systems since. This because it
|
shell prompt as soon as [bootstrap][] is done, without opening any
|
||||||
may give a user root access without having to log in. However, for
|
device node:
|
||||||
bringup and system debugging it can come in handy:
|
|
||||||
|
|
||||||
configure --enable-fallback-shell
|
tty [12345789] notty
|
||||||
|
|
||||||
|
This should of course not be enabled on production systems. Because it
|
||||||
|
may give a user root access without having to log in. However, for
|
||||||
|
board bringup and system debugging it can come in handy.
|
||||||
|
|
||||||
One can also use the `service` stanza to start a stand-alone shell:
|
One can also use the `service` stanza to start a stand-alone shell:
|
||||||
|
|
||||||
@@ -442,8 +574,8 @@ One can also use the `service` stanza to start a stand-alone shell:
|
|||||||
### Non-privileged Services
|
### Non-privileged Services
|
||||||
|
|
||||||
Every `run`, `task`, or `service` can also list the privileges the
|
Every `run`, `task`, or `service` can also list the privileges the
|
||||||
`/path/to/cmd` should be executed with. Simply prefix the path with
|
`/path/to/cmd` should be executed with. Prefix the command with
|
||||||
`[@USR[:GRP]]` like this:
|
`@USR[:GRP]`, group is optional, like this:
|
||||||
|
|
||||||
run [2345] @joe:users logger "Hello world"
|
run [2345] @joe:users logger "Hello world"
|
||||||
|
|
||||||
@@ -483,28 +615,129 @@ Log rotation is controlled using the global `log` setting.
|
|||||||
|
|
||||||
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
|
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
|
||||||
|
|
||||||
Worth noting is that conditions is allowed for all these stanzas. For a
|
|
||||||
detailed description, see the [Conditions](conditions.md) document.
|
Rescue Mode
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Finit supports a rescue mode which is activated by the `rescue` option
|
||||||
|
on the kernel command line. See [cmdline docs](cmdline.md) for how to
|
||||||
|
activate it.
|
||||||
|
|
||||||
|
The rescue mode comes in two flavors; *traditional* and *fallback*.
|
||||||
|
|
||||||
|
|
||||||
|
### Traditional
|
||||||
|
|
||||||
|
This is what most users expect. A very early maintenance login prompt,
|
||||||
|
served by the bundled `/libexec/finit/sulogin` program, or the standard
|
||||||
|
`sulogin` from util-linux or BusyBox is searched for in the UNIX default
|
||||||
|
`$PATH`. If a successful login is made, or the user exits (Ctrl-D), the
|
||||||
|
rescue mode is ended and the system boots up normally.
|
||||||
|
|
||||||
|
> **Note:** if the user (UID 0 and GID 0) does not have a password, or
|
||||||
|
> __the account is locked__, the user is presented with a password-less
|
||||||
|
> `"Press enter to enter maintenance mode."`, prompt which opens up a
|
||||||
|
> root shell.
|
||||||
|
|
||||||
|
|
||||||
|
### Fallback
|
||||||
|
|
||||||
|
If no `sulogin` program is found, Finit tries to bring up as much of its
|
||||||
|
own functionality as possible, yet limiting many aspects, meaning; no
|
||||||
|
network, no `fsck` of file systems in `/etc/fstab`, no `/etc/rc.local`,
|
||||||
|
no `runparts`, and most plugins are skipped (except those that provide
|
||||||
|
functionality for the condition subsystem).
|
||||||
|
|
||||||
|
Instead of reading `/etc/finit.conf` et al, system configuration is read
|
||||||
|
from `/lib/finit/rescue.conf`, which can be freely modified by the
|
||||||
|
system administrator.
|
||||||
|
|
||||||
|
The bundled default `rescue.conf` contains nothing more than:
|
||||||
|
|
||||||
|
runlevel 1
|
||||||
|
tty [12345] rescue
|
||||||
|
|
||||||
|
The `tty` has the `rescue` option set, which works similar to the board
|
||||||
|
bring-up tty option `notty`. The major difference being that `sulogin`
|
||||||
|
is started to query for root/admin password. If `sulogin` is not found,
|
||||||
|
`rescue` behaves like `notty` and gives a plain root shell prompt.
|
||||||
|
|
||||||
|
If Finit cannot find `/lib/finit/rescue.conf` it defaults to:
|
||||||
|
|
||||||
|
tty [12345] rescue
|
||||||
|
|
||||||
|
There is no way to exit the *fallback* rescue mode.
|
||||||
|
|
||||||
|
|
||||||
Limitations
|
Limitations
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
As of Finit v4 there are no limitations to where `.conf` settings can be
|
As of Finit v4 there are no limitations to where `.conf` settings can be
|
||||||
placed. Except for the system/global `rlimit`, which can only be set
|
placed. Except for the system/global `rlimit` and `cgroup` top-level
|
||||||
from `/etc/finit.conf`, since it is the first `.conf` file Finit reads.
|
group declarations, which can only be set from `/etc/finit.conf`, since
|
||||||
|
it is the first `.conf` file Finit reads.
|
||||||
|
|
||||||
Originally, `/etc/finit.conf` was the only way to set up a Finit system.
|
Originally, `/etc/finit.conf` was the only way to set up a Finit system.
|
||||||
Today it is mainly used for bootstrap settings like system hostname,
|
Today it is mainly used for bootstrap settings like system hostname,
|
||||||
network bringup and system shutdown. These can now also be set in any
|
early module loading for watchdogd, network bringup and system shutdown.
|
||||||
`.conf` file in `/etc/finit.d`.
|
These can now also be set in any `.conf` file in `/etc/finit.d`.
|
||||||
|
|
||||||
There is, however, nothing preventing you from having all configuration
|
There is, however, nothing preventing you from having all configuration
|
||||||
settings in `/etc/finit.conf`.
|
settings in `/etc/finit.conf`.
|
||||||
|
|
||||||
> **Note:** The `/etc/finit.d` directory was previously the default
|
> **Note:** The `/etc/finit.d` directory was previously the default
|
||||||
> Finit `runparts` directory. Finit no longer has a default
|
> Finit [runparts](#run-parts-scripts) directory. Finit no
|
||||||
> `runparts`, make sure to update your setup, or the finit
|
> longer has a default `runparts`, make sure to update your
|
||||||
> configuration, accordingly.
|
> setup, or the finit configuration, accordingly.
|
||||||
|
|
||||||
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
|
||||||
|
Watchdog
|
||||||
|
--------
|
||||||
|
|
||||||
|
When built `--with-watchdog` a separate service is built and installed
|
||||||
|
in `/libexec/finit/watchdogd`. If this exists at runtime, and the WDT
|
||||||
|
device node exists, Finit will start it and treat it as the elected
|
||||||
|
watchdog service to delegate its reboot to. See [bootstrap][] for
|
||||||
|
details. This delegation is to ensure that the system is rebooted by a
|
||||||
|
hardware watchdog timer -- on many embedded systems this is crucial to
|
||||||
|
ensure all circuits on the board are properly reset for the next boot,
|
||||||
|
in effect ensuring the system works the same after both a power-on and
|
||||||
|
reboot event.
|
||||||
|
|
||||||
|
The delegation is performed at the very last steps of system shutdown,
|
||||||
|
if reboot has been selected and an elected watchdog is known, first a
|
||||||
|
`SIGPWR` is sent to advise watchdogd of the pending reboot. Then, when
|
||||||
|
the necessary steps of preparing the system for shutdown (umount etc.)
|
||||||
|
are completed, Finit sends `SIGTERM` to watchdogd and puts itself in a
|
||||||
|
10 sec timeout loop waiting for the WDT to reset the board. If a reset
|
||||||
|
is not done before the timeout, Finit falls back to`reboot(RB_AUTOBOOT)`
|
||||||
|
which tells the kernel to do the reboot.
|
||||||
|
|
||||||
|
An external watchdog service can also be used. The more advanced cousin
|
||||||
|
[watchdogd](https://github.com/troglobit/watchdogd/) is the recommended
|
||||||
|
option here. It can register itself with Finit using the same IPC as
|
||||||
|
`initctl`. If the bundled watchdogd is running a hand-over takes place,
|
||||||
|
so it's safe to have both services installed on a system. For the
|
||||||
|
hand-over to work it requires that the WDT driver supports the safe exit
|
||||||
|
functionality where `"V"` is written to the device before closing the
|
||||||
|
device descriptor. If the kernel driver has been built without this,
|
||||||
|
the only option is to remove `/libexec/finit/watchdogd` or build without
|
||||||
|
it at configure time.
|
||||||
|
|
||||||
|
[bootstrap]: bootstrap.md
|
||||||
|
|
||||||
|
|
||||||
|
keventd
|
||||||
|
-------
|
||||||
|
|
||||||
|
The kernel event daemon bundled with Finit is a simple uevent monitor
|
||||||
|
for `/sys/class/power_supply`. It provides the `sys/pwr/ac` condition,
|
||||||
|
which can be useful to prevent power hungry services like anacron to run
|
||||||
|
when a laptop is only running on battery, for instance.
|
||||||
|
|
||||||
|
Since keventd is not an integral part of Finit yet it is not enabled by
|
||||||
|
default. Enable it using `./configuure --with-keventd`. The bundled
|
||||||
|
contrib build scripts for Debian, Alpine, and Void have this enabled.
|
||||||
|
|
||||||
|
This daemon is planned to be extended with monitoring of other uevents,
|
||||||
|
patches and ideas are welcome in the issue tracker.
|
||||||
|
|||||||
+17
-9
@@ -12,28 +12,36 @@ have been adopted:
|
|||||||
Same effect as `finit q`, `init q`, or `initctl reload`, reloads all
|
Same effect as `finit q`, `init q`, or `initctl reload`, reloads all
|
||||||
*.conf files in `/etc/finit.d/`
|
*.conf files in `/etc/finit.d/`
|
||||||
|
|
||||||
|
This also restarts the API (initctl) socket, like SysV init and systemd
|
||||||
|
does on USR1 with their FIFO/D-Bus.
|
||||||
|
|
||||||
|
|
||||||
`SIGUSR1`
|
`SIGUSR1`
|
||||||
---------
|
---------
|
||||||
|
|
||||||
Calls shutdown hooks, including `HOOK_SHUTDOWN`, stopping all running
|
Since Finit 4.1 this signal causes Finit to restart its API (initctl)
|
||||||
processes, and unmounts all file systems. Then tells kernel to halt.
|
socket, like SysV init and systemd does on USR1 with their FIFO/D-Bus.
|
||||||
Most people these days want `SIGUSR2` though.
|
|
||||||
|
Finit <= 4.0 performed a system halt (like USR2 without power-off), but
|
||||||
|
this caused compatibility problems with systemd and sysvinit on desktop
|
||||||
|
systems. Hence, since Finit 4.1 it is no longer possible to halt a
|
||||||
|
system with a signal.
|
||||||
|
|
||||||
SysV init and systemd use this to re-open their FIFO/D-Bus.
|
|
||||||
|
|
||||||
`SIGUSR2`
|
`SIGUSR2`
|
||||||
---------
|
---------
|
||||||
|
|
||||||
Like SIGUSR1, but tell kernel to power-off the system, if ACPI or
|
Calls shutdown hooks, including `HOOK_SHUTDOWN`, stopping all running
|
||||||
similar exists to actually do this. If the kernel fails power-off,
|
processes, and unmounts all file systems. Then tells kernel to power
|
||||||
Finit falls back to halt.
|
off the system, if ACPI or similar exists to actually do this. If the
|
||||||
|
kernel fails power-off, Finit falls back to halt.
|
||||||
|
|
||||||
SysV init N/A, systemd dumps its internal state to log.
|
SysV init N/A, systemd dumps its internal state to log.
|
||||||
|
|
||||||
`SIGTERM`
|
`SIGTERM`
|
||||||
---------
|
---------
|
||||||
|
|
||||||
Like `SIGUSR1`, but tell kernel to reboot the system when done.
|
Like `SIGUSR2`, but tell kernel to reboot the system when done.
|
||||||
|
|
||||||
SysV init N/A, systemd rexecutes itself.
|
SysV init N/A, systemd rexecutes itself.
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 138 KiB |
@@ -0,0 +1,2 @@
|
|||||||
|
Makefile
|
||||||
|
Makefile.in
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
dist_man8_MANS = finit.8 initctl.8
|
||||||
|
dist_man5_MANS = finit.conf.5
|
||||||
+178
@@ -0,0 +1,178 @@
|
|||||||
|
.\" Hey, EMACS: -*- nroff -*-
|
||||||
|
.\" First parameter, NAME, should be all caps
|
||||||
|
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||||
|
.\" other parameters are allowed: see man(7), man(1)
|
||||||
|
.Dd June 6, 2021
|
||||||
|
.\" Please adjust this date whenever revising the manpage.
|
||||||
|
.Dt FINIT 8 SMM
|
||||||
|
.Os Linux
|
||||||
|
.Sh NAME
|
||||||
|
.Nm finit
|
||||||
|
.Nd Fast init for Linux systems
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm /sbin/finit
|
||||||
|
.Op finit.status_style=classic
|
||||||
|
.Op finit.show_status=[on,off]
|
||||||
|
.Op finit.debug
|
||||||
|
.Op rescue | recover
|
||||||
|
.Op single | S
|
||||||
|
.Nm /sbin/telinit
|
||||||
|
.Op Fl hv
|
||||||
|
.Op q | Q | 0-9
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
Fast init for Linux systems. Reverse engineered from the EeePC
|
||||||
|
fastinit, 10+ years ago by Claudio Matsuoka, "gaps filled with frog
|
||||||
|
DNA ...". Focus is on small and embedded systems, although Finit is
|
||||||
|
fully usable on server and desktop systems as well.
|
||||||
|
.Pp
|
||||||
|
Features include:
|
||||||
|
.Bl -bullet -width 1n -compact
|
||||||
|
.It
|
||||||
|
Runlevels, defined per service
|
||||||
|
.It
|
||||||
|
One-shot tasks, services (daemons), or SysV init start/stop scripts
|
||||||
|
.It
|
||||||
|
Runparts and
|
||||||
|
.Pa /etc/rc.local
|
||||||
|
support
|
||||||
|
.It
|
||||||
|
Process supervision similar to
|
||||||
|
.Xr systemd 8
|
||||||
|
.It
|
||||||
|
Sourcing environment files
|
||||||
|
.It
|
||||||
|
Conditions for network/process/custom dependencies
|
||||||
|
.It
|
||||||
|
Pre/Post script actions
|
||||||
|
.It
|
||||||
|
Tooling to enable/disable services
|
||||||
|
.It
|
||||||
|
Built-in getty
|
||||||
|
.It
|
||||||
|
Built-in watchdog, with support for hand-over to
|
||||||
|
.Lk https://troglobit.com/watchdogd.html watchdogd
|
||||||
|
.It
|
||||||
|
Built-in support for Debian/BusyBox
|
||||||
|
.Pa /etc/network/interfaces
|
||||||
|
.It
|
||||||
|
Cgroups v2, both configuration and monitoring in `initctl top`
|
||||||
|
.It
|
||||||
|
Plugin support for customization
|
||||||
|
.It
|
||||||
|
Proper rescue mode with bundled `sulogin` for protected maintenance shell
|
||||||
|
.El
|
||||||
|
.Sh BOOTING
|
||||||
|
.Pp
|
||||||
|
Before laucnhing services, the system needs to be bootstrapped. This
|
||||||
|
involves mounting all filesystems (not already mounted by an initramfs)
|
||||||
|
in
|
||||||
|
.Pa /etc/fstab ,
|
||||||
|
ensuring that necessary filesystems like:
|
||||||
|
.Pa /dev ,
|
||||||
|
.Pa /proc ,
|
||||||
|
.Pa /sys ,
|
||||||
|
and
|
||||||
|
.Pa /run
|
||||||
|
are available and can provide the system with the services required.
|
||||||
|
.Pp
|
||||||
|
With that out of the way, a set of plugins take over:
|
||||||
|
.Pp
|
||||||
|
.Bl -tag -width bootmisc.so -offset indent
|
||||||
|
.It Cm bootmisc.so
|
||||||
|
Cleans up stale files from previous boots and default directories are
|
||||||
|
created in tmpfs filesystems
|
||||||
|
.It Cm modprobe.so
|
||||||
|
Probes kernel modules required by the system
|
||||||
|
.It Cm procps.so
|
||||||
|
Set kernel variables from
|
||||||
|
.Pa /etc/sysctl.conf
|
||||||
|
et al
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
When the plugins are done, finit reads
|
||||||
|
.Pa /etc/finit.conf
|
||||||
|
and all other enabled services in
|
||||||
|
.Pa /etc/finit.d/* .
|
||||||
|
First all services, run/tasks in runlevel S (bootStrap) are started,
|
||||||
|
When all run/tasks have completed, Finit changes to the configured
|
||||||
|
runlevel (default 2), Processes are started in parallel, in dependency
|
||||||
|
order according to their conditions.
|
||||||
|
.Pp
|
||||||
|
When all services and run/tasks have been started, the console progress
|
||||||
|
is disabled and all configured getty services are started.
|
||||||
|
.Sh CONDITIONS
|
||||||
|
The condition subysystem in Finit was initially created to track PID
|
||||||
|
files of daemons. If service/task B requires service A to have started,
|
||||||
|
Finit waits for the PID file of service A to be created/updated before
|
||||||
|
it starts service B. Conversely, if service A is stopped and its PID
|
||||||
|
file removed, service B is also stopped.
|
||||||
|
.Pp
|
||||||
|
The following condition families are available today:
|
||||||
|
.Pp
|
||||||
|
.Bl -tag -width pid -offset indent
|
||||||
|
.It Cm net
|
||||||
|
Linux netlink events, e.g. net/route/default, net/eth0/up, and
|
||||||
|
net/et0/running
|
||||||
|
.It Cm pid
|
||||||
|
PID files basd on the service declaration
|
||||||
|
.Cm name:id ,
|
||||||
|
gives the condition pid/name:id
|
||||||
|
.It Cm sys
|
||||||
|
System conditions, e.g. sys/key/ctrlaltdel and sys/pwr/fail
|
||||||
|
.It Cm usr
|
||||||
|
User conditions, assert and deassert using
|
||||||
|
.Cm initctl cond [set|clr] foo
|
||||||
|
.El
|
||||||
|
.Sh SIGNALS
|
||||||
|
PID 1 is the only process that by default blocks all signals. Finit
|
||||||
|
allows for the following signals to control operation, but recommends
|
||||||
|
instead using the
|
||||||
|
.Xr initctl 8
|
||||||
|
tool.
|
||||||
|
.Pp
|
||||||
|
.Bl -tag -width TERM
|
||||||
|
.It HUP
|
||||||
|
Tell
|
||||||
|
.Nm
|
||||||
|
to reload its configuration file(s), same as
|
||||||
|
.Cm initctl reload
|
||||||
|
.It USR1
|
||||||
|
Restart API
|
||||||
|
.Cm ( initctl )
|
||||||
|
socket.
|
||||||
|
.It USR2
|
||||||
|
Tell
|
||||||
|
.Nm
|
||||||
|
to perform a system shutdown, same as
|
||||||
|
.Cm initctl poweroff
|
||||||
|
.It TERM
|
||||||
|
Like SIGUSR2 but performs a reboot, same as
|
||||||
|
.Cm initctl reboot
|
||||||
|
.It INT
|
||||||
|
Sent from kernel when Ctrl-Alt-Del is pressed (on the console), this
|
||||||
|
asserts the sys/key/ctrlaltdel condition, which can be used to start
|
||||||
|
tasks or services
|
||||||
|
.It PWR
|
||||||
|
Sent from a a power daemon on changes to UPS status, Finit asserts
|
||||||
|
the sys/pwr/fail condition
|
||||||
|
.El
|
||||||
|
.Sh FILES
|
||||||
|
.Bl -tag -width /etc/finit.d/available/*.conf -compact
|
||||||
|
.It Pa /etc/finit.conf
|
||||||
|
Main configuration file
|
||||||
|
.It Pa /etc/finit.d/*.conf
|
||||||
|
Static service definitions
|
||||||
|
.It Pa /etc/finit.d/available/*.conf
|
||||||
|
Available services
|
||||||
|
.It Pa /etc/finit.d/enabled/*.conf
|
||||||
|
Symlinks from available
|
||||||
|
.It Pa /run/finit/
|
||||||
|
Runtime files, including the condition subsystem
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr finit.conf 5
|
||||||
|
.Xr initctl 8
|
||||||
|
.Sh AUTHORS
|
||||||
|
.Nm
|
||||||
|
was conceived and reverse engineered by Claudio Matsuoka. Since v1.0,
|
||||||
|
maintained by Joachim Wiberg, with contributions by many others.
|
||||||
@@ -0,0 +1,847 @@
|
|||||||
|
.\" Hey, EMACS: -*- nroff -*-
|
||||||
|
.\" First parameter, NAME, should be all caps
|
||||||
|
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||||
|
.\" other parameters are allowed: see man(7), man(1)
|
||||||
|
.Dd Oct 17, 2020
|
||||||
|
.Dt FINIT.CONF 5 SMM
|
||||||
|
.Os Linux
|
||||||
|
.Sh NAME
|
||||||
|
.Nm finit.conf
|
||||||
|
.Nd Finit configuration file format
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm /etc/finit.conf
|
||||||
|
.Nm /etc/finit.d/*.conf
|
||||||
|
.Nm /etc/finit.d/available/*.conf
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm finit
|
||||||
|
can be configured using only the original
|
||||||
|
.Pa /etc/finit.conf
|
||||||
|
file or in combination with
|
||||||
|
.Pa /etc/finit.d/*.conf .
|
||||||
|
Useful for package-based Linux distributions \(em each package can
|
||||||
|
provide its own "script" file.
|
||||||
|
.Pp
|
||||||
|
.Bl -tag -width /etc/finit.d/*.conf -offset indent -compact
|
||||||
|
.It Pa /etc/finit.conf
|
||||||
|
Main configuration file
|
||||||
|
.It Pa /etc/finit.d/*.conf
|
||||||
|
Snippets, usually one service per file
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
Not all configuration directives are available in
|
||||||
|
.Pa /etc/finit.d/*.conf
|
||||||
|
and some directives are only available at bootstrap, runlevel
|
||||||
|
.Cm S ,
|
||||||
|
see the section
|
||||||
|
.Sx Limitations
|
||||||
|
below for details.
|
||||||
|
.Sh FILES
|
||||||
|
.Bl -tag -width /etc/finit.d/available/*.conf -compact
|
||||||
|
.It Pa /etc/finit.conf
|
||||||
|
Main configuration file
|
||||||
|
.It Pa /etc/finit.d/*.conf
|
||||||
|
Static service definitions
|
||||||
|
.It Pa /etc/finit.d/available/*.conf
|
||||||
|
Available services
|
||||||
|
.It Pa /etc/finit.d/enabled/*.conf
|
||||||
|
Enabled services, symlinks from available
|
||||||
|
.El
|
||||||
|
.Sh FILE FORMAT
|
||||||
|
Lines starting with `#' are ignored. Note that end-of-line comments are
|
||||||
|
NOT supported, comments must be on a line of their own.
|
||||||
|
.Pp
|
||||||
|
A configuration stanza must be on a single (long) line and
|
||||||
|
.Em cannot
|
||||||
|
be broken up in multiple lines by use of a backslash as the last
|
||||||
|
character.
|
||||||
|
.Sh DIRECTIVES
|
||||||
|
This section lists all supported configuration directives. There also exist
|
||||||
|
deprecated directives, see the Markdown documentation for details on these.
|
||||||
|
.Pp
|
||||||
|
.Bl -tag -width 1n
|
||||||
|
.It Cm rlimit Oo hard|soft Oc Ar RESOURCE Aq LIMIT | unlimited
|
||||||
|
.Pp
|
||||||
|
Set the hard or soft limit for a resource, or both if that argument is
|
||||||
|
omitted.
|
||||||
|
.Ar RESOURCE
|
||||||
|
is the lower-case
|
||||||
|
.Cm RLIMIT_
|
||||||
|
string constants from
|
||||||
|
.Xr setrlimit 2 ,
|
||||||
|
without prefix. E.g. to set
|
||||||
|
.Cm RLIMIT_CPU ,
|
||||||
|
use
|
||||||
|
.Cm cpu .
|
||||||
|
.Pp
|
||||||
|
.Ar LIMIT
|
||||||
|
is an integer that depends on the resource being modified, see
|
||||||
|
the man page, or the kernel
|
||||||
|
.Pa /proc/PID/limits
|
||||||
|
file, for details.
|
||||||
|
Finit versions before v3.1 used
|
||||||
|
.Cm infinity
|
||||||
|
for
|
||||||
|
.Cm unlimited ,
|
||||||
|
which is still supported, albeit deprecated.
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
# No process is allowed more than 8MB of address space
|
||||||
|
rlimit hard as 8388608
|
||||||
|
|
||||||
|
# Core dumps may be arbitrarily large
|
||||||
|
rlimit soft core infinity
|
||||||
|
|
||||||
|
# CPU limit for all services, soft & hard = 10 sec
|
||||||
|
rlimit cpu 10
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
.Cm rlimit
|
||||||
|
can be set globally, in
|
||||||
|
.Pa /etc/finit.conf ,
|
||||||
|
or locally per each
|
||||||
|
.Pa /etc/finit.d/*.conf
|
||||||
|
read. I.e., a set of task/run/service stanzas can share the same
|
||||||
|
rlimits if they are in the same .conf.
|
||||||
|
.It Cm runlevel Aq N
|
||||||
|
The system runlevel to go to after bootstrap (S) has completed.
|
||||||
|
.Cm N
|
||||||
|
is the runlevel number 0-9, where 6 is reserved for reboot and 0 for
|
||||||
|
halt. All other can be used by operating system administrators.
|
||||||
|
Default: 2
|
||||||
|
.Pp
|
||||||
|
.Sy Note:
|
||||||
|
only read and executed in runlevel S (bootstrap).
|
||||||
|
.It Cm run Oo LVLS Oc Ao COND Ac Ar /path/to/cmd ARGS Op -- Optional description
|
||||||
|
One-shot command to run in sequence when entering a runlevel, with
|
||||||
|
optional arguments and description.
|
||||||
|
.Pp
|
||||||
|
.Cm run
|
||||||
|
commands are guaranteed to be completed before running the next
|
||||||
|
command. Highly useful if true serialization is needed. Usually
|
||||||
|
only used in the bootstrap (S) runlevel.
|
||||||
|
.Pp
|
||||||
|
.Cm Aq COND
|
||||||
|
conditions are described in
|
||||||
|
.Xr finit 8 ,
|
||||||
|
see also the
|
||||||
|
.Sx Examples
|
||||||
|
section below.
|
||||||
|
.It Cm task Oo LVLS Oc Ao COND Ac Ar /path/to/cmd ARGS Op -- Optional description
|
||||||
|
One-shot like
|
||||||
|
.Cm run ,
|
||||||
|
but starts in parallel with the next command.
|
||||||
|
.Pp
|
||||||
|
Both
|
||||||
|
.Cm run
|
||||||
|
and
|
||||||
|
.Cm task
|
||||||
|
commands are run in a shell, so pipes and redirects can be freely used:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
task [s] echo "foo" | cat >/tmp/bar
|
||||||
|
.Ed
|
||||||
|
.It Cm sysv Oo LVLS Oc Ao COND Ac Ar /path/to/script ARGS Op -- Optional description
|
||||||
|
Similar to
|
||||||
|
.Cm task
|
||||||
|
is the
|
||||||
|
.Cm sysv
|
||||||
|
stanza, which can be used to call SysV style start/stop scripts. The
|
||||||
|
primary intention for this command is to be able to re-use much of
|
||||||
|
existing setup and init scripts in Linux distributions.
|
||||||
|
.Pp
|
||||||
|
When entering an allowed runlevel, Finit calls
|
||||||
|
.Cm init-script start ,
|
||||||
|
when entering a disallowed runlevel, Finit calls
|
||||||
|
.Cm init-script stop ,
|
||||||
|
and if the Finit .conf, where the
|
||||||
|
.Cm sysv
|
||||||
|
stanza is declared, is modified, Finit calls
|
||||||
|
.Cm init-script restart
|
||||||
|
on
|
||||||
|
.Cm initctl reload .
|
||||||
|
Similar to how
|
||||||
|
.Cm service
|
||||||
|
stanzas work.
|
||||||
|
.Pp
|
||||||
|
Forking services started with
|
||||||
|
.Cm sysv
|
||||||
|
scripts can be monitored by Finit by declaring the PID file to look for:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
sysv pid:!/path/to/pidfile.pid /path/to/script ...
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
The leading '!' is to prevent Finit from managing the PID file, which is
|
||||||
|
the default behavior for the
|
||||||
|
.Cm pid:
|
||||||
|
command modifier.
|
||||||
|
.It Cm service Oo LVLS Oc Ao COND Ac Ar /path/to/daemon ARGS Op -- Optional description
|
||||||
|
Service, or daemon, to be monitored and automatically restarted if it
|
||||||
|
exits prematurely. Finit tries to restart services that die, by
|
||||||
|
default 10 times, before giving up and marking them as
|
||||||
|
.Em crashed .
|
||||||
|
After which they have to be restarted manually using
|
||||||
|
.Cm initctl restart NAME .
|
||||||
|
The number of restarts, the delay between each restart, and more is
|
||||||
|
configurable, see the options below.
|
||||||
|
.Pp
|
||||||
|
For daemons that support it, we recommend appending
|
||||||
|
.Cm --foreground , --no-background , -n , -F ,
|
||||||
|
or similar command line argument to prevent them from forking off a
|
||||||
|
sub-process in the background. This is the most reliable way to monitor
|
||||||
|
a service.
|
||||||
|
.Pp
|
||||||
|
However, not all daemons support running in the foreground, or they may
|
||||||
|
start logging to the foreground as well, these are called forking
|
||||||
|
services and are supported using the same syntax as forking
|
||||||
|
.Cm sysv
|
||||||
|
services, using the
|
||||||
|
.Cm pid:!/path/to/pidfile.pid
|
||||||
|
command modifier syntax.
|
||||||
|
.Pp
|
||||||
|
.Sy Example: in the case of
|
||||||
|
.Cm ospfd
|
||||||
|
(below), we omit the
|
||||||
|
.Cm -d
|
||||||
|
flag (daemonize) to prevent it from forking to the background:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
service [2345] <pid/zebra> /sbin/ospfd -- OSPF daemon
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
.Cm [2345]
|
||||||
|
denote the runlevels
|
||||||
|
.Cm ospfd
|
||||||
|
is allowed to run in, they are optional and default to runlevel 2-5 if
|
||||||
|
omitted.
|
||||||
|
.Pp
|
||||||
|
.Cm <pid/zebra>
|
||||||
|
is the condition for starting
|
||||||
|
.Cm ospfd .
|
||||||
|
In this example Finit waits for another service,
|
||||||
|
.Cm zebra ,
|
||||||
|
to have created its PID file in
|
||||||
|
.Pa /var/run/quagga/zebra.pid
|
||||||
|
before starting
|
||||||
|
.Cm ospfd .
|
||||||
|
Finit watches *all* files in
|
||||||
|
.Pa /var/run ,
|
||||||
|
for each file named
|
||||||
|
.Cm *.pid ,
|
||||||
|
.Cm */pid ,
|
||||||
|
Finit opens it and find the matching
|
||||||
|
.Cm NAME:ID
|
||||||
|
using the PID.
|
||||||
|
.Pp
|
||||||
|
Some services do not maintain a PID file and rather than patching each
|
||||||
|
application Finit provides a workaround. A
|
||||||
|
.Cm pid
|
||||||
|
modifier keyword can be set to have Finit automatically create (when
|
||||||
|
starting) and later remove (when stopping) the PID file. The file is
|
||||||
|
created in the
|
||||||
|
.Pa /var/run
|
||||||
|
directory using the
|
||||||
|
.Xr basename 3
|
||||||
|
of the service. The full syntax of the
|
||||||
|
.Cm pid
|
||||||
|
modifier is:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
pid[:[!][/path/to/]filename[.pid]]
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
For example, by adding
|
||||||
|
.Cm pid:/run/foo.pid
|
||||||
|
to the service
|
||||||
|
.Cm /sbin/bar ,
|
||||||
|
that PID file will, not only be created and removed automatically, but
|
||||||
|
also be used by the Finit condition subsystem. So a service/run/task
|
||||||
|
can depend on the
|
||||||
|
.Cm <pid/bar>
|
||||||
|
condition.
|
||||||
|
.Pp
|
||||||
|
If a service should not be automatically started, it can be configured
|
||||||
|
as manual with the
|
||||||
|
.Cm manual:yes
|
||||||
|
command modifier. The service can then be started at any time by
|
||||||
|
running
|
||||||
|
.Cm initctl start NAME
|
||||||
|
.Pp
|
||||||
|
The name of a service, shown by the
|
||||||
|
.Cm initctl
|
||||||
|
tool, defaults to the basename of the service executable. It can be
|
||||||
|
changed with the
|
||||||
|
.Cm name:foo
|
||||||
|
command modifier.
|
||||||
|
.Pp
|
||||||
|
As mentioned previously, services are automatically restarted should
|
||||||
|
they crash, this is configurable with the following options:
|
||||||
|
.Bl -tag -width 1n
|
||||||
|
.It Cm restart:NUM
|
||||||
|
number of times Finit tries to restart a crashing
|
||||||
|
service, default: 10. When this limit is reached the service is
|
||||||
|
marked
|
||||||
|
.Em crashed
|
||||||
|
and must be restarted manually with
|
||||||
|
.Xr initctl 8 .
|
||||||
|
.It Cm restart_sec:SEC
|
||||||
|
number of seconds before Finit tries to restart
|
||||||
|
a crashing service, default: 2 seconds for the first five retries,
|
||||||
|
then back-off to 5 seconds. The maximum of this configured value
|
||||||
|
and the above (2 and 5) will be used
|
||||||
|
.It Cm norestart
|
||||||
|
dont restart on failures, same as
|
||||||
|
.Cm restart:0
|
||||||
|
.It Cm oncrash:reboot
|
||||||
|
when all retries have failed, and the service
|
||||||
|
has
|
||||||
|
.Em crashed ,
|
||||||
|
if this option is set the system is rebooted. Note, future releases
|
||||||
|
may include other
|
||||||
|
.Cm oncrash:
|
||||||
|
actions.
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
When stopping a service (run/task/sysv/service), either manually or when
|
||||||
|
moving to another runlevel, Finit starts by sending SIGTERM, to allow
|
||||||
|
the process to shut down gracefully. If the process has not been
|
||||||
|
collected within 3 seconds, Finit sends SIGKILL. To halt the process
|
||||||
|
using a different signal, use the command modifier
|
||||||
|
.Cm halt:SIGNAL ,
|
||||||
|
e.g.,
|
||||||
|
.Cm halt:SIGPWR .
|
||||||
|
To change the delay between your halt signal and KILL, use the command
|
||||||
|
modifier
|
||||||
|
.Cm kill:SEC ,
|
||||||
|
e.g.,
|
||||||
|
.Cm kill:10
|
||||||
|
to wait 10 seconds before sending SIGKILL.
|
||||||
|
.Pp
|
||||||
|
Services support the
|
||||||
|
.Cm pre:script
|
||||||
|
and
|
||||||
|
.Cm post:script
|
||||||
|
command actions as well. These run as the same
|
||||||
|
.Cm @USER:GROUP
|
||||||
|
as the service itself, with any
|
||||||
|
.Cm env:file
|
||||||
|
sourced. The scripts must use an absolute path, but are executed from
|
||||||
|
the
|
||||||
|
.Cm $HOME
|
||||||
|
of the given user. The scripts are not called with any argument
|
||||||
|
(currently), but both get the
|
||||||
|
.Cm SERVICE_IDENT=foo
|
||||||
|
environment variable set. Here
|
||||||
|
.Cm foo
|
||||||
|
denotes the identity of the service, which if there are multiple
|
||||||
|
services named
|
||||||
|
.Cm foo ,
|
||||||
|
may be
|
||||||
|
.Cm foo:1 ,
|
||||||
|
or any unique identifier specified in the .conf file. The
|
||||||
|
.Cm post:script
|
||||||
|
is called with an additional set of environment variables:
|
||||||
|
.Bl -tag -offset indent -width 1n
|
||||||
|
.It Cm EXIT_CODE=[exited,signal]
|
||||||
|
set to one of
|
||||||
|
.Cm exited
|
||||||
|
or
|
||||||
|
.Cm signal
|
||||||
|
.It Cm EXIT_STATUS=[num,SIGNAME]
|
||||||
|
set to one of exit status code from the program, if it exited normally,
|
||||||
|
or the signal name (HUP, TERM, etc.) if it exited due to signal
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
The scripts have a default execution time of 3 seconds before they are
|
||||||
|
SIGKILLed, this can be adjusted using the
|
||||||
|
.Cm kill:SEC
|
||||||
|
modifier syntax.
|
||||||
|
.Pp
|
||||||
|
.Sy Note:
|
||||||
|
the
|
||||||
|
.Cm pre:script
|
||||||
|
.Em must
|
||||||
|
be idempotent, because a service can transition between READY and HALTED
|
||||||
|
states any number of times before going to RUNNING.
|
||||||
|
.It Cm runparts Aq DIR
|
||||||
|
Call
|
||||||
|
.Xr run-parts 8
|
||||||
|
on
|
||||||
|
.Cm DIR
|
||||||
|
to run start scripts. All executable files, or scripts, in the
|
||||||
|
directory are called, in alphabetic order. The scripts in this
|
||||||
|
directory are executed at the very end of bootstrap, runlevel S.
|
||||||
|
.Pp
|
||||||
|
It can be beneficial to use
|
||||||
|
.Cm S01name ,
|
||||||
|
.Cm S02othername ,
|
||||||
|
etc. if there is a dependency order between the scripts. Symlinks to
|
||||||
|
existing daemons can talso be used, but make sure they daemonize by
|
||||||
|
default.
|
||||||
|
.Pp
|
||||||
|
Similar to the
|
||||||
|
.Pa /etc/rc.local
|
||||||
|
shell script, make sure that all your services and programs either
|
||||||
|
terminate or start in the background or you will block Finit.
|
||||||
|
.Sy Note:
|
||||||
|
only read and executed in runlevel S (bootstrap).
|
||||||
|
.It Cm include Aq CONF
|
||||||
|
Include another configuration file. Absolute path required.
|
||||||
|
.It Cm log size:BYTES count:NUM
|
||||||
|
Log rotation for run/task/services using the
|
||||||
|
.Cm log
|
||||||
|
command modifier with redirection to a log file. Global setting,
|
||||||
|
applies to all services.
|
||||||
|
.Pp
|
||||||
|
The size can be given as bytes, without a specifier, or in `k`, `M`,
|
||||||
|
or `G`, e.g.
|
||||||
|
.Cm size:10M ,
|
||||||
|
or
|
||||||
|
.Cm size:3G .
|
||||||
|
A value of
|
||||||
|
.Cm size:0
|
||||||
|
disables log rotation. The default is
|
||||||
|
.Cm size:200k .
|
||||||
|
.Pp
|
||||||
|
The count value is recommended to be between 1-5, with a default 5.
|
||||||
|
Setting count to 0 means the logfile will be truncated when the MAX
|
||||||
|
size limit is reached.
|
||||||
|
.It Cm tty Oo LVLS Oc Ao COND Ac Ar DEV Oo BAUD Oc Oo noclear Oc Oo nowait Oc Oo nologin Oc Oo TERM Oc
|
||||||
|
This form of the
|
||||||
|
.Cm tty
|
||||||
|
stanza uses the built-in getty on the given TTY device
|
||||||
|
.Ar DEV ,
|
||||||
|
in the given runlevels.
|
||||||
|
.Ar DEV may be the special keyword
|
||||||
|
.Cm @console ,
|
||||||
|
or `console`, which is expanded from `/sys/class/tty/console/active`,
|
||||||
|
useful on embedded systems.
|
||||||
|
.Pp
|
||||||
|
The default baud rate is 0, i.e., keep kernel default.
|
||||||
|
.Pp
|
||||||
|
The `tty` stanza inherits runlevel, condition (and other feature)
|
||||||
|
parsing from the `service` stanza. So TTYs can run in one or many
|
||||||
|
runlevels and depend on any condition supported by Finit. This is
|
||||||
|
useful e.g. to depend on `<pid/elogind>` before starting a TTY.
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
tty [12345] /dev/ttyAMA0 115200 noclear vt220
|
||||||
|
.Ed
|
||||||
|
.It Cm tty Oo LVLS Oc Ao COND Ac Ar CMD DEV Oo noclear Oc Oo nowait Oc
|
||||||
|
This form of the
|
||||||
|
.Cm tty
|
||||||
|
stanza is for using an external getty, like agetty or the BusyBox getty.
|
||||||
|
.Pp
|
||||||
|
By default, these first two syntax variants
|
||||||
|
.Em clear
|
||||||
|
the TTY and
|
||||||
|
.Em wait
|
||||||
|
for the user to press enter before starting getty.
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
tty [12345] /sbin/getty -L 115200 /dev/ttyAMA0 vt100
|
||||||
|
tty [12345] /sbin/agetty -L ttyAMA0 115200 vt100 nowait
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Cm noclear
|
||||||
|
option disables clearing the TTY after each session. Clearing the TTY
|
||||||
|
when a user logs out is usually preferable.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Cm nowait
|
||||||
|
option disables the
|
||||||
|
.Cm Please press Enter to activate console
|
||||||
|
message before actually starting the getty program. On small and
|
||||||
|
embedded systems running multiple unused getty wastes both memory and
|
||||||
|
CPU cycles, so `wait` is the preferred default.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Cm nologin
|
||||||
|
option disables getty and
|
||||||
|
.Pa /bin/login ,
|
||||||
|
and gives the user a root (login) shell on the given TTY
|
||||||
|
.Cm DEV
|
||||||
|
immediately. Needless to say, this is a rather insecure option, but can
|
||||||
|
be very useful for developer builds, during board bringup, or similar.
|
||||||
|
.Pp
|
||||||
|
Notice the ordering, the
|
||||||
|
.Cm TERM
|
||||||
|
option to the built-in getty must be the last argument.
|
||||||
|
.Pp
|
||||||
|
Embedded systems may want to enable automatic `DEV` by supplying the
|
||||||
|
special
|
||||||
|
.Cm @console
|
||||||
|
device. This works regardless weather the system uses
|
||||||
|
.Cm ttyS0 , ttyAMA0 , ttyMXC0 ,
|
||||||
|
or anything else. Finit figures it out by querying sysfs:
|
||||||
|
.Pa /sys/class/tty/console/active .
|
||||||
|
The speed can be omitted to keep the kernel default.
|
||||||
|
.Pp
|
||||||
|
Most systems get by fine by just using `console`, which will evaluate
|
||||||
|
to
|
||||||
|
.Pa /dev/console .
|
||||||
|
If you have to use
|
||||||
|
.Cm @console
|
||||||
|
to get any output, you may have some issue with your kernel config.
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
tty [12345] @console noclear vt220
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
On really bare bones systems, or for board bringup, Finit can give you a
|
||||||
|
shell prompt as soon as bootstrap is done, without opening any device
|
||||||
|
node:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
tty [12345789] notty
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
This should of course not be enabled on production systems. Because it
|
||||||
|
may give a user root access without having to log in. However, for
|
||||||
|
board bringup and system debugging it can come in handy.
|
||||||
|
.Pp
|
||||||
|
One can also use the
|
||||||
|
.Cm service
|
||||||
|
stanza to start a stand-alone shell:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
service [12345] /bin/sh -l
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
.It Cm tty Oo LVLS Oc Ao COND Ac Oo notty Oc Oo rescue Oc
|
||||||
|
The third
|
||||||
|
.Cm tty
|
||||||
|
form is for board bringup and the
|
||||||
|
.Cm rescue
|
||||||
|
boot mode. No device node is required in this variant, the same output
|
||||||
|
that the kernel uses is reused for stdio. If the
|
||||||
|
.Cm rescue
|
||||||
|
option is omitted, a shell is started. The flags
|
||||||
|
.Cm nologin , noclear ,
|
||||||
|
and
|
||||||
|
.Cm nowait
|
||||||
|
are implied. If the
|
||||||
|
.Cm rescue
|
||||||
|
option is set the bundled
|
||||||
|
.Pa /libexec/finit/sulogin
|
||||||
|
is started to present a bare-bones root login prompt. If the root
|
||||||
|
(uid:0, gid:0) user does not have a password set, no rescue is possible.
|
||||||
|
.El
|
||||||
|
.Sh COMMAND MODIFIERS
|
||||||
|
The run/task/tty/service/sysv stanzas take modifiers, or options, to
|
||||||
|
control their behavior. This section lists them with their limitations.
|
||||||
|
All modifiers must be placed between the stanza and its command.
|
||||||
|
.Bl -tag -width 1n
|
||||||
|
.It Cm @user:group
|
||||||
|
Every
|
||||||
|
.Cm run , task ,
|
||||||
|
or
|
||||||
|
.Cm service
|
||||||
|
can also list the privileges the
|
||||||
|
.Cm /path/to/cmd
|
||||||
|
should be executed with. Prefix the command with
|
||||||
|
.Cm @USR[:GRP] ,
|
||||||
|
group is optional, like this:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
run [2345] @joe:users logger "Hello world"
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
For multiple instances of the same command, e.g. a DHCP client or
|
||||||
|
multiple web servers, add
|
||||||
|
.Cm :ID
|
||||||
|
somewhere between the
|
||||||
|
.Cm run , task , service
|
||||||
|
keyword and the command, like this:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
service :80 [2345] httpd -f -h /http -p 80 -- Web server
|
||||||
|
service :8080[2345] httpd -f -h /http -p 8080 -- Old web server
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Without the
|
||||||
|
.Cm :ID
|
||||||
|
to the service the latter will overwrite the former and only the old web
|
||||||
|
server would be started and supervised.
|
||||||
|
.It Cm log:/path/to/file
|
||||||
|
Redirect stdout/stderr of a command to the given log file. See the
|
||||||
|
global log directive, above, for details on log rotation.
|
||||||
|
.It Cm log:console
|
||||||
|
Redirect stdout/stderr of a command to
|
||||||
|
.Pa /dev/console ,
|
||||||
|
only use this for debugging or bringup.
|
||||||
|
.It Cm log:null
|
||||||
|
Redirect stdout/stderr of a command to
|
||||||
|
.Pa /dev/null .
|
||||||
|
.It Cm log:prio:facility.level,tag:ident
|
||||||
|
Redirect stdout/stderr of a command to syslog using the given priority
|
||||||
|
and tag identity.
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
|
||||||
|
.Ed
|
||||||
|
.It Cm log
|
||||||
|
Default
|
||||||
|
.Cm prio
|
||||||
|
is
|
||||||
|
.Cm daemon.info
|
||||||
|
and the default
|
||||||
|
.Cm tag
|
||||||
|
identity is the basename of the service or run/task command.
|
||||||
|
.El
|
||||||
|
.Sh RESCUE MODE
|
||||||
|
Finit supports a rescue mode which is activated by the
|
||||||
|
.Cm rescue
|
||||||
|
option on the kernel command line. The rescue mode comes in two
|
||||||
|
flavors:
|
||||||
|
.Em traditional
|
||||||
|
and
|
||||||
|
.Em fallback .
|
||||||
|
.Ss Traditional
|
||||||
|
This is what most users expect. A very early maintenance login prompt,
|
||||||
|
served by the bundled
|
||||||
|
.Pa /libexec/finit/sulogin
|
||||||
|
program, or the standard
|
||||||
|
.Cm sulogin
|
||||||
|
from util-linux or BusyBox is searched for in the UNIX default
|
||||||
|
.Cm $PATH .
|
||||||
|
If a successful login is made, or the user exits (Ctrl-D), the rescue
|
||||||
|
mode is ended and the system boots up normally.
|
||||||
|
.Pp
|
||||||
|
.Sy Note:
|
||||||
|
if the user (UID 0 and GID 0) does not have a password, or
|
||||||
|
.Em the account is locked ,
|
||||||
|
the user is presented with a password-less prompt:
|
||||||
|
.Cm "Press enter to enter maintenance mode." ,
|
||||||
|
which opens up a root shell.
|
||||||
|
.Ss Fallback
|
||||||
|
If no
|
||||||
|
.Cm sulogin
|
||||||
|
program is found, Finit tries to bring up as much of its own
|
||||||
|
functionality as possible, yet limiting many aspects, meaning; no
|
||||||
|
network, no`fsck` of file systems in
|
||||||
|
.Pa /etc/fstab ,
|
||||||
|
no
|
||||||
|
.Pa /etc/rc.local ,
|
||||||
|
no
|
||||||
|
.Cm runparts ,
|
||||||
|
and most plugins are skipped (except those that provide functionality
|
||||||
|
for the condition subsystem).
|
||||||
|
.Pp
|
||||||
|
Instead of reading
|
||||||
|
.Pa /etc/finit.conf
|
||||||
|
et al, system configuration is read from
|
||||||
|
.Pa /lib/finit/rescue.conf ,
|
||||||
|
which can be freely modified by the system administrator.
|
||||||
|
.Pp
|
||||||
|
The bundled default `rescue.conf` contains nothing more than:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
runlevel 1
|
||||||
|
tty [12345] rescue
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Cm tty
|
||||||
|
has the
|
||||||
|
.Cm rescue
|
||||||
|
option set, which works similar to the board bring-up tty option
|
||||||
|
.Cm notty .
|
||||||
|
The major difference being that `sulogin` is started to query for
|
||||||
|
root/admin password. If
|
||||||
|
.Cm sulogin
|
||||||
|
is not found,
|
||||||
|
.Cm rescue
|
||||||
|
behaves like
|
||||||
|
.Cm notty
|
||||||
|
and gives a plain root shell prompt.
|
||||||
|
.Pp
|
||||||
|
If Finit cannot find
|
||||||
|
.Pa /lib/finit/rescue.conf
|
||||||
|
it defaults to:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
tty [12345] rescue
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
There is no way to exit the
|
||||||
|
.Em fallback
|
||||||
|
rescue mode.
|
||||||
|
.Sh SERVICE ENVIRONMENT
|
||||||
|
Finit supports sourcing environment variables from
|
||||||
|
.Pa /etc/default/* ,
|
||||||
|
or similar. This is a common pattern from SysV init scripts, where the
|
||||||
|
start/stop script is a generic script for the given service,
|
||||||
|
.Cm foo ,
|
||||||
|
and the options for the service are sourced from the file
|
||||||
|
.Pa /etc/default/foo .
|
||||||
|
Like this:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
/etc/default/foo:
|
||||||
|
|
||||||
|
FOO_OPTIONS=--extra-arg="bar" -s -x
|
||||||
|
|
||||||
|
/etc/finit.conf:
|
||||||
|
|
||||||
|
service [2345] env:-/etc/default/foo foo -n $FOO_OPTIONS -- Example foo daemon
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Here the service
|
||||||
|
.Cm foo
|
||||||
|
is started with
|
||||||
|
.Op Fl -n ,
|
||||||
|
to make sure it runs in the foreground, and the with the options found
|
||||||
|
in the environment file. With the
|
||||||
|
.Cm ps
|
||||||
|
command we can see that the process is started with:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
foo -n --extra-arg=bar -s -x
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
.Sy Note:
|
||||||
|
the leading `-` determines if Finit should treat a missing environment
|
||||||
|
file as blocking the start of the service or not. When `-` is used, a
|
||||||
|
missing environment file does
|
||||||
|
.Em not
|
||||||
|
block the start.
|
||||||
|
.Sh SERVICE WRAPPER SCRIPTS
|
||||||
|
If your service requires to run additional commands, executed before the
|
||||||
|
service is actually started, like the systemd `ExecStartPre`, you can
|
||||||
|
use a wrapper shell script to start your service.
|
||||||
|
.Pp
|
||||||
|
The Finit service
|
||||||
|
.Cm .conf
|
||||||
|
file can be put into
|
||||||
|
.Pa /etc/finit.d/available ,
|
||||||
|
so you can control the service using
|
||||||
|
.Cm initctl .
|
||||||
|
Then use the path to the wrapper script in the Finit
|
||||||
|
.Cm .conf
|
||||||
|
service stanza. The following example employs a wrapper script in
|
||||||
|
.Pa /etc/start.d .
|
||||||
|
.Bd -unfilled
|
||||||
|
/etc/finit.d/available/program.conf:
|
||||||
|
|
||||||
|
service [235] <!> /etc/start.d/program -- Example Program
|
||||||
|
|
||||||
|
/etc/start.d/program:
|
||||||
|
|
||||||
|
#!/bin/sh
|
||||||
|
# Prepare the command line options
|
||||||
|
OPTIONS="-u $(cat /etc/username)"
|
||||||
|
|
||||||
|
# Execute the program
|
||||||
|
exec /usr/bin/program $OPTIONS
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
.Sy Note:
|
||||||
|
the example sets
|
||||||
|
.Cm <!>
|
||||||
|
to denote that it doesn't support SIGHUP. That way Finit will
|
||||||
|
stop/start the service instead of sending SIGHUP at restart/reload
|
||||||
|
events.
|
||||||
|
.Sh CGROUPS
|
||||||
|
There are three major cgroup configuration directives:
|
||||||
|
.Pp
|
||||||
|
.Bl -enum -offset indent -compact
|
||||||
|
.It
|
||||||
|
Global top-level group: init, system, user, or a custom group
|
||||||
|
.It
|
||||||
|
Selecting a top-level group for a set of run/task/services
|
||||||
|
.It
|
||||||
|
Per run/task/service limits
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
Top-level group configuration.
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
# Top-level cgroups and their default settings. All groups mandatory
|
||||||
|
# but more can be added, max 8 groups in total currently. The cgroup
|
||||||
|
# 'root' is also available, reserved for RT processes. Settings are
|
||||||
|
# as-is, only one shorthand 'mem.' exists, other than that it's the
|
||||||
|
# cgroup v2 controller default names.
|
||||||
|
cgroup init cpu.weight:100
|
||||||
|
cgroup user cpu.weight:100
|
||||||
|
cgroup system cpu.weight:9800
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Adding an extra cgroup
|
||||||
|
.Cm maint/
|
||||||
|
will require you to adjust the weight of the above three. We leave
|
||||||
|
.Cm init/
|
||||||
|
and
|
||||||
|
.Cm user/
|
||||||
|
as-is reducing weight of
|
||||||
|
.Cm system/
|
||||||
|
to 9700.
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
cgroup system cpu.weight:9700
|
||||||
|
|
||||||
|
# Example extra cgroup 'maint'
|
||||||
|
cgroup maint cpu.weight:100
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
By default, the
|
||||||
|
.Cm system/
|
||||||
|
cgroup is selected for almost everything. The
|
||||||
|
.Cm init/
|
||||||
|
cgroup is reserved for PID 1 itself and its closest relatives. The
|
||||||
|
.Cm user/
|
||||||
|
cgroup is for local TTY logins spawned by getty.
|
||||||
|
.Pp
|
||||||
|
To select a different top-level cgroup, e.g.
|
||||||
|
.Cm maint/ ,
|
||||||
|
one can either define it for a group of run/task/service directives in a
|
||||||
|
.Cm .conf
|
||||||
|
or per each stanza:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
cgroup.maint
|
||||||
|
service [...] <...> /path/to/foo args -- description
|
||||||
|
service [...] <...> /path/to/bar args -- description
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
or
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
service [...] <...> cgroup.maint /path/to/foo args -- description
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
The latter form also allows per-stanza limits on the form:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
service [...] <...> cgroup.maint:cpu.max:10000,mem.max:655360 /path/to/foo args -- description
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Notice the comma separation and the
|
||||||
|
.Cm mem.
|
||||||
|
exception to the rule: every cgroup setting maps directly to cgroup v2
|
||||||
|
syntax. I.e.,
|
||||||
|
.Cm cpu.max
|
||||||
|
maps to the file
|
||||||
|
.Pm /sys/fs/cgroup/maint/foo/cpu.max .
|
||||||
|
There is no filtering, except for expanding the shorthand
|
||||||
|
.Cm mem.
|
||||||
|
to
|
||||||
|
.Cm memory. ,
|
||||||
|
if the file is not available, either the cgroup controller is not
|
||||||
|
available in your Linux kernel, or the name is misspelled.
|
||||||
|
.Pp
|
||||||
|
Linux cgroups and details surrounding values are not explained in the
|
||||||
|
Finit documentation. The Linux admin-guide cover this well:
|
||||||
|
.Lk https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html
|
||||||
|
.Sh LIMITATIONS
|
||||||
|
As of Finit v4 there are no limitations to where
|
||||||
|
.Cm .conf
|
||||||
|
settings can be placed. Except for the system/global
|
||||||
|
.Cm rlimit
|
||||||
|
and
|
||||||
|
.Cm cgroup
|
||||||
|
top-level group declarations, which can only be set from
|
||||||
|
.Pa /etc/finit.conf ,
|
||||||
|
since it is the first
|
||||||
|
.Cm .conf
|
||||||
|
file Finit reads.
|
||||||
|
.Pp
|
||||||
|
Originally,
|
||||||
|
.Pp /etc/finit.conf
|
||||||
|
was the only way to set up a Finit system. Today it is mainly used for
|
||||||
|
bootstrap settings like system hostname, early module loading for
|
||||||
|
watchdogd, network bringup and system shutdown. These can now also be
|
||||||
|
set in any
|
||||||
|
.Cm .conf
|
||||||
|
file in
|
||||||
|
.Pa /etc/finit.d .
|
||||||
|
.Pp
|
||||||
|
There is, however, nothing preventing you from having all configuration
|
||||||
|
settings in
|
||||||
|
.Pa /etc/finit.conf .
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr finit 8 ,
|
||||||
|
.Xr initctl 8
|
||||||
|
.Sh AUTHORS
|
||||||
|
.Nm finit
|
||||||
|
was conceived and reverse engineered by Claudio Matsuoka. Since v1.0,
|
||||||
|
maintained by Joachim Wiberg, with contributions by many others.
|
||||||
+186
@@ -0,0 +1,186 @@
|
|||||||
|
.\" Hey, EMACS: -*- nroff -*-
|
||||||
|
.\" First parameter, NAME, should be all caps
|
||||||
|
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||||
|
.\" other parameters are allowed: see man(7), man(1)
|
||||||
|
.Dd June 6, 2021
|
||||||
|
.\" Please adjust this date whenever revising the manpage.
|
||||||
|
.Dt INITCTL 8 SMM
|
||||||
|
.Os Linux
|
||||||
|
.Sh NAME
|
||||||
|
.Nm initctl
|
||||||
|
.Nd Control tool for Finit
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm /sbin/initctl
|
||||||
|
.Op Fl bcfhlpqtv
|
||||||
|
.Op COMMAND
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
is the official tool for interacting with
|
||||||
|
.Xr finit 8 .
|
||||||
|
It comes with functions for showing status, querying health of services,
|
||||||
|
as well as editing, enabling and disabling services.
|
||||||
|
.Sh OPTIONS
|
||||||
|
This program follows the usual UNIX command line syntax, with long
|
||||||
|
options starting with two dashes (`-'). The options are as follows:
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl b, -batch
|
||||||
|
Batch mode, no screen size probing.
|
||||||
|
.It Fl c, -create
|
||||||
|
Create missing paths (and files) as needed. Useful with the edit command.
|
||||||
|
.It Fl f, -force
|
||||||
|
Ignore missing files and arguments, never prompt.
|
||||||
|
.It Fl h, -help
|
||||||
|
Show built-in help text.
|
||||||
|
.It Fl 1, -once
|
||||||
|
Only one lap in commands like top.
|
||||||
|
.It Fl p, -plain
|
||||||
|
Use plain table headings, no ANSI control characters.
|
||||||
|
.It Fl q, -quiet
|
||||||
|
Silent, only return status of command.
|
||||||
|
.It Fl t, -no-heading
|
||||||
|
Skip table headings.
|
||||||
|
.It Fl v, -verbose
|
||||||
|
Verbose output, where applicable.
|
||||||
|
.El
|
||||||
|
.Sh COMMANDS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Nm Ar debug
|
||||||
|
Toggle finit (daemon) debug to
|
||||||
|
.Pa /dev/console
|
||||||
|
.It Nm Ar help
|
||||||
|
Show built-in help text
|
||||||
|
.It Nm Ar version
|
||||||
|
Show Finit (daemon) version
|
||||||
|
.It Nm Ar ls | list
|
||||||
|
List all
|
||||||
|
.Cm *.conf
|
||||||
|
files in
|
||||||
|
.Pa /etc/finit.d
|
||||||
|
.It Nm Ar create Ar CONF
|
||||||
|
Create
|
||||||
|
.Cm .conf
|
||||||
|
in
|
||||||
|
.Pa /etc/finit.d/available
|
||||||
|
.It Nm Ar delete Ar CONF
|
||||||
|
Delete
|
||||||
|
.Cm .conf
|
||||||
|
in
|
||||||
|
.Pa /etc/finit.d/available
|
||||||
|
.It Nm Ar show Ar CONF
|
||||||
|
Show
|
||||||
|
.Cm .conf
|
||||||
|
in
|
||||||
|
.Pa /etc/finit.d/available
|
||||||
|
.It Nm Ar edit Ar CONF
|
||||||
|
Edit
|
||||||
|
.Cm .conf
|
||||||
|
in
|
||||||
|
.Pa /etc/finit.d/available
|
||||||
|
.It Nm Ar touch Ar CONF
|
||||||
|
Change (mark as modified)
|
||||||
|
.Cm .conf
|
||||||
|
in
|
||||||
|
.Pa /etc/finit.d/available ,
|
||||||
|
like
|
||||||
|
.Ar edit
|
||||||
|
this tells
|
||||||
|
.Nm finit
|
||||||
|
that a configuration has been changed and is a candidate to be restarted
|
||||||
|
(or SIGHUP'ed) on
|
||||||
|
.Cm initctl reload
|
||||||
|
.It Nm Ar enable Ar CONF
|
||||||
|
Enable
|
||||||
|
.Cm .conf
|
||||||
|
in
|
||||||
|
.Pa /etc/finit.d/available ,
|
||||||
|
i.e., add symlink in
|
||||||
|
.Pa /etc/finit.d/enabled
|
||||||
|
.It Nm Ar disable Ar CONF
|
||||||
|
Disable
|
||||||
|
.Cm .conf
|
||||||
|
in
|
||||||
|
.Pa /etc/finit.d/enabled ,
|
||||||
|
i.e., removes symlink
|
||||||
|
.It Nm Ar reload
|
||||||
|
Reload
|
||||||
|
.Cm *.conf in
|
||||||
|
.Pa /etc/finit.d ,
|
||||||
|
i.e., activates changes
|
||||||
|
.It Nm Ar cond set Ar COND
|
||||||
|
Set (assert) user-defined condition,
|
||||||
|
.Cm +usr/COND
|
||||||
|
.It Nm Ar cond clr | clear Ar COND
|
||||||
|
Clear (deassert) user-defined condition,
|
||||||
|
.Cm -usr/COND
|
||||||
|
.It Nm Ar cond status
|
||||||
|
Show condition status, default
|
||||||
|
.Cm cond
|
||||||
|
command.
|
||||||
|
.It Nm Ar cond dump
|
||||||
|
Dump all conditions and their status
|
||||||
|
.It Nm Ar ident Op Cm NAME
|
||||||
|
Display indentities of all run/task/services, or only instances
|
||||||
|
matching
|
||||||
|
.Cm NAME .
|
||||||
|
A partial string, e.g.,
|
||||||
|
.Cm NAM ,
|
||||||
|
will not match anything
|
||||||
|
.It Nm Ar log Op Cm NAME
|
||||||
|
Show ten last Finit, or
|
||||||
|
.Cm NAME ,
|
||||||
|
messages from syslog
|
||||||
|
.It Nm Ar start Cm NAME[:ID]
|
||||||
|
Start service by name, with optional ID, e.g.,
|
||||||
|
.Cm initctl start tty:1
|
||||||
|
.It Nm Ar stop Cm NAME[:ID]
|
||||||
|
Stop/Pause a running service by name
|
||||||
|
.It Nm Ar reload Cm NAME[:ID]
|
||||||
|
Reload service by name (SIGHUP or restart)
|
||||||
|
.It Nm Ar restart Cm NAME[:ID]
|
||||||
|
Restart (stop/start) service by name
|
||||||
|
.It Nm Ar status Cm NAME[:ID]
|
||||||
|
Show service status, by name. If only
|
||||||
|
.Cm NAME
|
||||||
|
is given and multiple instances exits, a summary of all matching
|
||||||
|
instances are shown. Only an exact match displays the detailed status
|
||||||
|
for a particular instance
|
||||||
|
.It Nm Ar status
|
||||||
|
Show status of all services, default command
|
||||||
|
.It Nm Ar cgroup
|
||||||
|
List cgroup config overview
|
||||||
|
.It Nm Ar ps
|
||||||
|
List processes based on cgroups
|
||||||
|
.It Nm Ar top
|
||||||
|
Show top-like listing based on cgroups
|
||||||
|
.It Nm Ar runlevel Op Ar 0-9
|
||||||
|
Show or set runlevel: 0 halt, 6 reboot
|
||||||
|
.It Nm Ar reboot
|
||||||
|
Reboot system, default if
|
||||||
|
.Cm reboot
|
||||||
|
is symlinked to
|
||||||
|
.Nm
|
||||||
|
.It Nm Ar halt
|
||||||
|
Halt system, default if
|
||||||
|
.Cm halt
|
||||||
|
is symlinked to
|
||||||
|
.Nm
|
||||||
|
.It Nm Ar poweroff
|
||||||
|
Power-off system, default if
|
||||||
|
.Cm poweroff
|
||||||
|
is symlinked to
|
||||||
|
.Nm
|
||||||
|
.It Nm Ar suspend
|
||||||
|
Suspend system, default if
|
||||||
|
.Cm suspend
|
||||||
|
is symlinked to
|
||||||
|
.Nm
|
||||||
|
.It Nm Ar utmp show
|
||||||
|
Raw dump of UTMP/WTMP db
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr finit.conf 5
|
||||||
|
.Xr finit 8
|
||||||
|
.Sh AUTHORS
|
||||||
|
.Nm finit
|
||||||
|
was conceived and reverse engineered by Claudio Matsuoka. Since v1.0,
|
||||||
|
maintained by Joachim Wiberg, with contributions by many others.
|
||||||
+22
-2
@@ -7,7 +7,7 @@ AM_CPPFLAGS += $(lite_CFLAGS)
|
|||||||
|
|
||||||
if STATIC
|
if STATIC
|
||||||
noinst_LTLIBRARIES = libplug.la
|
noinst_LTLIBRARIES = libplug.la
|
||||||
libplug_la_SOURCES = bootmisc.c modprobe.c rtc.c pidfile.c procps.c tty.c urandom.c
|
libplug_la_SOURCES = bootmisc.c modprobe.c pidfile.c procps.c sys.c tty.c usr.c
|
||||||
|
|
||||||
if BUILD_ALSA_UTILS_PLUGIN
|
if BUILD_ALSA_UTILS_PLUGIN
|
||||||
libplug_la_SOURCES += alsa-utils.c
|
libplug_la_SOURCES += alsa-utils.c
|
||||||
@@ -33,8 +33,20 @@ if BUILD_RESOLVCONF_PLUGIN
|
|||||||
libplug_la_SOURCES += resolvconf.c
|
libplug_la_SOURCES += resolvconf.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if BUILD_RTC_PLUGIN
|
||||||
|
libplug_la_SOURCES += rtc.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
if BUILD_URANDOM_PLUGIN
|
||||||
|
libplug_la_SOURCES += urandom.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
if BUILD_X11_COMMON_PLUGIN
|
||||||
|
libplug_la_SOURCES += x11-common.c
|
||||||
|
endif
|
||||||
|
|
||||||
else
|
else
|
||||||
pkglib_LTLIBRARIES = bootmisc.la modprobe.la rtc.la pidfile.la procps.la tty.la urandom.la
|
pkglib_LTLIBRARIES = bootmisc.la modprobe.la pidfile.la procps.la sys.la tty.la usr.la
|
||||||
|
|
||||||
if BUILD_ALSA_UTILS_PLUGIN
|
if BUILD_ALSA_UTILS_PLUGIN
|
||||||
pkglib_LTLIBRARIES += alsa-utils.la
|
pkglib_LTLIBRARIES += alsa-utils.la
|
||||||
@@ -60,6 +72,14 @@ if BUILD_RESOLVCONF_PLUGIN
|
|||||||
pkglib_LTLIBRARIES += resolvconf.la
|
pkglib_LTLIBRARIES += resolvconf.la
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if BUILD_RTC_PLUGIN
|
||||||
|
pkglib_LTLIBRARIES += rtc.la
|
||||||
|
endif
|
||||||
|
|
||||||
|
if BUILD_URANDOM_PLUGIN
|
||||||
|
pkglib_LTLIBRARIES += urandom.la
|
||||||
|
endif
|
||||||
|
|
||||||
if BUILD_X11_COMMON_PLUGIN
|
if BUILD_X11_COMMON_PLUGIN
|
||||||
pkglib_LTLIBRARIES += x11-common.la
|
pkglib_LTLIBRARIES += x11-common.la
|
||||||
endif
|
endif
|
||||||
|
|||||||
+16
-1
@@ -21,7 +21,12 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
@@ -30,6 +35,11 @@
|
|||||||
|
|
||||||
static void save(void *arg)
|
static void save(void *arg)
|
||||||
{
|
{
|
||||||
|
if (rescue) {
|
||||||
|
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (whichp(ALSACTL)) {
|
if (whichp(ALSACTL)) {
|
||||||
_d("Saving sound settings ...");
|
_d("Saving sound settings ...");
|
||||||
run_interactive(ALSACTL " -g store", "Saving sound settings");
|
run_interactive(ALSACTL " -g store", "Saving sound settings");
|
||||||
@@ -38,6 +48,11 @@ static void save(void *arg)
|
|||||||
|
|
||||||
static void restore(void *arg)
|
static void restore(void *arg)
|
||||||
{
|
{
|
||||||
|
if (rescue) {
|
||||||
|
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (whichp(ALSACTL)) {
|
if (whichp(ALSACTL)) {
|
||||||
_d("Restoring sound settings ...");
|
_d("Restoring sound settings ...");
|
||||||
run_interactive(ALSACTL " -g restore", "Restoring sound settings");
|
run_interactive(ALSACTL " -g restore", "Restoring sound settings");
|
||||||
|
|||||||
+56
-47
@@ -24,7 +24,11 @@
|
|||||||
#include <ftw.h>
|
#include <ftw.h>
|
||||||
#include <mntent.h>
|
#include <mntent.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
@@ -65,7 +69,7 @@ static int is_tmpfs(char *path)
|
|||||||
return tmpfs;
|
return tmpfs;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_clean(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftw)
|
static int bootclean(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftw)
|
||||||
{
|
{
|
||||||
if (ftw->level == 0)
|
if (ftw->level == 0)
|
||||||
return 1;
|
return 1;
|
||||||
@@ -76,8 +80,14 @@ static int do_clean(const char *fpath, const struct stat *sb, int tflag, struct
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We can safely skip tmpfs, nothing to clean from previous boot there */
|
/*
|
||||||
static void bootclean(void)
|
* Cleanup stale files from previous boot, if any still linger on.
|
||||||
|
* Some systems, e.g. Alpine Linux, still have a persistent /run and
|
||||||
|
* /tmp, i.e. not tmpfs.
|
||||||
|
*
|
||||||
|
* We can safely skip tmpfs, nothing to clean there.
|
||||||
|
*/
|
||||||
|
static void clean(void *arg)
|
||||||
{
|
{
|
||||||
char *dir[] = {
|
char *dir[] = {
|
||||||
"/tmp/",
|
"/tmp/",
|
||||||
@@ -90,22 +100,26 @@ static void bootclean(void)
|
|||||||
if (is_tmpfs(dir[i]))
|
if (is_tmpfs(dir[i]))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
nftw(dir[i], do_clean, 20, FTW_DEPTH);
|
nftw(dir[i], bootclean, 20, FTW_DEPTH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ln(const char *target, const char *linkpath, int ignerr)
|
||||||
|
{
|
||||||
|
if (symlink(target, linkpath) && !ignerr)
|
||||||
|
_pe("Failed creating %s -> %s symlink", target, linkpath);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup standard FHS 2.3 structure in /var, and write runlevel to UTMP
|
* Setup standard FHS 2.3 structure in /var, and write runlevel to UTMP
|
||||||
*/
|
*/
|
||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
{
|
{
|
||||||
int uid, gid;
|
mode_t prev;
|
||||||
|
|
||||||
/* Cleanup stale files, if any still linger on. */
|
prev = umask(0);
|
||||||
bootclean();
|
|
||||||
|
|
||||||
_d("Setting up FHS structure in /var ...");
|
_d("Setting up FHS structure in /var ...");
|
||||||
umask(0);
|
|
||||||
makedir("/var/cache", 0755);
|
makedir("/var/cache", 0755);
|
||||||
makedir("/var/db", 0755); /* _PATH_VARDB on some systems */
|
makedir("/var/db", 0755); /* _PATH_VARDB on some systems */
|
||||||
makedir("/var/games", 0755);
|
makedir("/var/games", 0755);
|
||||||
@@ -115,15 +129,16 @@ static void setup(void *arg)
|
|||||||
makedir("/var/lib/urandom",0755);
|
makedir("/var/lib/urandom",0755);
|
||||||
if (fisdir("/run")) {
|
if (fisdir("/run")) {
|
||||||
_d("System with new /run tmpfs ...");
|
_d("System with new /run tmpfs ...");
|
||||||
makedir("/run/lock", 1777);
|
if (!fisdir("/run/lock"))
|
||||||
symlink("/run/lock", "/var/lock");
|
makedir("/run/lock", 1777);
|
||||||
symlink("/dev/shm", "/run/shm");
|
ln("/run/lock", "/var/lock", 0);
|
||||||
|
ln("/dev/shm", "/run/shm", 0);
|
||||||
|
|
||||||
/* compat only, should really be set up by OS/dist */
|
/* compat only, should really be set up by OS/dist */
|
||||||
symlink("/run", "/var/run");
|
ln("/run", "/var/run", 1);
|
||||||
} else {
|
} else {
|
||||||
makedir("/var/lock", 1777);
|
makedir("/var/lock", 1777);
|
||||||
makedir("/var/run", 0755);
|
makedir("/var/run", 0755);
|
||||||
}
|
}
|
||||||
makedir("/var/log", 0755);
|
makedir("/var/log", 0755);
|
||||||
makedir("/var/mail", 0755);
|
makedir("/var/mail", 0755);
|
||||||
@@ -133,19 +148,21 @@ static void setup(void *arg)
|
|||||||
makedir("/var/tmp", 0755);
|
makedir("/var/tmp", 0755);
|
||||||
makedir("/var/empty", 0755);
|
makedir("/var/empty", 0755);
|
||||||
|
|
||||||
/*
|
|
||||||
* If /etc/group or "utmp" group is missing,
|
|
||||||
* default to "root"/"wheel" group
|
|
||||||
*/
|
|
||||||
_d("Setting up necessary UTMP files ...");
|
|
||||||
gid = getgroup("utmp");
|
|
||||||
if (gid < 0)
|
|
||||||
gid = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* UTMP actually needs multiple db files
|
* UTMP actually needs multiple db files
|
||||||
*/
|
*/
|
||||||
if (has_utmp()) {
|
if (has_utmp()) {
|
||||||
|
int gid;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If /etc/group or "utmp" group is missing, default to
|
||||||
|
* "root", or "wheel", group.
|
||||||
|
*/
|
||||||
|
_d("Setting up necessary UTMP files ...");
|
||||||
|
gid = getgroup("utmp");
|
||||||
|
if (gid < 0)
|
||||||
|
gid = 0;
|
||||||
|
|
||||||
create("/var/run/utmp", 0644, 0, gid); /* Currently logged in */
|
create("/var/run/utmp", 0644, 0, gid); /* Currently logged in */
|
||||||
create("/var/log/wtmp", 0644, 0, gid); /* Login history */
|
create("/var/log/wtmp", 0644, 0, gid); /* Login history */
|
||||||
create("/var/log/btmp", 0600, 0, gid); /* Failed logins */
|
create("/var/log/btmp", 0600, 0, gid); /* Failed logins */
|
||||||
@@ -165,39 +182,31 @@ static void setup(void *arg)
|
|||||||
makedir("/var/run/network",0755); /* Needed by Debian/Ubuntu ifupdown */
|
makedir("/var/run/network",0755); /* Needed by Debian/Ubuntu ifupdown */
|
||||||
makedir("/var/run/lldpd", 0755); /* Needed by lldpd */
|
makedir("/var/run/lldpd", 0755); /* Needed by lldpd */
|
||||||
makedir("/var/run/pluto", 0755); /* Needed by Openswan */
|
makedir("/var/run/pluto", 0755); /* Needed by Openswan */
|
||||||
makedir("/var/run/quagga", 0755); /* Needed by Quagga */
|
mksubsys("/var/run/quagga", 0755, "quagga", "quagga");
|
||||||
makedir("/var/log/quagga", 0755); /* Needed by Quagga */
|
mksubsys("/var/log/quagga", 0755, "quagga", "quagga");
|
||||||
makedir("/var/run/frr", 0755); /* Needed by FRR */
|
mksubsys("/var/run/frr", 0755, "frr", "frr");
|
||||||
makedir("/var/log/frr", 0755); /* Needed by FRR */
|
mksubsys("/var/log/frr", 0755, "frr", "frr");
|
||||||
makedir("/var/run/sshd", 01755); /* OpenSSH */
|
makedir("/var/run/sshd", 01755); /* OpenSSH */
|
||||||
|
|
||||||
gid = getgroup("tty");
|
|
||||||
if (gid < 0)
|
|
||||||
gid = 0;
|
|
||||||
makefifo("/dev/xconsole", 0640); /* sysklogd */
|
|
||||||
chown("/dev/xconsole", 0, gid);
|
|
||||||
|
|
||||||
if (!fexist("/etc/mtab"))
|
if (!fexist("/etc/mtab"))
|
||||||
symlink("../proc/self/mounts", "/etc/mtab");
|
ln("../proc/self/mounts", "/etc/mtab", 1);
|
||||||
|
|
||||||
/* Void Linux has a uuidd that runs as uuid:uuid and needs /run/uuid */
|
/* Void Linux has a uuidd that runs as uuid:uuid and needs /run/uuid */
|
||||||
uid = getuser("uuidd", NULL);
|
mksubsys("/var/run/uuidd", 0755, "uuidd", "uuidd");
|
||||||
if (uid >= 0) {
|
|
||||||
gid = getgroup("uuidd");
|
|
||||||
if (gid < 0)
|
|
||||||
gid = 0;
|
|
||||||
makedir("/var/run/uuidd", 0755);
|
|
||||||
chown("/var/run/uuidd", uid, gid);
|
|
||||||
}
|
|
||||||
|
|
||||||
umask(022);
|
/* Debian has /run/sudo, ensure correct perms and SELinux label */
|
||||||
|
mksubsys("/var/run/sudo", 0711, "root", "root");
|
||||||
|
mksubsys("/var/run/sudo/ts", 0700, "root", "root");
|
||||||
|
if (whichp("restorecon"))
|
||||||
|
run("restorecon /var/run/sudo /var/run/sudo/ts");
|
||||||
|
|
||||||
|
umask(prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
.name = __FILE__,
|
.name = __FILE__,
|
||||||
.hook[HOOK_BASEFS_UP] = {
|
.hook[HOOK_MOUNT_POST] = { .cb = clean },
|
||||||
.cb = setup
|
.hook[HOOK_BASEFS_UP] = { .cb = setup },
|
||||||
},
|
|
||||||
.depends = { "pidfile" },
|
.depends = { "pidfile" },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+29
-12
@@ -22,7 +22,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@@ -32,13 +36,27 @@
|
|||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
|
||||||
#define DAEMON "dbus-daemon"
|
#define DAEMON "dbus-daemon"
|
||||||
#define ARGS "--nofork --system"
|
#define ARGS "--nofork --system --syslog-only"
|
||||||
#define DESC "D-Bus message bus daemon"
|
#define DESC "D-Bus message bus daemon"
|
||||||
|
|
||||||
|
#ifndef DAEMONUSER
|
||||||
|
#define DAEMONUSER "messagebus"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DAEMONPIDFILE
|
||||||
|
#define DAEMONPIDFILE "/var/run/dbus/pid"
|
||||||
|
#endif
|
||||||
|
|
||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
{
|
{
|
||||||
char *cmd;
|
|
||||||
char line[256];
|
char line[256];
|
||||||
|
mode_t prev;
|
||||||
|
char *cmd;
|
||||||
|
|
||||||
|
if (rescue) {
|
||||||
|
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
cmd = which(DAEMON);
|
cmd = which(DAEMON);
|
||||||
if (!cmd) {
|
if (!cmd) {
|
||||||
@@ -46,29 +64,28 @@ static void setup(void *arg)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
umask(0);
|
prev =umask(0);
|
||||||
|
|
||||||
makedir("/var/run/dbus", 0755);
|
mksubsys("/var/run/dbus", 0755, DAEMONUSER, DAEMONUSER);
|
||||||
makedir("/var/lock/subsys", 0755);
|
|
||||||
makedir("/var/lock/subsys/messagebus", 0755);
|
|
||||||
if (whichp("dbus-uuidgen"))
|
if (whichp("dbus-uuidgen"))
|
||||||
run("dbus-uuidgen --ensure");
|
run_interactive("dbus-uuidgen --ensure", "Creating machine UUID for D-Bus");
|
||||||
|
|
||||||
/* Clean up from any previous pre-bootstrap run */
|
/* Clean up from any previous pre-bootstrap run */
|
||||||
erase("/var/run/dbus/pid");
|
remove(DAEMONPIDFILE);
|
||||||
|
|
||||||
/* Register service with Finit */
|
/* Register service with Finit */
|
||||||
snprintf(line, sizeof(line), "[S12345] pid:!/run/dbus/pid log:prio:daemon.info,tag:dbus %s %s -- %s", cmd, ARGS, DESC);
|
snprintf(line, sizeof(line), "[S12345789] cgroup.system pid:!%s @%s:%s %s %s -- %s",
|
||||||
|
DAEMONPIDFILE, DAEMONUSER, DAEMONUSER, cmd, ARGS, DESC);
|
||||||
if (service_register(SVC_TYPE_SERVICE, line, global_rlimit, NULL))
|
if (service_register(SVC_TYPE_SERVICE, line, global_rlimit, NULL))
|
||||||
_pe("Failed registering %s", DAEMON);
|
_pe("Failed registering %s", DAEMON);
|
||||||
free(cmd);
|
free(cmd);
|
||||||
|
|
||||||
umask(022);
|
umask(prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
.name = __FILE__,
|
.name = __FILE__,
|
||||||
.hook[HOOK_NETWORK_UP] = {
|
.hook[HOOK_BASEFS_UP] = {
|
||||||
.cb = setup
|
.cb = setup
|
||||||
},
|
},
|
||||||
.depends = { "bootmisc", },
|
.depends = { "bootmisc", },
|
||||||
|
|||||||
+9
-3
@@ -34,6 +34,11 @@ static void setup(void *arg)
|
|||||||
char cmd[256];
|
char cmd[256];
|
||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
|
if (rescue) {
|
||||||
|
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Populate /dev and prepare for runtime events from kernel.
|
* Populate /dev and prepare for runtime events from kernel.
|
||||||
* Prefer udev if mdev is also available on the system.
|
* Prefer udev if mdev is also available on the system.
|
||||||
@@ -43,17 +48,17 @@ static void setup(void *arg)
|
|||||||
path = which("/lib/systemd/systemd-udevd");
|
path = which("/lib/systemd/systemd-udevd");
|
||||||
if (path) {
|
if (path) {
|
||||||
/* Register udevd as a monitored service */
|
/* Register udevd as a monitored service */
|
||||||
snprintf(cmd, sizeof(cmd), "[S12345789] pid:udevd name:udevd log %s "
|
snprintf(cmd, sizeof(cmd), "[S12345789] cgroup.system pid:udevd name:udevd log %s "
|
||||||
"-- Device event managing daemon", path);
|
"-- Device event managing daemon", path);
|
||||||
if (service_register(SVC_TYPE_SERVICE, cmd, global_rlimit, NULL)) {
|
if (service_register(SVC_TYPE_SERVICE, cmd, global_rlimit, NULL)) {
|
||||||
_pe("Failed registering %s", path);
|
_pe("Failed registering %s", path);
|
||||||
} else {
|
} else {
|
||||||
snprintf(cmd, sizeof(cmd), ":1 [S] <pid/udevd> log "
|
snprintf(cmd, sizeof(cmd), "cgroup.init :1 [S] <pid/udevd> log "
|
||||||
"udevadm trigger -c add -t devices "
|
"udevadm trigger -c add -t devices "
|
||||||
"-- Requesting device events");
|
"-- Requesting device events");
|
||||||
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
||||||
|
|
||||||
snprintf(cmd, sizeof(cmd), ":2 [S] <pid/udevd> log "
|
snprintf(cmd, sizeof(cmd), "cgroup.init :2 [S] <pid/udevd> log "
|
||||||
"udevadm trigger -c add -t subsystems "
|
"udevadm trigger -c add -t subsystems "
|
||||||
"-- Requesting subsystem events");
|
"-- Requesting subsystem events");
|
||||||
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
||||||
@@ -90,6 +95,7 @@ static plugin_t plugin = {
|
|||||||
.hook[HOOK_BASEFS_UP] = {
|
.hook[HOOK_BASEFS_UP] = {
|
||||||
.cb = setup
|
.cb = setup
|
||||||
},
|
},
|
||||||
|
.depends = { "bootmisc" },
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
|
|||||||
+6
-2
@@ -40,11 +40,15 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/time.h> /* gettimeofday() */
|
#include <sys/time.h> /* gettimeofday() */
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "util.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
|
||||||
struct module {
|
struct module {
|
||||||
|
|||||||
+25
-16
@@ -21,10 +21,14 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <lite/lite.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
@@ -36,43 +40,48 @@
|
|||||||
#define MODULES_LOAD_PATH "/etc/modules-load.d"
|
#define MODULES_LOAD_PATH "/etc/modules-load.d"
|
||||||
#endif
|
#endif
|
||||||
#define SERVICE_LINE \
|
#define SERVICE_LINE \
|
||||||
":%d name:modprobe.%s [2345] /sbin/modprobe %s %s -- Kernel module: %s"
|
"cgroup.init :%d name:modprobe.%s [2345] /sbin/modprobe %s %s -- Kernel module: %s"
|
||||||
|
|
||||||
static void load(void *arg)
|
static void load(void *arg)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
struct dirent *d;
|
||||||
DIR *dirp;
|
|
||||||
struct dirent *direntp;
|
|
||||||
char line[256];
|
char line[256];
|
||||||
int index = 1;
|
int index = 1;
|
||||||
|
FILE *fp;
|
||||||
|
DIR *dir;
|
||||||
|
|
||||||
_d("Scanning " MODULES_LOAD_PATH " for config files ...");
|
_d("Scanning " MODULES_LOAD_PATH " for config files ...");
|
||||||
|
|
||||||
dirp = opendir(MODULES_LOAD_PATH);
|
dir = opendir(MODULES_LOAD_PATH);
|
||||||
if (!dirp) return;
|
if (!dir)
|
||||||
|
return;
|
||||||
|
|
||||||
while ((direntp = readdir(dirp)))
|
while ((d = readdir(dir))) {
|
||||||
{
|
|
||||||
char module_path[PATH_MAX];
|
char module_path[PATH_MAX];
|
||||||
|
|
||||||
strlcpy(module_path, MODULES_LOAD_PATH "/", sizeof(module_path));
|
strlcpy(module_path, MODULES_LOAD_PATH "/", sizeof(module_path));
|
||||||
strlcat(module_path, direntp->d_name, sizeof(module_path));
|
strlcat(module_path, d->d_name, sizeof(module_path));
|
||||||
|
|
||||||
fp = fopen(module_path, "r");
|
fp = fopen(module_path, "r");
|
||||||
if (!fp) continue;
|
if (!fp)
|
||||||
|
continue;
|
||||||
|
|
||||||
while (fgets(line, sizeof(line), fp)) {
|
while (fgets(line, sizeof(line), fp)) {
|
||||||
char cmd[CMD_SIZE], *mod, *args;
|
char cmd[CMD_SIZE], *mod, *args;
|
||||||
|
|
||||||
mod = strip_line(line);
|
mod = strip_line(line);
|
||||||
if (!*mod) continue;
|
if (!*mod)
|
||||||
|
continue;
|
||||||
|
|
||||||
mod = chomp(mod);
|
mod = chomp(mod);
|
||||||
if (!mod || !*mod) continue;
|
if (!mod || !*mod)
|
||||||
|
continue;
|
||||||
|
|
||||||
mod = strtok_r(mod, " ", &args);
|
mod = strtok_r(mod, " ", &args);
|
||||||
|
if (!mod)
|
||||||
|
continue;
|
||||||
|
|
||||||
snprintf(cmd, sizeof(cmd), SERVICE_LINE,
|
snprintf(cmd, sizeof(cmd), SERVICE_LINE, index, mod, mod, args, mod);
|
||||||
index, mod, mod, args, mod);
|
|
||||||
service_register(SVC_TYPE_TASK, cmd, global_rlimit, NULL);
|
service_register(SVC_TYPE_TASK, cmd, global_rlimit, NULL);
|
||||||
|
|
||||||
index++;
|
index++;
|
||||||
@@ -81,7 +90,7 @@ static void load(void *arg)
|
|||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
closedir(dirp);
|
closedir(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
|
|||||||
+228
-42
@@ -30,31 +30,35 @@
|
|||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
#include "service.h"
|
||||||
|
|
||||||
static int nlmsg_validate(struct nlmsghdr *nh, size_t len)
|
#define NL_BUFSZ 4096
|
||||||
{
|
|
||||||
if (!NLMSG_OK(nh, len))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (nh->nlmsg_type == NLMSG_DONE) {
|
struct nl_request {
|
||||||
_d("Done with netlink messages.");
|
struct nlmsghdr nh;
|
||||||
return 1;
|
union {
|
||||||
}
|
struct rtmsg rtm;
|
||||||
|
struct ifinfomsg ifi;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
if (nh->nlmsg_type == NLMSG_ERROR) {
|
static int nl_defidx;
|
||||||
_d("Netlink reports error.");
|
static int nl_ifdown;
|
||||||
return 1;
|
static char *nl_buf;
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
|
static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
|
||||||
{
|
{
|
||||||
|
char daddr[INET_ADDRSTRLEN];
|
||||||
|
char gaddr[INET_ADDRSTRLEN];
|
||||||
|
struct in_addr ind, ing;
|
||||||
struct rtmsg *r;
|
struct rtmsg *r;
|
||||||
struct rtattr *a;
|
struct rtattr *a;
|
||||||
|
int plen = 0;
|
||||||
|
int dst = 0;
|
||||||
|
int idx = 0;
|
||||||
|
int gw = 0;
|
||||||
int la;
|
int la;
|
||||||
int gw = 0, dst = 0, mask = 0, idx = 0;
|
|
||||||
|
|
||||||
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg))) {
|
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg))) {
|
||||||
_e("Packet too small or truncated!");
|
_e("Packet too small or truncated!");
|
||||||
@@ -80,8 +84,8 @@ static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
|
|
||||||
case RTA_DST:
|
case RTA_DST:
|
||||||
dst = *((int *)data);
|
dst = *((int *)data);
|
||||||
mask = r->rtm_dst_len;
|
plen = r->rtm_dst_len;
|
||||||
//_d("MASK: 0x%04x", mask);
|
//_d("Prefix LEN: 0x%04x", plen);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTA_OIF:
|
case RTA_OIF:
|
||||||
@@ -93,11 +97,20 @@ static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
a = RTA_NEXT(a, la);
|
a = RTA_NEXT(a, la);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!dst && !mask) && (gw || idx)) {
|
ind.s_addr = dst;
|
||||||
if (nlmsg->nlmsg_type == RTM_DELROUTE)
|
ing.s_addr = gw;
|
||||||
|
inet_ntop(AF_INET, &ind, daddr, sizeof(daddr));
|
||||||
|
inet_ntop(AF_INET, &ing, gaddr, sizeof(gaddr));
|
||||||
|
_d("Got gw %s dst/len %s/%d ifindex %d", gaddr, daddr, plen, idx);
|
||||||
|
|
||||||
|
if ((!dst && !plen) && (gw || idx)) {
|
||||||
|
if (nlmsg->nlmsg_type == RTM_DELROUTE) {
|
||||||
cond_clear("net/route/default");
|
cond_clear("net/route/default");
|
||||||
else
|
nl_defidx = 0;
|
||||||
|
} else {
|
||||||
cond_set("net/route/default");
|
cond_set("net/route/default");
|
||||||
|
nl_defidx = idx;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,14 +130,14 @@ static int validate_ifname(const char *ifname)
|
|||||||
if (!ifname || !ifname[0])
|
if (!ifname || !ifname[0])
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (strlen(ifname) >= IFNAMSIZ)
|
if (strnlen(ifname, IFNAMSIZ) == IFNAMSIZ)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (strstr(ifname, ".."))
|
if (!strcmp(ifname, ".") || !strcmp(ifname, ".."))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
while (*ifname) {
|
while (*ifname) {
|
||||||
if (*ifname == '/' || isspace(*ifname))
|
if (*ifname == '/' || *ifname == ':' || isspace(*ifname))
|
||||||
return 1;
|
return 1;
|
||||||
ifname++;
|
ifname++;
|
||||||
}
|
}
|
||||||
@@ -132,12 +145,25 @@ static int validate_ifname(const char *ifname)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if this interface was associated with the default route
|
||||||
|
* previously, or if it's been removed. If so, trigger a recheck
|
||||||
|
* of the system default route.
|
||||||
|
*/
|
||||||
|
static void nl_check_default(char *ifname)
|
||||||
|
{
|
||||||
|
int idx = (int)if_nametoindex(ifname);
|
||||||
|
|
||||||
|
if ((nl_defidx > 0 && nl_defidx == idx) || (idx == 0 && errno == ENODEV))
|
||||||
|
nl_ifdown = 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
||||||
{
|
{
|
||||||
int la;
|
|
||||||
char ifname[IFNAMSIZ + 1];
|
char ifname[IFNAMSIZ + 1];
|
||||||
struct rtattr *a;
|
|
||||||
struct ifinfomsg *i;
|
struct ifinfomsg *i;
|
||||||
|
struct rtattr *a;
|
||||||
|
int la;
|
||||||
|
|
||||||
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) {
|
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) {
|
||||||
_e("Packet too small or truncated!");
|
_e("Packet too small or truncated!");
|
||||||
@@ -172,6 +198,8 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
net_cond_set(ifname, "exist", 1);
|
net_cond_set(ifname, "exist", 1);
|
||||||
net_cond_set(ifname, "up", i->ifi_flags & IFF_UP);
|
net_cond_set(ifname, "up", i->ifi_flags & IFF_UP);
|
||||||
net_cond_set(ifname, "running", i->ifi_flags & IFF_RUNNING);
|
net_cond_set(ifname, "running", i->ifi_flags & IFF_RUNNING);
|
||||||
|
if (!(i->ifi_flags & IFF_UP) || !(i->ifi_flags & IFF_RUNNING))
|
||||||
|
nl_check_default(ifname);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTM_DELLINK:
|
case RTM_DELLINK:
|
||||||
@@ -180,6 +208,7 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
net_cond_set(ifname, "exist", 0);
|
net_cond_set(ifname, "exist", 0);
|
||||||
net_cond_set(ifname, "up", 0);
|
net_cond_set(ifname, "up", 0);
|
||||||
net_cond_set(ifname, "running", 0);
|
net_cond_set(ifname, "running", 0);
|
||||||
|
nl_check_default(ifname);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTM_NEWADDR:
|
case RTM_NEWADDR:
|
||||||
@@ -197,26 +226,176 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nl_callback(void *arg, int sd, int events)
|
static int nl_parse(int sd)
|
||||||
{
|
{
|
||||||
static char buf[4096];
|
while (1) {
|
||||||
struct nlmsghdr *nh;
|
struct nlmsghdr *nh;
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
|
size_t l;
|
||||||
|
|
||||||
memset(buf, 0, sizeof(buf));
|
while ((len = recv(sd, nl_buf, NL_BUFSZ, 0)) < 0) {
|
||||||
len = recv(sd, buf, sizeof(buf), 0);
|
switch (errno) {
|
||||||
if (len < 0) {
|
case EAGAIN: /* Nothing more right now. */
|
||||||
if (errno != EINTR) /* Signal */
|
return 0;
|
||||||
_pe("recv()");
|
|
||||||
|
case EINTR: /* Signal */
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case ENOBUFS: /* netlink(7) */
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
_pe("recv()");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_d("recv %lld bytes", len);
|
||||||
|
l = (size_t)len;
|
||||||
|
for (nh = (struct nlmsghdr *)nl_buf; NLMSG_OK(nh, l); nh = NLMSG_NEXT(nh, l)) {
|
||||||
|
struct nlmsgerr *nle;
|
||||||
|
|
||||||
|
switch (nh->nlmsg_type) {
|
||||||
|
case NLMSG_DONE:
|
||||||
|
_d("Done with netlink messages.");
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case NLMSG_ERROR:
|
||||||
|
_d("Kernel netlink comm. error.");
|
||||||
|
nle = NLMSG_DATA(nh);
|
||||||
|
if (nle) {
|
||||||
|
errno = -nle->error;
|
||||||
|
_pe("Kernel netlink error %d", errno);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
case RTM_NEWROUTE:
|
||||||
|
case RTM_DELROUTE:
|
||||||
|
_d("Netlink route ...");
|
||||||
|
nl_route(nh, len);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RTM_NEWLINK:
|
||||||
|
case RTM_DELLINK:
|
||||||
|
_d("Netlink link ...");
|
||||||
|
nl_link(nh, len);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
_w("unhandled netlink message, type %d", nh->nlmsg_type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nl_request(int sd, unsigned int seq, int type)
|
||||||
|
{
|
||||||
|
struct nl_request *nlr = (struct nl_request *)nl_buf;
|
||||||
|
|
||||||
|
memset(nlr, 0, sizeof(struct nl_request));
|
||||||
|
nlr->nh.nlmsg_type = type;
|
||||||
|
nlr->nh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
|
||||||
|
nlr->nh.nlmsg_seq = seq;
|
||||||
|
nlr->nh.nlmsg_pid = 1;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case RTM_GETROUTE:
|
||||||
|
_d("RTM_GETROUTE");
|
||||||
|
nlr->rtm.rtm_family = AF_INET;
|
||||||
|
nlr->rtm.rtm_table = RT_TABLE_MAIN;
|
||||||
|
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RTM_GETLINK:
|
||||||
|
_d("RTM_GETLINK");
|
||||||
|
nlr->ifi.ifi_family = AF_UNSPEC;
|
||||||
|
nlr->ifi.ifi_change = 0xFFFFFFFF;
|
||||||
|
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
_w("Cannot resync, unhandled message type %d", type);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (send(sd, nlr, nlr->nh.nlmsg_len, 0) < 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return nl_parse(sd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nl_resync_routes(int sd, unsigned int seq)
|
||||||
|
{
|
||||||
|
if (nl_request(sd, seq, RTM_GETROUTE))
|
||||||
|
_pe("Failed netlink route request");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nl_resync_ifaces(int sd, unsigned int seq)
|
||||||
|
{
|
||||||
|
if (nl_request(sd, seq, RTM_GETLINK))
|
||||||
|
_pe("Failed netlink link request");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We've potentially lost netlink events, let's resync with kernel.
|
||||||
|
*/
|
||||||
|
static void nl_resync(int all)
|
||||||
|
{
|
||||||
|
unsigned int seq = 0;
|
||||||
|
int sd;
|
||||||
|
|
||||||
|
sd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
|
||||||
|
if (sd < 0) {
|
||||||
|
_pe("netlink socket");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (nh = (struct nlmsghdr *)buf; !nlmsg_validate(nh, len); nh = NLMSG_NEXT(nh, len)) {
|
if (all) {
|
||||||
//_d("Well formed netlink message received. type %d ...", nh->nlmsg_type);
|
_d("============================ RESYNC =================================");
|
||||||
if (nh->nlmsg_type == RTM_NEWROUTE || nh->nlmsg_type == RTM_DELROUTE)
|
/* this doesn't update conditions, and thus does not stop services */
|
||||||
nl_route(nh, len);
|
cond_deassert("net/");
|
||||||
else
|
|
||||||
nl_link(nh, len);
|
nl_resync_ifaces(sd, seq++);
|
||||||
|
nl_resync_routes(sd, seq++);
|
||||||
|
|
||||||
|
/* delayed update after we've corrected things */
|
||||||
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
_d("=========================== RESYNCED ================================");
|
||||||
|
} else
|
||||||
|
nl_resync_routes(sd, seq++);
|
||||||
|
|
||||||
|
close(sd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nl_callback(void *arg, int sd, int events)
|
||||||
|
{
|
||||||
|
if (nl_parse(sd) < 0) {
|
||||||
|
if (errno == ENOBUFS) { /* netlink(7) */
|
||||||
|
_w("busy system, resynchronizing with kernel.");
|
||||||
|
nl_resync(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Linux doesn't send route changes when interfaces go down, so
|
||||||
|
* we need to check ourselves, e.g. for loss of default route.
|
||||||
|
*/
|
||||||
|
if (nl_ifdown) {
|
||||||
|
_d("interface down, checking default route.");
|
||||||
|
if (nl_defidx > 0) {
|
||||||
|
nl_defidx = 0;
|
||||||
|
nl_resync(0);
|
||||||
|
if (nl_defidx <= 0) {
|
||||||
|
cond_clear("net/route/default");
|
||||||
|
nl_defidx = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nl_ifdown = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,8 +415,8 @@ static plugin_t plugin = {
|
|||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
{
|
{
|
||||||
int sd;
|
|
||||||
struct sockaddr_nl sa;
|
struct sockaddr_nl sa;
|
||||||
|
int sd;
|
||||||
|
|
||||||
sd = socket(AF_NETLINK, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, NETLINK_ROUTE);
|
sd = socket(AF_NETLINK, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, NETLINK_ROUTE);
|
||||||
if (sd < 0) {
|
if (sd < 0) {
|
||||||
@@ -247,7 +426,7 @@ PLUGIN_INIT(plugin_init)
|
|||||||
|
|
||||||
memset(&sa, 0, sizeof(sa));
|
memset(&sa, 0, sizeof(sa));
|
||||||
sa.nl_family = AF_NETLINK;
|
sa.nl_family = AF_NETLINK;
|
||||||
sa.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_LINK; // | RTMGRP_NOTIFY | RTMGRP_IPV4_IFADDR;
|
sa.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_LINK;
|
||||||
sa.nl_pid = getpid();
|
sa.nl_pid = getpid();
|
||||||
|
|
||||||
if (bind(sd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
if (bind(sd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
||||||
@@ -256,6 +435,13 @@ PLUGIN_INIT(plugin_init)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nl_buf = malloc(NL_BUFSZ);
|
||||||
|
if (!nl_buf) {
|
||||||
|
_pe("malloc()");
|
||||||
|
close(sd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
plugin.io.fd = sd;
|
plugin.io.fd = sd;
|
||||||
plugin_register(&plugin);
|
plugin_register(&plugin);
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-15
@@ -58,7 +58,7 @@ static int pidfile_add_path(struct iwatch *iw, char *path)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return iwatch_add(iw, path, IN_ONLYDIR);
|
return iwatch_add(iw, path, IN_ONLYDIR | IN_CLOSE_WRITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
|
static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
|
||||||
@@ -68,11 +68,11 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
|
|||||||
svc_t *svc;
|
svc_t *svc;
|
||||||
|
|
||||||
paste(fn, sizeof(fn), dir, name);
|
paste(fn, sizeof(fn), dir, name);
|
||||||
_d("path: %s, mask: %08x", fn, mask);
|
|
||||||
|
|
||||||
if (fnmatch("*\\.pid", fn, 0) && fnmatch("*/pid", fn, 0))
|
if (fnmatch("*\\.pid", fn, 0) && fnmatch("*/pid", fn, 0))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
_d("path: %s, mask: %08x", fn, mask);
|
||||||
|
|
||||||
svc = svc_find_by_pidfile(fn);
|
svc = svc_find_by_pidfile(fn);
|
||||||
if (!svc) {
|
if (!svc) {
|
||||||
_d("No matching svc for %s", fn);
|
_d("No matching svc for %s", fn);
|
||||||
@@ -82,15 +82,27 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
|
|||||||
_d("Found svc %s for %s with pid %d", svc->name, fn, svc->pid);
|
_d("Found svc %s for %s with pid %d", svc->name, fn, svc->pid);
|
||||||
|
|
||||||
mkcond(svc, cond, sizeof(cond));
|
mkcond(svc, cond, sizeof(cond));
|
||||||
if (mask & (IN_CREATE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) {
|
if (mask & (IN_CLOSE_WRITE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) {
|
||||||
svc_started(svc);
|
svc_started(svc);
|
||||||
|
if (!svc_has_pidfile(svc)) {
|
||||||
|
_d("Setting %s PID file to %s", svc->name, fn);
|
||||||
|
pid_file_set(svc, fn, 1);
|
||||||
|
}
|
||||||
|
|
||||||
if (svc_is_forking(svc)) {
|
if (svc_is_forking(svc)) {
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
pid = pid_file_read(pid_file(svc));
|
pid = pid_file_read(pid_file(svc));
|
||||||
_d("Forking service %s changed PID from %d to %d",
|
if (pid == -1) {
|
||||||
svc->cmd, svc->pid, pid);
|
cond_clear(cond);
|
||||||
svc->pid = pid;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid != svc->pid) {
|
||||||
|
_d("Forking service %s changed PID from %d to %d",
|
||||||
|
svc->cmd, svc->pid, pid);
|
||||||
|
svc->pid = pid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cond_set(cond);
|
cond_set(cond);
|
||||||
@@ -174,8 +186,6 @@ static void pidfile_callback(void *arg, int fd, int events)
|
|||||||
if (!ev->mask)
|
if (!ev->mask)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_d("name %s, event: 0x%08x", ev->name, ev->mask);
|
|
||||||
|
|
||||||
/* Find base path for this event */
|
/* Find base path for this event */
|
||||||
iwp = iwatch_find_by_wd(&iw_pidfile, ev->wd);
|
iwp = iwatch_find_by_wd(&iw_pidfile, ev->wd);
|
||||||
if (!iwp)
|
if (!iwp)
|
||||||
@@ -186,12 +196,7 @@ static void pidfile_callback(void *arg, int fd, int events)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ev->mask & IN_DELETE) {
|
if (ev->mask & (IN_CLOSE_WRITE | IN_DELETE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO))
|
||||||
_d("pidfile %s/%s removed ...", iwp->path, ev->name);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ev->mask & (IN_CREATE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO))
|
|
||||||
pidfile_update_conds(iwp->path, ev->name, ev->mask);
|
pidfile_update_conds(iwp->path, ev->name, ev->mask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -233,8 +238,14 @@ static void pidfile_reconf(void *arg)
|
|||||||
|
|
||||||
static void pidfile_init(void *arg)
|
static void pidfile_init(void *arg)
|
||||||
{
|
{
|
||||||
|
char piddir[MAX_ARG_LEN];
|
||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
|
if (mkpath(pid_runpath(_PATH_CONDPID, piddir, sizeof(piddir)), 0755) && errno != EEXIST) {
|
||||||
|
_pe("Failed creating %s condition directory, %s", COND_PID, _PATH_CONDPID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The bootmisc plugin is responsible for setting up /var/run.
|
* The bootmisc plugin is responsible for setting up /var/run.
|
||||||
* and/or /run, with proper symlinks etc. We depend on bootmisc
|
* and/or /run, with proper symlinks etc. We depend on bootmisc
|
||||||
@@ -242,6 +253,7 @@ static void pidfile_init(void *arg)
|
|||||||
*/
|
*/
|
||||||
path = realpath(_PATH_VARRUN, NULL);
|
path = realpath(_PATH_VARRUN, NULL);
|
||||||
if (!path) {
|
if (!path) {
|
||||||
|
_d("Failed querying realpath(%s): %s", _PATH_VARRUN, strerror(errno));
|
||||||
path = realpath("/run", NULL);
|
path = realpath("/run", NULL);
|
||||||
if (!path) {
|
if (!path) {
|
||||||
_e("System does not have %s or /run, aborting.", _PATH_VARRUN);
|
_e("System does not have %s or /run, aborting.", _PATH_VARRUN);
|
||||||
@@ -251,6 +263,8 @@ static void pidfile_init(void *arg)
|
|||||||
|
|
||||||
if (pidfile_add_path(&iw_pidfile, path))
|
if (pidfile_add_path(&iw_pidfile, path))
|
||||||
iwatch_exit(&iw_pidfile);
|
iwatch_exit(&iw_pidfile);
|
||||||
|
|
||||||
|
free(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
+13
-1
@@ -22,7 +22,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <glob.h>
|
#include <glob.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "finit.h"
|
||||||
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
|
||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
@@ -31,6 +38,11 @@ static void setup(void *arg)
|
|||||||
glob_t gl;
|
glob_t gl;
|
||||||
char buf[160];
|
char buf[160];
|
||||||
|
|
||||||
|
if (rescue) {
|
||||||
|
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
glob("/run/sysctl.d/*.conf", 0, NULL, &gl);
|
glob("/run/sysctl.d/*.conf", 0, NULL, &gl);
|
||||||
glob("/etc/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
glob("/etc/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||||
glob("/usr/local/lib/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
glob("/usr/local/lib/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||||
|
|||||||
@@ -21,7 +21,11 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|||||||
+26
-2
@@ -24,7 +24,11 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <linux/rtc.h>
|
#include <linux/rtc.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
@@ -84,6 +88,11 @@ static void rtc_save(void *arg)
|
|||||||
int fd, rc = 0;
|
int fd, rc = 0;
|
||||||
char tz[128];
|
char tz[128];
|
||||||
|
|
||||||
|
if (rescue) {
|
||||||
|
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
fd = rtc_open();
|
fd = rtc_open();
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return;
|
return;
|
||||||
@@ -121,6 +130,11 @@ static void rtc_restore(void *arg)
|
|||||||
int fd, rc = 0;
|
int fd, rc = 0;
|
||||||
char tz[128];
|
char tz[128];
|
||||||
|
|
||||||
|
if (rescue) {
|
||||||
|
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
fd = rtc_open();
|
fd = rtc_open();
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return;
|
return;
|
||||||
@@ -142,8 +156,18 @@ static void rtc_restore(void *arg)
|
|||||||
logit(LOG_ERR, "RTC has no previously saved (valid) time.");
|
logit(LOG_ERR, "RTC has no previously saved (valid) time.");
|
||||||
else
|
else
|
||||||
logit(LOG_ERR, "RTC error code %d: %s", errno, strerror(errno));
|
logit(LOG_ERR, "RTC error code %d: %s", errno, strerror(errno));
|
||||||
|
|
||||||
|
/* Been here already? */
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* Attempt to set RTC to a sane value ... */
|
||||||
|
tv.tv_sec = RTC_TIMESTAMP_BEGIN_2000;
|
||||||
|
if (!gmtime_r(&tv.tv_sec, &tm))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
logit(LOG_NOTICE, "Resetting RTC to kernel default, 2000-01-01 00:00.");
|
||||||
rc = 2;
|
rc = 2;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
print_desc(NULL, "Restoring system clock (UTC) from RTC");
|
print_desc(NULL, "Restoring system clock (UTC) from RTC");
|
||||||
|
|||||||
+209
@@ -0,0 +1,209 @@
|
|||||||
|
/* System condition event monitor for the Finit condition engine
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <fnmatch.h>
|
||||||
|
#include <glob.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <paths.h>
|
||||||
|
|
||||||
|
#include "finit.h"
|
||||||
|
#include "cond.h"
|
||||||
|
#include "pid.h"
|
||||||
|
#include "plugin.h"
|
||||||
|
#include "iwatch.h"
|
||||||
|
|
||||||
|
static struct iwatch iw_sys;
|
||||||
|
|
||||||
|
|
||||||
|
static int sys_add_path(struct iwatch *iw, char *path)
|
||||||
|
{
|
||||||
|
return iwatch_add(iw, path, IN_ONLYDIR | IN_CLOSE_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* unlink conditions with no active task/service, otherwise they may
|
||||||
|
* trigger inadvertently when calling `initctl reload` to activate
|
||||||
|
* a new configuration.
|
||||||
|
*/
|
||||||
|
static void sys_update_conds(char *dir, char *name, uint32_t mask)
|
||||||
|
{
|
||||||
|
char path[256];
|
||||||
|
char *cond;
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
ptr = strrchr(name, '/');
|
||||||
|
if (ptr)
|
||||||
|
snprintf(path, sizeof(path), "%s/%s", dir, ++ptr);
|
||||||
|
else
|
||||||
|
snprintf(path, sizeof(path), "%s/%s", dir, name);
|
||||||
|
|
||||||
|
cond = strstr(path, COND_BASE);
|
||||||
|
if (!cond)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cond += strlen(COND_BASE) + 1;
|
||||||
|
_d("cond: %s set: %d", cond, mask & IN_CREATE ? 1 : 0);
|
||||||
|
if (!cond_update(cond))
|
||||||
|
unlink(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* synthesize events in case of new run dirs */
|
||||||
|
static void sys_scandir(struct iwatch *iw, char *dir, int len)
|
||||||
|
{
|
||||||
|
glob_t gl;
|
||||||
|
size_t i;
|
||||||
|
char path[len + 6];
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "%s/*", dir);
|
||||||
|
rc = glob(path, GLOB_NOSORT, NULL, &gl);
|
||||||
|
if (rc && rc != GLOB_NOMATCH)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < gl.gl_pathc; i++) {
|
||||||
|
_d("scan found %s", gl.gl_pathv[i]);
|
||||||
|
sys_update_conds(dir, gl.gl_pathv[i], IN_CREATE);
|
||||||
|
}
|
||||||
|
globfree(&gl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* create/remove sub-directory in monitored directory
|
||||||
|
*/
|
||||||
|
static void sys_handle_dir(struct iwatch *iw, char *dir, char *name, int mask)
|
||||||
|
{
|
||||||
|
char path[strlen(dir) + strlen(name) + 2];
|
||||||
|
struct iwatch_path *iwp;
|
||||||
|
|
||||||
|
paste(path, sizeof(path), dir, name);
|
||||||
|
_d("path: %s", path);
|
||||||
|
|
||||||
|
iwp = iwatch_find_by_path(iw, path);
|
||||||
|
|
||||||
|
if (mask & IN_CREATE) {
|
||||||
|
if (!iwp) {
|
||||||
|
if (!sys_add_path(iw, path))
|
||||||
|
sys_scandir(iw, path, sizeof(path));
|
||||||
|
}
|
||||||
|
} else if (mask & IN_DELETE) {
|
||||||
|
if (iwp)
|
||||||
|
iwatch_del(&iw_sys, iwp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sys_callback(void *arg, int fd, int events)
|
||||||
|
{
|
||||||
|
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
||||||
|
struct inotify_event *ev;
|
||||||
|
ssize_t sz;
|
||||||
|
size_t off;
|
||||||
|
|
||||||
|
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
||||||
|
if (sz <= 0) {
|
||||||
|
_pe("invalid inotify event");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ev_buf[sz] = 0;
|
||||||
|
|
||||||
|
for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) {
|
||||||
|
struct iwatch_path *iwp;
|
||||||
|
|
||||||
|
if (off + sizeof(*ev) > (size_t)sz)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ev = (struct inotify_event *)&ev_buf[off];
|
||||||
|
if (off + sizeof(*ev) + ev->len > (size_t)sz)
|
||||||
|
break;
|
||||||
|
|
||||||
|
_d("name %s, event: 0x%08x", ev->name, ev->mask);
|
||||||
|
if (!ev->mask)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Find base path for this event */
|
||||||
|
iwp = iwatch_find_by_wd(&iw_sys, ev->wd);
|
||||||
|
if (!iwp)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ev->mask & IN_ISDIR) {
|
||||||
|
sys_handle_dir(&iw_sys, iwp->path, ev->name, ev->mask);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ev->mask & (IN_CREATE | IN_DELETE))
|
||||||
|
sys_update_conds(iwp->path, ev->name, ev->mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sys_init(void *arg)
|
||||||
|
{
|
||||||
|
char sysdir[MAX_ARG_LEN];
|
||||||
|
char *path;
|
||||||
|
|
||||||
|
if (mkpath(pid_runpath(_PATH_CONDSYS, sysdir, sizeof(sysdir)), 0755) && errno != EEXIST) {
|
||||||
|
_pe("Failed creating %s condition directory, %s", COND_SYS, _PATH_CONDSYS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
path = realpath(_PATH_CONDSYS, NULL);
|
||||||
|
if (!path) {
|
||||||
|
_pe("Cannot figure out real path to %s, aborting", _PATH_CONDSYS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iwatch_add(&iw_sys, path, IN_ONLYDIR))
|
||||||
|
iwatch_exit(&iw_sys);
|
||||||
|
}
|
||||||
|
|
||||||
|
static plugin_t plugin = {
|
||||||
|
.name = __FILE__,
|
||||||
|
.hook[HOOK_BASEFS_UP] = { .cb = sys_init },
|
||||||
|
};
|
||||||
|
|
||||||
|
PLUGIN_INIT(plugin_init)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = iwatch_init(&iw_sys);
|
||||||
|
if (fd < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
plugin.io.fd = fd;
|
||||||
|
plugin.io.cb = sys_callback;
|
||||||
|
plugin.io.flags = PLUGIN_IO_READ;
|
||||||
|
|
||||||
|
plugin_register(&plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
PLUGIN_EXIT(plugin_exit)
|
||||||
|
{
|
||||||
|
iwatch_exit(&iw_sys);
|
||||||
|
plugin_unregister(&plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Variables:
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
+21
-11
@@ -27,18 +27,23 @@
|
|||||||
#include <unistd.h> /* read() */
|
#include <unistd.h> /* read() */
|
||||||
#include <sys/inotify.h>
|
#include <sys/inotify.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
#include "service.h"
|
||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
|
|
||||||
static void watcher(void *arg, int fd, int events);
|
static void tty_watcher(void *arg, int fd, int events);
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
.io = {
|
.io = {
|
||||||
.cb = watcher,
|
.cb = tty_watcher,
|
||||||
.flags = PLUGIN_IO_READ,
|
.flags = PLUGIN_IO_READ,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -56,19 +61,24 @@ static void setup(void)
|
|||||||
static void do_tty(char *tty, size_t len, int creat)
|
static void do_tty(char *tty, size_t len, int creat)
|
||||||
{
|
{
|
||||||
char name[len + 6];
|
char name[len + 6];
|
||||||
struct tty *entry;
|
svc_t *svc;
|
||||||
|
|
||||||
snprintf(name, sizeof(name), "/dev/%s", tty);
|
snprintf(name, sizeof(name), "/dev/%s", tty);
|
||||||
entry = tty_find(name);
|
svc = svc_find_by_tty(name);
|
||||||
if (entry && tty_enabled(entry)) {
|
if (svc) {
|
||||||
if (creat)
|
if (svc_is_blocked(svc) && creat) {
|
||||||
tty_start(entry);
|
_d("%s: blocked, re-enabling", svc_ident(svc, NULL, 0));
|
||||||
else if (entry->pid)
|
svc_start(svc);
|
||||||
tty_stop(entry);
|
} else if (svc->pid) {
|
||||||
|
_d("%s: missing ...", svc_ident(svc, NULL, 0));
|
||||||
|
svc_missing(svc);
|
||||||
|
}
|
||||||
|
|
||||||
|
service_step_all(SVC_TYPE_TTY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void watcher(void *arg, int fd, int events)
|
static void tty_watcher(void *arg, int fd, int events)
|
||||||
{
|
{
|
||||||
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
||||||
struct inotify_event *ev;
|
struct inotify_event *ev;
|
||||||
|
|||||||
+90
-8
@@ -1,4 +1,4 @@
|
|||||||
/* Setup random seed
|
/* Setup and save random seed at boot/shutdown
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
@@ -22,25 +22,46 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/time.h> /* gettimeofday() */
|
#include <sys/time.h> /* gettimeofday() */
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
#include <linux/random.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
|
||||||
|
#ifndef RANDOM_BYTES
|
||||||
|
#define RANDOM_BYTES (32*1024)
|
||||||
|
#endif
|
||||||
|
|
||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
{
|
{
|
||||||
#ifdef RANDOMSEED
|
#ifdef RANDOMSEED
|
||||||
|
struct rand_pool_info *rpi;
|
||||||
|
ssize_t len = 0;
|
||||||
|
int rc = -1;
|
||||||
|
int fd, err;
|
||||||
|
|
||||||
|
if (rescue) {
|
||||||
|
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!fexist(RANDOMSEED)) {
|
if (!fexist(RANDOMSEED)) {
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
|
mode_t prev;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
print_desc("Bootstrapping random seed", NULL);
|
print_desc("Bootstrapping random seed", NULL);
|
||||||
umask(077);
|
prev = umask(077);
|
||||||
fp = fopen(RANDOMSEED, "w");
|
fp = fopen(RANDOMSEED, "w");
|
||||||
if (fp) {
|
if (fp) {
|
||||||
int iter = 128;
|
int iter = 128;
|
||||||
@@ -57,21 +78,82 @@ static void setup(void *arg)
|
|||||||
ret = fclose(fp);
|
ret = fclose(fp);
|
||||||
}
|
}
|
||||||
print_result(ret);
|
print_result(ret);
|
||||||
umask(0);
|
umask(prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
print_desc("Initializing random number generator", NULL);
|
print_desc("Initializing random number generator", NULL);
|
||||||
print_result(512 != copyfile(RANDOMSEED, "/dev/urandom", 0, 0));
|
|
||||||
|
/*
|
||||||
|
* Simply copying our saved entropy to /dev/urandom doesn't
|
||||||
|
* increment the kernel "entropy count", instead we must use
|
||||||
|
* the ioctl below.
|
||||||
|
*/
|
||||||
|
fd = open(RANDOMSEED, O_RDONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
goto fallback;
|
||||||
|
|
||||||
|
rpi = malloc(sizeof(*rpi) + RANDOM_BYTES);
|
||||||
|
if (!rpi) {
|
||||||
|
close(fd);
|
||||||
|
goto fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
ssize_t num;
|
||||||
|
|
||||||
|
num = read(fd, &rpi->buf[len], RANDOM_BYTES - len);
|
||||||
|
if (num <= 0) {
|
||||||
|
if (num == -1 && errno == EINTR)
|
||||||
|
continue;
|
||||||
|
if (len > 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
free(rpi);
|
||||||
|
goto fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
len += num;
|
||||||
|
} while (len < RANDOM_BYTES);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
fd = open("/dev/urandom", O_WRONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
free(rpi);
|
||||||
|
goto fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
rpi->buf_size = len;
|
||||||
|
rpi->entropy_count = len * 8;
|
||||||
|
rc = ioctl(fd, RNDADDENTROPY, rpi);
|
||||||
|
err = errno;
|
||||||
|
close(fd);
|
||||||
|
free(rpi);
|
||||||
|
if (rc < 0)
|
||||||
|
logit(LOG_ERR, "Failed adding entropy to kernel random pool: %s", strerror(err));
|
||||||
|
print_result(rc < 0);
|
||||||
|
return;
|
||||||
|
fallback:
|
||||||
|
print_result(512 > copyfile(RANDOMSEED, "/dev/urandom", 0, 0));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void save(void *arg)
|
static void save(void *arg)
|
||||||
{
|
{
|
||||||
#ifdef RANDOMSEED
|
#ifdef RANDOMSEED
|
||||||
umask(077);
|
mode_t prev;
|
||||||
|
|
||||||
|
if (rescue) {
|
||||||
|
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev = umask(077);
|
||||||
|
|
||||||
print_desc("Saving random seed", NULL);
|
print_desc("Saving random seed", NULL);
|
||||||
print_result(512 != copyfile("/dev/urandom", RANDOMSEED, 512, 0));
|
print_result(RANDOM_BYTES != copyfile("/dev/urandom", RANDOMSEED, RANDOM_BYTES, 0));
|
||||||
umask(0);
|
|
||||||
|
umask(prev);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+135
@@ -0,0 +1,135 @@
|
|||||||
|
/* User-defined condition event monitor for the Finit condition engine
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fnmatch.h>
|
||||||
|
#include <glob.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <paths.h>
|
||||||
|
|
||||||
|
#include "finit.h"
|
||||||
|
#include "cond.h"
|
||||||
|
#include "pid.h"
|
||||||
|
#include "plugin.h"
|
||||||
|
#include "iwatch.h"
|
||||||
|
|
||||||
|
static struct iwatch iw_usr;
|
||||||
|
|
||||||
|
|
||||||
|
static void usr_cond(char *name, uint32_t mask)
|
||||||
|
{
|
||||||
|
char cond[MAX_COND_LEN] = COND_USR;
|
||||||
|
|
||||||
|
strlcat(cond, name, sizeof(cond));
|
||||||
|
cond_update(cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usr_callback(void *arg, int fd, int events)
|
||||||
|
{
|
||||||
|
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
||||||
|
struct inotify_event *ev;
|
||||||
|
ssize_t sz;
|
||||||
|
size_t off;
|
||||||
|
|
||||||
|
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
||||||
|
if (sz <= 0) {
|
||||||
|
_pe("invalid inotify event");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ev_buf[sz] = 0;
|
||||||
|
|
||||||
|
for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) {
|
||||||
|
if (off + sizeof(*ev) > (size_t)sz)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ev = (struct inotify_event *)&ev_buf[off];
|
||||||
|
if (off + sizeof(*ev) + ev->len > (size_t)sz)
|
||||||
|
break;
|
||||||
|
|
||||||
|
_d("name %s, event: 0x%08x", ev->name, ev->mask);
|
||||||
|
if (!ev->mask)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ev->mask & IN_ISDIR)
|
||||||
|
continue; /* unsupported */
|
||||||
|
|
||||||
|
if (ev->mask & IN_DELETE)
|
||||||
|
sync(); /* dont ask */
|
||||||
|
|
||||||
|
usr_cond(ev->name, ev->mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usr_init(void *arg)
|
||||||
|
{
|
||||||
|
char usrdir[MAX_ARG_LEN];
|
||||||
|
char *path;
|
||||||
|
|
||||||
|
if (mkpath(pid_runpath(_PATH_CONDUSR, usrdir, sizeof(usrdir)), 0755) && errno != EEXIST) {
|
||||||
|
_pe("Failed creating %s condition directory, %s", COND_USR, _PATH_CONDUSR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
path = realpath(_PATH_CONDUSR, NULL);
|
||||||
|
if (!path) {
|
||||||
|
_pe("Cannot figure out real path to %s, aborting", _PATH_CONDUSR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iwatch_add(&iw_usr, path, IN_ONLYDIR))
|
||||||
|
iwatch_exit(&iw_usr);
|
||||||
|
|
||||||
|
free(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static plugin_t plugin = {
|
||||||
|
.name = __FILE__,
|
||||||
|
.hook[HOOK_BASEFS_UP] = { .cb = usr_init },
|
||||||
|
};
|
||||||
|
|
||||||
|
PLUGIN_INIT(plugin_init)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = iwatch_init(&iw_usr);
|
||||||
|
if (fd < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
plugin.io.fd = fd;
|
||||||
|
plugin.io.cb = usr_callback;
|
||||||
|
plugin.io.flags = PLUGIN_IO_READ;
|
||||||
|
|
||||||
|
plugin_register(&plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
PLUGIN_EXIT(plugin_exit)
|
||||||
|
{
|
||||||
|
iwatch_exit(&iw_usr);
|
||||||
|
plugin_unregister(&plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Variables:
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
+15
-5
@@ -24,7 +24,11 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
@@ -32,13 +36,19 @@
|
|||||||
|
|
||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
{
|
{
|
||||||
|
const char *username = "nobody";
|
||||||
|
char line[LINE_SIZE];
|
||||||
|
mode_t prev;
|
||||||
#ifdef PAM_CONSOLE
|
#ifdef PAM_CONSOLE
|
||||||
int fd;
|
int fd;
|
||||||
#endif
|
#endif
|
||||||
char line[LINE_SIZE];
|
|
||||||
const char *username = "nobody";
|
|
||||||
|
|
||||||
umask(0);
|
if (rescue) {
|
||||||
|
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev = umask(0);
|
||||||
|
|
||||||
makedir("/var/run/console", 01777);
|
makedir("/var/run/console", 01777);
|
||||||
snprintf(line, sizeof(line), "/var/run/console/%s", username);
|
snprintf(line, sizeof(line), "/var/run/console/%s", username);
|
||||||
@@ -58,7 +68,7 @@ static void setup(void *arg)
|
|||||||
if (whichp("restorecon"))
|
if (whichp("restorecon"))
|
||||||
run("restorecon /tmp/.ICE-unix /tmp/.X11-unix");
|
run("restorecon /tmp/.ICE-unix /tmp/.X11-unix");
|
||||||
|
|
||||||
umask(022);
|
umask(prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
.deps/*
|
.deps/*
|
||||||
finit
|
finit
|
||||||
|
getty
|
||||||
initctl
|
initctl
|
||||||
|
keventd
|
||||||
logit
|
logit
|
||||||
reboot
|
reboot
|
||||||
|
sulogin
|
||||||
watchdogd
|
watchdogd
|
||||||
Makefile
|
Makefile
|
||||||
Makefile.in
|
Makefile.in
|
||||||
|
|||||||
+34
-22
@@ -1,4 +1,4 @@
|
|||||||
EXTRA_DIST = cgreaper.sh rescue.conf sample.conf
|
EXTRA_DIST = rescue.conf sample.conf
|
||||||
AM_CPPFLAGS = -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
|
AM_CPPFLAGS = -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
|
||||||
if STATIC
|
if STATIC
|
||||||
AM_CPPFLAGS += -DENABLE_STATIC
|
AM_CPPFLAGS += -DENABLE_STATIC
|
||||||
@@ -7,29 +7,42 @@ else
|
|||||||
AM_LDFLAGS = -export-dynamic
|
AM_LDFLAGS = -export-dynamic
|
||||||
endif
|
endif
|
||||||
|
|
||||||
sbin_PROGRAMS = finit initctl
|
sbin_PROGRAMS = finit initctl
|
||||||
pkglibexec_SCRIPTS = cgreaper.sh
|
pkglibexec_PROGRAMS = getty logit sulogin
|
||||||
|
if KEVENTD
|
||||||
|
pkglibexec_PROGRAMS += keventd
|
||||||
|
endif
|
||||||
|
if WATCHDOGD
|
||||||
|
pkglibexec_PROGRAMS += watchdogd
|
||||||
|
endif
|
||||||
|
|
||||||
finit_pkglibdir = $(pkglibdir)
|
finit_pkglibdir = $(pkglibdir)
|
||||||
finit_pkglib_SCRIPTS = rescue.conf sample.conf
|
finit_pkglib_SCRIPTS = rescue.conf sample.conf
|
||||||
|
|
||||||
if WATCHDOGD
|
getty_SOURCES = finit.h getty.c helpers.h logrotate.c stty.c utmp-api.c utmp-api.h
|
||||||
pkglibexec_PROGRAMS = watchdogd
|
getty_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||||
endif
|
getty_CFLAGS += $(lite_CFLAGS)
|
||||||
|
getty_LDADD = $(lite_LIBS)
|
||||||
|
|
||||||
if LOGIT
|
keventd_SOURCES = keventd.c iwatch.c iwatch.h util.c util.h
|
||||||
pkglibexec_PROGRAMS = logit
|
keventd_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||||
logit_SOURCES = logit.c logrotate.c
|
keventd_CFLAGS += $(lite_CFLAGS)
|
||||||
logit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
keventd_LDADD = $(lite_LIBS)
|
||||||
logit_CFLAGS += $(lite_CFLAGS)
|
|
||||||
logit_LDADD = $(lite_LIBS)
|
sulogin_SOURCES = sulogin.c
|
||||||
endif
|
sulogin_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||||
|
sulogin_LDADD = -lcrypt
|
||||||
|
|
||||||
|
logit_SOURCES = logit.c logrotate.c
|
||||||
|
logit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||||
|
logit_CFLAGS += $(lite_CFLAGS)
|
||||||
|
logit_LDADD = $(lite_LIBS)
|
||||||
|
|
||||||
finit_SOURCES = api.c cgroup.c cgroup.h \
|
finit_SOURCES = api.c cgroup.c cgroup.h \
|
||||||
cond.c cond-w.c cond.h \
|
cond.c cond-w.c cond.h \
|
||||||
conf.c conf.h \
|
conf.c conf.h \
|
||||||
exec.c finit.c finit.h \
|
exec.c finit.c finit.h \
|
||||||
getty.c stty.c \
|
stty.c \
|
||||||
helpers.c helpers.h \
|
helpers.c helpers.h \
|
||||||
iwatch.c iwatch.h \
|
iwatch.c iwatch.h \
|
||||||
log.c log.h \
|
log.c log.h \
|
||||||
@@ -48,7 +61,7 @@ if LOGROTATE
|
|||||||
finit_SOURCES += logrotate.c
|
finit_SOURCES += logrotate.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
pkginclude_HEADERS = cond.h finit.h helpers.h log.h plugin.h svc.h
|
pkginclude_HEADERS = cgroup.h cond.h finit.h helpers.h log.h plugin.h svc.h
|
||||||
|
|
||||||
finit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
finit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||||
finit_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
|
finit_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
|
||||||
@@ -59,20 +72,19 @@ else
|
|||||||
finit_LDADD += -ldl
|
finit_LDADD += -ldl
|
||||||
endif
|
endif
|
||||||
|
|
||||||
initctl_SOURCES = initctl.c client.c client.h \
|
initctl_SOURCES = initctl.c initctl.h cgutil.c cgutil.h \
|
||||||
reboot.c serv.c serv.h svc.h \
|
client.c client.h cond.c cond.h reboot.c \
|
||||||
cond.c cond.h util.c util.h
|
serv.c serv.h svc.h util.c util.h
|
||||||
initctl_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
initctl_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||||
initctl_CFLAGS += $(lite_CFLAGS)
|
initctl_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
|
||||||
initctl_LDADD = $(lite_LIBS)
|
initctl_LDADD = $(lite_LIBS) $(uev_LIBS)
|
||||||
|
|
||||||
INIT_LNKS = init
|
INIT_LNKS = init telinit
|
||||||
REBOOT_LNKS = reboot shutdown halt poweroff suspend
|
REBOOT_LNKS = reboot shutdown halt poweroff suspend
|
||||||
|
|
||||||
if WATCHDOGD
|
if WATCHDOGD
|
||||||
watchdogd_SOURCES = watchdog.c watchdog.h
|
watchdogd_SOURCES = watchdog.c watchdog.h
|
||||||
watchdogd_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
watchdogd_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||||
#log.c log.h
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Hook in install to add finit and reboot symlink(s)
|
# Hook in install to add finit and reboot symlink(s)
|
||||||
|
|||||||
@@ -29,7 +29,11 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
#include <uev/uev.h>
|
#include <uev/uev.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@@ -74,7 +78,24 @@ static int start(svc_t *svc)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTE: this does not wait for svc to be stopped first, that is the
|
||||||
|
* responsibility of initctl to do. Otherwise we'd block PID 1,
|
||||||
|
* or introduce some nasty race conditions.
|
||||||
|
*/
|
||||||
static int restart(svc_t *svc)
|
static int restart(svc_t *svc)
|
||||||
|
{
|
||||||
|
if (!svc)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
svc_mark_dirty(svc);
|
||||||
|
svc_start(svc);
|
||||||
|
service_step(svc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int reload(svc_t *svc)
|
||||||
{
|
{
|
||||||
if (!svc)
|
if (!svc)
|
||||||
return 1;
|
return 1;
|
||||||
@@ -88,9 +109,10 @@ static int restart(svc_t *svc)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_start (char *buf, size_t len) { return call(start, buf, len); }
|
|
||||||
static int do_stop (char *buf, size_t len) { return call(stop, buf, len); }
|
static int do_stop (char *buf, size_t len) { return call(stop, buf, len); }
|
||||||
|
static int do_start (char *buf, size_t len) { return call(start, buf, len); }
|
||||||
static int do_restart(char *buf, size_t len) { return call(restart, buf, len); }
|
static int do_restart(char *buf, size_t len) { return call(restart, buf, len); }
|
||||||
|
static int do_reload (char *buf, size_t len) { return call(reload, buf, len); }
|
||||||
|
|
||||||
static char query_buf[368];
|
static char query_buf[368];
|
||||||
static int missing(char *job, char *id)
|
static int missing(char *job, char *id)
|
||||||
@@ -110,7 +132,7 @@ static int missing(char *job, char *id)
|
|||||||
|
|
||||||
static int do_query(char *buf, size_t len)
|
static int do_query(char *buf, size_t len)
|
||||||
{
|
{
|
||||||
memset(query_buf, 0, sizeof(query_buf));
|
query_buf[0] = 0;
|
||||||
if (svc_parse_jobstr(buf, len, NULL, missing)) {
|
if (svc_parse_jobstr(buf, len, NULL, missing)) {
|
||||||
memcpy(buf, query_buf, len);
|
memcpy(buf, query_buf, len);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -252,10 +274,10 @@ static void send_svc(int sd, svc_t *svc)
|
|||||||
|
|
||||||
static void api_cb(uev_t *w, void *arg, int events)
|
static void api_cb(uev_t *w, void *arg, int events)
|
||||||
{
|
{
|
||||||
int sd, lvl;
|
|
||||||
svc_t *svc;
|
|
||||||
static svc_t *iter = NULL;
|
static svc_t *iter = NULL;
|
||||||
struct init_request rq;
|
struct init_request rq;
|
||||||
|
int sd, lvl;
|
||||||
|
svc_t *svc;
|
||||||
|
|
||||||
sd = accept(w->fd, NULL, NULL);
|
sd = accept(w->fd, NULL, NULL);
|
||||||
if (sd < 0) {
|
if (sd < 0) {
|
||||||
@@ -327,16 +349,22 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
result = do_start(rq.data, sizeof(rq.data));
|
result = do_start(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case INIT_CMD_RESTART_SVC:
|
||||||
|
_d("restart %s", rq.data);
|
||||||
|
strterm(rq.data, sizeof(rq.data));
|
||||||
|
result = do_restart(rq.data, sizeof(rq.data));
|
||||||
|
break;
|
||||||
|
|
||||||
case INIT_CMD_STOP_SVC:
|
case INIT_CMD_STOP_SVC:
|
||||||
_d("stop %s", rq.data);
|
_d("stop %s", rq.data);
|
||||||
strterm(rq.data, sizeof(rq.data));
|
strterm(rq.data, sizeof(rq.data));
|
||||||
result = do_stop(rq.data, sizeof(rq.data));
|
result = do_stop(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_RESTART_SVC:
|
case INIT_CMD_RELOAD_SVC:
|
||||||
_d("restart %s", rq.data);
|
_d("reload %s", rq.data);
|
||||||
strterm(rq.data, sizeof(rq.data));
|
strterm(rq.data, sizeof(rq.data));
|
||||||
result = do_restart(rq.data, sizeof(rq.data));
|
result = do_reload(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_GET_RUNLEVEL:
|
case INIT_CMD_GET_RUNLEVEL:
|
||||||
@@ -363,27 +391,33 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_e("Request to hand-over wdog ... to PID %d", rq.runlevel);
|
_d("Request to hand-over wdog ... to PID %d", rq.runlevel);
|
||||||
if (!svc_find_by_pid(rq.runlevel)) {
|
svc = svc_find_by_pid(rq.runlevel);
|
||||||
|
if (!svc) {
|
||||||
logit(LOG_ERR, "Cannot find PID %d, not registered.", rq.runlevel);
|
logit(LOG_ERR, "Cannot find PID %d, not registered.", rq.runlevel);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disable and allow Finit to collect bundled watchdog */
|
if (wdog && wdog != svc) {
|
||||||
if (wdog) {
|
char name[32];
|
||||||
logit(LOG_NOTICE, "Stopping and removing %s (PID:%d)", wdog->cmd, wdog->pid);
|
|
||||||
stop(wdog);
|
svc_ident(svc, name, sizeof(name));
|
||||||
|
logit(LOG_NOTICE, "Handing over wdog ctrl from %s[%d] to %s[%d]",
|
||||||
|
svc_ident(wdog, NULL, 0), wdog->pid, name, svc->pid);
|
||||||
|
|
||||||
if (wdog->protect) {
|
if (wdog->protect) {
|
||||||
wdog->protect = 0;
|
logit(LOG_NOTICE, "Stopping and deleting built-in watchdog.");
|
||||||
wdog->runlevels = 0;
|
stop(wdog);
|
||||||
|
svc_del(wdog);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
wdog = svc;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_SVC_ITER:
|
case INIT_CMD_SVC_ITER:
|
||||||
_d("svc iter, first: %d", rq.runlevel);
|
// _d("svc iter, first: %d", rq.runlevel);
|
||||||
/*
|
/*
|
||||||
* XXX: This severly limits the number of
|
* XXX: This severely limits the number of
|
||||||
* simultaneous client connections, but will
|
* simultaneous client connections, but will
|
||||||
* have to do for now.
|
* have to do for now.
|
||||||
*/
|
*/
|
||||||
@@ -436,34 +470,41 @@ error:
|
|||||||
|
|
||||||
int api_init(uev_ctx_t *ctx)
|
int api_init(uev_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
int sd;
|
|
||||||
mode_t oldmask;
|
|
||||||
struct sockaddr_un sun = {
|
struct sockaddr_un sun = {
|
||||||
.sun_family = AF_UNIX,
|
.sun_family = AF_UNIX,
|
||||||
.sun_path = INIT_SOCKET,
|
.sun_path = INIT_SOCKET,
|
||||||
};
|
};
|
||||||
|
mode_t oldmask;
|
||||||
|
int uid, gid;
|
||||||
|
int sd;
|
||||||
|
|
||||||
_d("Setting up external API socket ...");
|
_d("Setting up external API socket ...");
|
||||||
sd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
sd = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
|
||||||
if (-1 == sd) {
|
if (-1 == sd) {
|
||||||
_pe("Failed starting external API socket");
|
_pe("Failed starting external API socket");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uid = geteuid();
|
||||||
|
gid = getgroup(DEFGROUP);
|
||||||
|
|
||||||
erase(INIT_SOCKET);
|
erase(INIT_SOCKET);
|
||||||
oldmask = umask(0077);
|
oldmask = umask(0117);
|
||||||
if (-1 == bind(sd, (struct sockaddr*)&sun, sizeof(sun)))
|
if (-1 == bind(sd, (struct sockaddr*)&sun, sizeof(sun)))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (-1 == listen(sd, 10))
|
if (-1 == listen(sd, 10))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
if (chown(INIT_SOCKET, uid, gid))
|
||||||
|
_pe("Failed setting group %s on %s", DEFGROUP, INIT_SOCKET);
|
||||||
|
|
||||||
umask(oldmask);
|
umask(oldmask);
|
||||||
if (!uev_io_init(ctx, &api_watcher, api_cb, NULL, sd, UEV_READ))
|
if (!uev_io_init(ctx, &api_watcher, api_cb, NULL, sd, UEV_READ))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
_pe("Failed intializing API socket");
|
_pe("Failed initializing API socket");
|
||||||
umask(oldmask);
|
umask(oldmask);
|
||||||
close(sd);
|
close(sd);
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
# Called by kernel when last child in cgroup exists
|
|
||||||
|
|
||||||
BASE=/sys/fs/cgroup/finit
|
|
||||||
PROC=`basename $1`
|
|
||||||
DIR="$BASE$1"
|
|
||||||
|
|
||||||
#/libexec/finit/logit -p daemon.info -t finit "$PROC stopped, cleaning up control group $DIR"
|
|
||||||
rmdir $DIR
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
+464
-85
@@ -24,117 +24,496 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
# include <libite/queue.h> /* BSD sys/queue.h API */
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
# include <lite/queue.h> /* BSD sys/queue.h API */
|
||||||
|
#endif
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
|
#include <sys/sysinfo.h> /* get_nprocs_conf() */
|
||||||
|
|
||||||
|
#include "cgroup.h"
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
|
#include "iwatch.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
static int cg_init = 0;
|
struct cg {
|
||||||
|
TAILQ_ENTRY(cg) link;
|
||||||
|
|
||||||
/*
|
char *name; /* top-level group name */
|
||||||
* Called by Finit at early boot to mount initial cgroups
|
char *cfg; /* kernel settings */
|
||||||
*/
|
|
||||||
void cgroup_init(void)
|
int active; /* for mark & sweep */
|
||||||
|
int is_protected; /* for init/, user/, & system/ */
|
||||||
|
};
|
||||||
|
|
||||||
|
static TAILQ_HEAD(, cg) cgroups = TAILQ_HEAD_INITIALIZER(cgroups);
|
||||||
|
|
||||||
|
static char controllers[256];
|
||||||
|
|
||||||
|
static struct iwatch iw_cgroup;
|
||||||
|
static uev_t cgw;
|
||||||
|
static int avail;
|
||||||
|
|
||||||
|
|
||||||
|
static void cgset(const char *path, char *ctrl, char *prop)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
char *val;
|
||||||
char buf[80];
|
|
||||||
int opts = MS_NODEV | MS_NOEXEC | MS_NOSUID;
|
|
||||||
|
|
||||||
fp = fopen("/proc/cgroups", "r");
|
_d("path %s, ctrl %s, prop %s", path ?: "NIL", ctrl ?: "NIL", prop ?: "NIL");
|
||||||
if (!fp) {
|
if (!path || !ctrl) {
|
||||||
_d("No cgroup support");
|
_e("Missing path or controller, skipping!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mount("none", "/sys/fs/cgroup", "tmpfs", opts, NULL)) {
|
if (!prop) {
|
||||||
_d("Failed mounting cgroups");
|
prop = strchr(ctrl, '.');
|
||||||
goto fail;
|
if (!prop) {
|
||||||
|
_e("Invalid cgroup ctrl syntax: %s", ctrl);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*prop++ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Skip first line, header */
|
val = strchr(prop, ':');
|
||||||
(void)fgets(buf, sizeof(buf), fp);
|
if (!val) {
|
||||||
while (fgets(buf, sizeof(buf), fp)) {
|
_e("Missing cgroup ctrl value, prop %s", prop);
|
||||||
char *cgroup;
|
return;
|
||||||
char rc[80];
|
}
|
||||||
|
*val++ = 0;
|
||||||
|
|
||||||
cgroup = strtok(buf, "\t ");
|
/* disallow sneaky relative paths */
|
||||||
if (!cgroup)
|
if (strstr(ctrl, "..") || strstr(prop, "..")) {
|
||||||
continue;
|
_e("Possible security violation; '..' not allowed in cgroup config!");
|
||||||
|
return;
|
||||||
snprintf(rc, sizeof(rc), "/sys/fs/cgroup/%s", cgroup);
|
|
||||||
if (mkdir(rc, 0755) && EEXIST != errno)
|
|
||||||
continue;
|
|
||||||
if (mount("cgroup", rc, "cgroup", opts, cgroup))
|
|
||||||
_d("Failed mounting %s cgroup on %s", cgroup, rc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Default cgroups for process monitoring */
|
_d("%s/%s.%s <= %s", path, ctrl, prop, val);
|
||||||
if (mkdir(FINIT_CGPATH, 0755) && EEXIST != errno)
|
if (fnwrite(val, "%s/%s.%s", path, ctrl, prop))
|
||||||
goto fail;
|
_pe("Failed setting %s/%s.%s = %s", path, ctrl, prop, val);
|
||||||
if (mount("none", FINIT_CGPATH, "cgroup", opts, "none,name=finit")) {
|
|
||||||
_pe("Failed mounting Finit cgroup hierarchy");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set up reaper and enable callbacks */
|
|
||||||
echo(FINIT_CGPATH "/release_agent", 0, FINIT_LIBPATH_ "/cgreaper.sh");
|
|
||||||
echo(FINIT_CGPATH "/notify_on_release", 0, "1");
|
|
||||||
|
|
||||||
/* Default groups, PID 1, services, and user/login processes */
|
|
||||||
if (mkdir(FINIT_CGPATH "/init", 0755) && EEXIST != errno)
|
|
||||||
goto fail;
|
|
||||||
if (mkdir(FINIT_CGPATH "/system", 0755) && EEXIST != errno)
|
|
||||||
goto fail;
|
|
||||||
if (mkdir(FINIT_CGPATH "/user", 0755) && EEXIST != errno)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
/* Move ourselves to init */
|
|
||||||
echo(FINIT_CGPATH "/init/cgroup.procs", 0, "1");
|
|
||||||
|
|
||||||
/* We have signal, main screen turn on! */
|
|
||||||
cg_init = 1;
|
|
||||||
fail:
|
|
||||||
fclose(fp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int move_pid(char *group, char *name, char *id, int pid)
|
/*
|
||||||
|
* Settings for a cgroup are on the form: cpu.weight:1234,mem.max:4321,...
|
||||||
|
* Finit supports the short-form 'mem.', replacing it with 'memory.' when
|
||||||
|
* writing the setting to the file system.
|
||||||
|
*/
|
||||||
|
static void group_init(char *path, int leaf, const char *cfg)
|
||||||
|
{
|
||||||
|
char *ptr, *s;
|
||||||
|
|
||||||
|
_d("path %s, leaf %d, cfg %s", path, leaf, cfg ?: "NIL");
|
||||||
|
if (!fisdir(path)) {
|
||||||
|
if (mkdir(path, 0755)) {
|
||||||
|
_pe("Failed creating cgroup %s", path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* enable detected controllers on domain groups */
|
||||||
|
if (!leaf && fnwrite(controllers, "%s/cgroup.subtree_control", path))
|
||||||
|
_pe("Failed enabling %s for %s", controllers, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cfg || !cfg[0])
|
||||||
|
return;
|
||||||
|
|
||||||
|
s = strdupa(cfg);
|
||||||
|
if (!s) {
|
||||||
|
_pe("Failed activating cgroup cfg for %s", path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_d("%s <=> %s", path, s);
|
||||||
|
ptr = strtok(s, ",");
|
||||||
|
while (ptr) {
|
||||||
|
_d("ptr: %s", ptr);
|
||||||
|
if (!strncmp("mem.", ptr, 4))
|
||||||
|
cgset(path, "memory", &ptr[4]);
|
||||||
|
else
|
||||||
|
cgset(path, ptr, NULL);
|
||||||
|
|
||||||
|
ptr = strtok(NULL, ",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cgroup_leaf_init(char *group, char *name, int pid, const char *cfg)
|
||||||
{
|
{
|
||||||
char path[256];
|
char path[256];
|
||||||
|
|
||||||
snprintf(path, sizeof(path), "/sys/fs/cgroup/%s/%s", group, name);
|
_d("group %s, name %s, pid %d, cfg %s", group, name, pid, cfg ?: "NIL");
|
||||||
if (id && strlen(id)) {
|
if (pid < 0 || pid == 1) {
|
||||||
strlcat(path, ":", sizeof(path));
|
|
||||||
strlcat(path, id, sizeof(path));
|
|
||||||
}
|
|
||||||
if (mkdir(path, 0755) && errno != EEXIST)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
strlcat(path, "/cgroup.procs", sizeof(path));
|
|
||||||
|
|
||||||
return echo(path, 0, "%d", pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cgroup_user(char *name)
|
|
||||||
{
|
|
||||||
if (!cg_init)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return move_pid("finit/user", name, "0", getpid());
|
|
||||||
}
|
|
||||||
|
|
||||||
int cgroup_service(char *nm, char *id, int pid)
|
|
||||||
{
|
|
||||||
if (!cg_init)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (pid <= 0) {
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return move_pid("finit/system", nm, id, pid);
|
/* create and initialize new group */
|
||||||
|
snprintf(path, sizeof(path), "/sys/fs/cgroup/%s/%s", group, name);
|
||||||
|
group_init(path, 1, cfg);
|
||||||
|
|
||||||
|
/* move process to new group */
|
||||||
|
if (fnwrite(str("%d", pid), "%s/cgroup.procs", path))
|
||||||
|
_pe("Failed moving pid %d to group %s", pid, path);
|
||||||
|
|
||||||
|
strlcat(path, "/cgroup.events", sizeof(path));
|
||||||
|
|
||||||
|
return iwatch_add(&iw_cgroup, path, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cgroup_user(char *name, int pid)
|
||||||
|
{
|
||||||
|
if (!avail)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return cgroup_leaf_init("user", name, pid, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cgroup_service(char *name, int pid, struct cgroup *cg)
|
||||||
|
{
|
||||||
|
char *group = "system";
|
||||||
|
|
||||||
|
if (!avail)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (cg && cg->name[0]) {
|
||||||
|
char path[256];
|
||||||
|
|
||||||
|
if (!strcmp(cg->name, "root"))
|
||||||
|
return fnwrite(str("%d", pid), FINIT_CGPATH "/cgroup.procs");
|
||||||
|
|
||||||
|
if (!strcmp(cg->name, "init"))
|
||||||
|
return fnwrite(str("%d", pid), FINIT_CGPATH "/init/cgroup.procs");
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "/sys/fs/cgroup/%s", cg->name);
|
||||||
|
if (fisdir(path))
|
||||||
|
group = cg->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cgroup_leaf_init(group, name, pid, cg ? cg->cfg : NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void append_ctrl(char *ctrl)
|
||||||
|
{
|
||||||
|
if (controllers[0])
|
||||||
|
strlcat(controllers, " ", sizeof(controllers));
|
||||||
|
|
||||||
|
strlcat(controllers, "+", sizeof(controllers));
|
||||||
|
strlcat(controllers, ctrl, sizeof(controllers));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cgroup_handle_event(char *event, uint32_t mask)
|
||||||
|
{
|
||||||
|
char path[strlen(event) + 1];
|
||||||
|
char buf[80];
|
||||||
|
char *ptr;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
_d("event: '%s', mask: %08x", event, mask);
|
||||||
|
if (!(mask & IN_MODIFY))
|
||||||
|
return;
|
||||||
|
|
||||||
|
fp = fopen(event, "r");
|
||||||
|
if (!fp) {
|
||||||
|
_d("Failed opening %s, skipping ...", event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
if (strncmp(buf, "populated", 9))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
chomp(buf);
|
||||||
|
if (atoi(&buf[10]))
|
||||||
|
break;
|
||||||
|
|
||||||
|
strlcpy(path, event, sizeof(path));
|
||||||
|
ptr = strrchr(path, '/');
|
||||||
|
if (ptr) {
|
||||||
|
*ptr = 0;
|
||||||
|
if (!cgroup_del(path)) {
|
||||||
|
/*
|
||||||
|
* try with parent, top-level group, we
|
||||||
|
* may get events out-of-order *sigh*
|
||||||
|
*/
|
||||||
|
ptr = strrchr(path, '/');
|
||||||
|
if (!ptr)
|
||||||
|
break;
|
||||||
|
*ptr = 0;
|
||||||
|
cgroup_del(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cgroup_events_cb(uev_t *w, void *arg, int events)
|
||||||
|
{
|
||||||
|
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
||||||
|
struct inotify_event *ev;
|
||||||
|
ssize_t sz;
|
||||||
|
size_t off;
|
||||||
|
|
||||||
|
sz = read(w->fd, ev_buf, sizeof(ev_buf) - 1);
|
||||||
|
if (sz <= 0) {
|
||||||
|
_pe("invalid inotify event");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ev_buf[sz] = 0;
|
||||||
|
|
||||||
|
for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) {
|
||||||
|
struct iwatch_path *iwp;
|
||||||
|
|
||||||
|
if (off + sizeof(*ev) > (size_t)sz)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ev = (struct inotify_event *)&ev_buf[off];
|
||||||
|
if (off + sizeof(*ev) + ev->len > (size_t)sz)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!ev->mask)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Find base path for this event */
|
||||||
|
iwp = iwatch_find_by_wd(&iw_cgroup, ev->wd);
|
||||||
|
if (!iwp || !iwp->path)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
cgroup_handle_event(iwp->path, ev->mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_AUTO_RELOAD
|
||||||
|
if (conf_any_change())
|
||||||
|
service_reload_dynamic();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct cg *cgroup_find(char *name)
|
||||||
|
{
|
||||||
|
struct cg *cg;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(cg, &cgroups, link) {
|
||||||
|
if (strcmp(cg->name, name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return cg;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Marks all unprotected cgroups for deletion (during reload)
|
||||||
|
*/
|
||||||
|
void cgroup_mark_all(void)
|
||||||
|
{
|
||||||
|
struct cg *cg;
|
||||||
|
|
||||||
|
if (!avail)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(cg, &cgroups, link) {
|
||||||
|
if (cg->is_protected)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
cg->active = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove (try to) all unused cgroups
|
||||||
|
*/
|
||||||
|
void cgroup_cleanup(void)
|
||||||
|
{
|
||||||
|
struct cg *cg, *tmp;
|
||||||
|
char path[256];
|
||||||
|
|
||||||
|
if (!avail)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TAILQ_FOREACH_SAFE(cg, &cgroups, link, tmp) {
|
||||||
|
if (cg->active)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), FINIT_CGPATH "/%s", cg->name);
|
||||||
|
cgroup_del(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add, or update, settings for top-level cgroup
|
||||||
|
*/
|
||||||
|
int cgroup_add(char *name, char *cfg, int is_protected)
|
||||||
|
{
|
||||||
|
struct cg *cg;
|
||||||
|
|
||||||
|
if (!avail)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
return -1;
|
||||||
|
if (!cfg)
|
||||||
|
cfg = "";
|
||||||
|
|
||||||
|
cg = cgroup_find(name);
|
||||||
|
if (!cg) {
|
||||||
|
cg = malloc(sizeof(struct cg));
|
||||||
|
if (!cg) {
|
||||||
|
_pe("Failed allocating 'struct cg' for %s", name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
cg->name = strdup(name);
|
||||||
|
if (!cg->name) {
|
||||||
|
_pe("Failed setting cgroup name %s", name);
|
||||||
|
free(cg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
TAILQ_INSERT_TAIL(&cgroups, cg, link);
|
||||||
|
} else
|
||||||
|
free(cg->cfg);
|
||||||
|
|
||||||
|
cg->cfg = strdup(cfg);
|
||||||
|
if (!cg->cfg) {
|
||||||
|
_pe("Failed add/update of cgroup %s", name);
|
||||||
|
TAILQ_REMOVE(&cgroups, cg, link);
|
||||||
|
free(cg->name);
|
||||||
|
free(cg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
cg->is_protected = is_protected;
|
||||||
|
cg->active = 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove inactive top-level cgroup
|
||||||
|
*/
|
||||||
|
int cgroup_del(char *dir)
|
||||||
|
{
|
||||||
|
struct cg *cg;
|
||||||
|
char path[256];
|
||||||
|
|
||||||
|
if (!avail)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(cg, &cgroups, link) {
|
||||||
|
snprintf(path, sizeof(path), FINIT_CGPATH "/%s", cg->name);
|
||||||
|
if (strcmp(path, dir))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (cg->active)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rmdir(dir) && errno != ENOENT) {
|
||||||
|
_d("Failed removing %s: %s", dir, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cg) {
|
||||||
|
TAILQ_REMOVE(&cgroups, cg, link);
|
||||||
|
free(cg->name);
|
||||||
|
free(cg->cfg);
|
||||||
|
free(cg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the top-level init cgroup is a leaf, that's ensured in cgroup_init() */
|
||||||
|
void cgroup_config(void)
|
||||||
|
{
|
||||||
|
struct cg *cg;
|
||||||
|
|
||||||
|
if (!avail)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(cg, &cgroups, link) {
|
||||||
|
char path[256];
|
||||||
|
int leaf = 0;
|
||||||
|
|
||||||
|
if (!cg->active)
|
||||||
|
continue;
|
||||||
|
if (!strcmp(cg->name, "init"))
|
||||||
|
leaf = 1; /* reserved */
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "%s/%s", FINIT_CGPATH, cg->name);
|
||||||
|
group_init(path, leaf, cg->cfg);
|
||||||
|
|
||||||
|
strlcat(path, "/cgroup.events", sizeof(path));
|
||||||
|
iwatch_add(&iw_cgroup, path, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called by Finit at early boot to mount initial cgroups
|
||||||
|
*/
|
||||||
|
void cgroup_init(uev_ctx_t *ctx)
|
||||||
|
{
|
||||||
|
int opts = MS_NODEV | MS_NOEXEC | MS_NOSUID;
|
||||||
|
char buf[80];
|
||||||
|
FILE *fp;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if (mount("none", FINIT_CGPATH, "cgroup2", opts, NULL)) {
|
||||||
|
if (errno == ENOENT)
|
||||||
|
logit(LOG_NOTICE, "Kernel does not support cgroups v2, disabling.");
|
||||||
|
else
|
||||||
|
_pe("Failed mounting cgroup v2, disabling.");
|
||||||
|
avail = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
avail = 1;
|
||||||
|
|
||||||
|
/* Find available controllers */
|
||||||
|
fp = fopen(FINIT_CGPATH "/cgroup.controllers", "r");
|
||||||
|
if (!fp) {
|
||||||
|
_pe("Failed opening %s", FINIT_CGPATH "/cgroup.controllers");
|
||||||
|
umount(FINIT_CGPATH);
|
||||||
|
avail = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
char *cgroup;
|
||||||
|
|
||||||
|
cgroup = strtok(chomp(buf), "\t ");
|
||||||
|
while (cgroup) {
|
||||||
|
append_ctrl(cgroup);
|
||||||
|
cgroup = strtok(NULL, "\t ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
/* Enable all controllers */
|
||||||
|
if (fnwrite(controllers, FINIT_CGPATH "/cgroup.subtree_control"))
|
||||||
|
_pe("Failed enabling %s for %s", controllers, FINIT_CGPATH "/cgroup.subtree_control");
|
||||||
|
|
||||||
|
/* Default (protected) groups, PID 1, services, and user/login processes */
|
||||||
|
cgroup_add("init", "cpu.weight:100", 1);
|
||||||
|
cgroup_add("system", "cpu.weight:9800", 1);
|
||||||
|
cgroup_add("user", "cpu.weight:100", 1);
|
||||||
|
cgroup_config();
|
||||||
|
|
||||||
|
/* Move ourselves to init (best effort, otherwise run in 'root' group */
|
||||||
|
if (fnwrite("1", FINIT_CGPATH "/init/cgroup.procs"))
|
||||||
|
_pe("Failed moving PID 1 to cgroup ", FINIT_CGPATH "/init");
|
||||||
|
|
||||||
|
/* prepare cgroup.events watcher */
|
||||||
|
fd = iwatch_init(&iw_cgroup);
|
||||||
|
if (uev_io_init(ctx, &cgw, cgroup_events_cb, NULL, fd, UEV_READ)) {
|
||||||
|
_pe("Failed setting up cgroup.events watcher");
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+17
-3
@@ -24,9 +24,23 @@
|
|||||||
#ifndef FINIT_CGROUP_H_
|
#ifndef FINIT_CGROUP_H_
|
||||||
#define FINIT_CGROUP_H_
|
#define FINIT_CGROUP_H_
|
||||||
|
|
||||||
void cgroup_init (void);
|
#include <uev/uev.h>
|
||||||
|
|
||||||
int cgroup_user (char *name);
|
struct cgroup {
|
||||||
int cgroup_service (char *cmd, char *id, int pid);
|
char name[16];
|
||||||
|
char cfg[128];
|
||||||
|
};
|
||||||
|
|
||||||
|
void cgroup_mark_all(void);
|
||||||
|
void cgroup_cleanup (void);
|
||||||
|
|
||||||
|
int cgroup_add (char *name, char *cfg, int is_protected);
|
||||||
|
int cgroup_del (char *dir);
|
||||||
|
void cgroup_config (void);
|
||||||
|
|
||||||
|
void cgroup_init (uev_ctx_t *ctx);
|
||||||
|
|
||||||
|
int cgroup_user (char *name, int pid);
|
||||||
|
int cgroup_service (char *name, int pid, struct cgroup *cg);
|
||||||
|
|
||||||
#endif /* FINIT_CGROUP_H_ */
|
#endif /* FINIT_CGROUP_H_ */
|
||||||
|
|||||||
+662
@@ -0,0 +1,662 @@
|
|||||||
|
/* New client tool, replaces old /dev/initctl API and telinit tool
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <search.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
#include <sys/sysinfo.h> /* sysinfo() */
|
||||||
|
|
||||||
|
#include "cgutil.h"
|
||||||
|
#include "initctl.h"
|
||||||
|
|
||||||
|
#define CDIM plain ? "" : "\e[2m"
|
||||||
|
#define CRST plain ? "" : "\e[0m"
|
||||||
|
|
||||||
|
#define NONE " "
|
||||||
|
#define PIPE plain ? "| " : "│ "
|
||||||
|
#define FORK plain ? "|-" : "├─"
|
||||||
|
#define END plain ? "`-" : "└─"
|
||||||
|
|
||||||
|
uint64_t total_ram; /* From sysinfo() */
|
||||||
|
|
||||||
|
struct cg dummy; /* empty result "NULL" */
|
||||||
|
struct cg *list;
|
||||||
|
|
||||||
|
int cgroup_avail(void)
|
||||||
|
{
|
||||||
|
return fismnt(FINIT_CGPATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *pid_cmdline(int pid, char *buf, size_t len)
|
||||||
|
{
|
||||||
|
size_t i, sz;
|
||||||
|
char *ptr;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopenf("r", "/proc/%d/cmdline", pid);
|
||||||
|
if (!fp) {
|
||||||
|
buf[0] = 0;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
sz = fread(buf, sizeof(buf[0]), len - 1, fp);
|
||||||
|
fclose(fp);
|
||||||
|
if (!sz)
|
||||||
|
return NULL; /* kernel thread */
|
||||||
|
|
||||||
|
buf[sz] = 0;
|
||||||
|
|
||||||
|
ptr = strchr(buf, 0);
|
||||||
|
if (ptr && ptr != buf) {
|
||||||
|
ptr++;
|
||||||
|
sz -= ptr - buf;
|
||||||
|
memmove(buf, ptr, sz + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < sz; i++) {
|
||||||
|
if (buf[i] == 0)
|
||||||
|
buf[i] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *pid_comm(int pid, char *buf, size_t len)
|
||||||
|
{
|
||||||
|
char *ptr = NULL;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopenf("r", "/proc/%d/comm", pid);
|
||||||
|
if (!fp)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (fgets(buf, len, fp))
|
||||||
|
ptr = chomp(buf);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *pid_cgroup(int pid, char *buf, size_t len)
|
||||||
|
{
|
||||||
|
char *ptr = NULL;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopenf("r", "/proc/%d/cgroup", pid);
|
||||||
|
if (!fp)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (fgets(buf, len, fp))
|
||||||
|
ptr = chomp(buf);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
if (ptr)
|
||||||
|
ptr = strchr(buf, '/');
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *cgroup_val(char *path, char *file, char *buf, size_t len)
|
||||||
|
{
|
||||||
|
char *val = NULL;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopenf("r", "%s/%s", path, file);
|
||||||
|
if (fp) {
|
||||||
|
if (fgets(buf, len, fp)) {
|
||||||
|
val = chomp(buf);
|
||||||
|
len = strcspn(val, " \t");
|
||||||
|
val[len] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t cgroup_uint64(char *path, char *file)
|
||||||
|
{
|
||||||
|
uint64_t val = 0;
|
||||||
|
char buf[42];
|
||||||
|
|
||||||
|
if (cgroup_val(path, file, buf, sizeof(buf)))
|
||||||
|
val = strtoull(buf, NULL, 10);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *cgroup_memval(char *path, char *file, char *buf, size_t len)
|
||||||
|
{
|
||||||
|
char data[42];
|
||||||
|
|
||||||
|
if (cgroup_val(path, file, data, sizeof(data))) {
|
||||||
|
if (!strcmp(data, "max"))
|
||||||
|
strlcpy(buf, data, len);
|
||||||
|
else
|
||||||
|
memsz(strtoull(data, NULL, 10), buf, len);
|
||||||
|
} else
|
||||||
|
buf[0] = 0;
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t cgroup_memuse(struct cg *cg)
|
||||||
|
{
|
||||||
|
char buf[42];
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopenf("r", "%s/memory.stat", cg->cg_path);
|
||||||
|
if (fp) {
|
||||||
|
cg->cg_rss = 0;
|
||||||
|
cg->cg_vmlib = 0;
|
||||||
|
|
||||||
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
chomp(buf);
|
||||||
|
|
||||||
|
if (!strncmp(buf, "anon", 4)) {
|
||||||
|
cg->cg_rss += strtoull(&buf[5], NULL, 10);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strncmp(buf, "slab", 4)) {
|
||||||
|
cg->cg_rss += strtoull(&buf[5], NULL, 10);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strncmp(buf, "kernel_stack", 12)) {
|
||||||
|
cg->cg_rss += strtoull(&buf[5], NULL, 10);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strncmp(buf, "pagetables", 10)) {
|
||||||
|
cg->cg_rss += strtoull(&buf[5], NULL, 10);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strncmp(buf, "percpu", 6)) {
|
||||||
|
cg->cg_rss += strtoull(&buf[5], NULL, 10);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strncmp(buf, "sock", 4)) {
|
||||||
|
cg->cg_rss += strtoull(&buf[5], NULL, 10);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strncmp(buf, "file", 4)) {
|
||||||
|
cg->cg_vmlib += strtoull(&buf[5], NULL, 10);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strncmp(buf, "file_mapped", 11)) {
|
||||||
|
cg->cg_vmlib += strtoull(&buf[5], NULL, 10);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
cg->cg_memshare = (float)(cg->cg_rss * 100 / total_ram);
|
||||||
|
|
||||||
|
return cg->cg_vmsize = cgroup_uint64(cg->cg_path, "memory.current");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t cgroup_memory(char *group)
|
||||||
|
{
|
||||||
|
char path[256];
|
||||||
|
|
||||||
|
paste(path, sizeof(path), FINIT_CGPATH, group);
|
||||||
|
|
||||||
|
return cgroup_uint64(path, "memory.current");
|
||||||
|
}
|
||||||
|
|
||||||
|
static float cgroup_cpuload(struct cg *cg)
|
||||||
|
{
|
||||||
|
char fn[256];
|
||||||
|
char buf[64];
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
snprintf(fn, sizeof(fn), "%s/cpu.stat", cg->cg_path);
|
||||||
|
fp = fopen(fn, "r");
|
||||||
|
if (!fp)
|
||||||
|
err(1, "Cannot open %s", fn);
|
||||||
|
|
||||||
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
uint64_t curr;
|
||||||
|
|
||||||
|
chomp(buf);
|
||||||
|
if (strncmp(buf, "usage_usec", 10))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
curr = strtoull(&buf[11], NULL, 10);
|
||||||
|
if (cg->cg_prev != 0) {
|
||||||
|
uint64_t diff = curr - cg->cg_prev;
|
||||||
|
|
||||||
|
/* this expects 1 sec poll interval */
|
||||||
|
cg->cg_load = (float)(diff / 1000000);
|
||||||
|
cg->cg_load *= 100.0;
|
||||||
|
}
|
||||||
|
cg->cg_prev = curr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return cg->cg_load;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct cg *append(char *path)
|
||||||
|
{
|
||||||
|
struct cg *cg;
|
||||||
|
char fn[256];
|
||||||
|
ENTRY item;
|
||||||
|
|
||||||
|
snprintf(fn, sizeof(fn), "%s/cpu.stat", path);
|
||||||
|
if (access(fn, F_OK)) {
|
||||||
|
/* older kernels, 4.19, don't have summary cpu.stat in root */
|
||||||
|
if (strcmp(path, FINIT_CGPATH))
|
||||||
|
warn("not a cgroup path with cpu controller, %s", path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cg = calloc(1, sizeof(struct cg));
|
||||||
|
if (!cg)
|
||||||
|
err(1, "failed allocating struct cg");
|
||||||
|
|
||||||
|
cg->cg_path = strdup(path);
|
||||||
|
if (list)
|
||||||
|
cg->cg_next = list;
|
||||||
|
list = cg;
|
||||||
|
|
||||||
|
item.key = cg->cg_path;
|
||||||
|
item.data = cg;
|
||||||
|
if (!hsearch(item, ENTER))
|
||||||
|
err(1, "failed adding to hash table");
|
||||||
|
|
||||||
|
return cg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct cg *find(char *path)
|
||||||
|
{
|
||||||
|
ENTRY *ep, item = { path, NULL };
|
||||||
|
|
||||||
|
ep = hsearch(item, FIND);
|
||||||
|
if (ep)
|
||||||
|
return ep->data;
|
||||||
|
|
||||||
|
return append(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update stats */
|
||||||
|
struct cg *cg_stats(char *path)
|
||||||
|
{
|
||||||
|
struct cg *cg;
|
||||||
|
|
||||||
|
cg = find(path);
|
||||||
|
if (!cg)
|
||||||
|
return &dummy;
|
||||||
|
|
||||||
|
cgroup_cpuload(cg);
|
||||||
|
cgroup_memuse(cg);
|
||||||
|
|
||||||
|
return cg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* query config */
|
||||||
|
struct cg *cg_conf(char *path)
|
||||||
|
{
|
||||||
|
static struct cg cg;
|
||||||
|
|
||||||
|
cgroup_val(path, "memory.min", cg.cg_mem.min, sizeof(cg.cg_mem.min));
|
||||||
|
cgroup_memval(path, "memory.max", cg.cg_mem.max, sizeof(cg.cg_mem.max));
|
||||||
|
cgroup_val(path, "cpu.weight", cg.cg_cpu.weight, sizeof(cg.cg_cpu.weight));
|
||||||
|
cgroup_val(path, "cpu.max", cg.cg_cpu.max, sizeof(cg.cg_cpu.max));
|
||||||
|
cgroup_val(path, "cpuset.cpus.effective", cg.cg_cpu.set, sizeof(cg.cg_cpu.set));
|
||||||
|
cg.cg_vmsize = cgroup_uint64(path, "memory.current");
|
||||||
|
|
||||||
|
return &cg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cgroup_filter(const struct dirent *entry)
|
||||||
|
{
|
||||||
|
/* Skip current dir ".", and prev dir "..", from list of files */
|
||||||
|
if ((1 == strlen(entry->d_name) && entry->d_name[0] == '.') ||
|
||||||
|
(2 == strlen(entry->d_name) && !strcmp(entry->d_name, "..")))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (entry->d_name[0] == '.')
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (entry->d_type != DT_DIR)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cgroup_tree(char *path, char *pfx, int mode, int pos)
|
||||||
|
{
|
||||||
|
struct dirent **namelist = NULL;
|
||||||
|
char s[32], r[32], l[32];
|
||||||
|
char row[ttcols + 9]; /* + control codes */
|
||||||
|
size_t rlen = sizeof(row) - 1;
|
||||||
|
size_t rplen = rlen - 9;
|
||||||
|
struct stat st;
|
||||||
|
struct cg *cg;
|
||||||
|
char buf[512];
|
||||||
|
int rc = 0;
|
||||||
|
FILE *fp;
|
||||||
|
int i, n;
|
||||||
|
int num;
|
||||||
|
|
||||||
|
if (pos >= ttrows)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (-1 == lstat(path, &st))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if ((st.st_mode & S_IFMT) != S_IFDIR) {
|
||||||
|
errno = ENOTDIR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp = fopenf("r", "%s/cgroup.procs", path);
|
||||||
|
if (!fp)
|
||||||
|
return -1;
|
||||||
|
num = 0;
|
||||||
|
while (fgets(buf, sizeof(buf), fp))
|
||||||
|
num++;
|
||||||
|
|
||||||
|
if (!pfx) {
|
||||||
|
pfx = "";
|
||||||
|
switch (mode) {
|
||||||
|
case 1:
|
||||||
|
cg = cg_stats(path);
|
||||||
|
snprintf(row, rplen, "\r %6.6s %6.6s %6.6s %5.1f %5.1f %s",
|
||||||
|
memsz(cg->cg_vmsize, s, sizeof(s)),
|
||||||
|
memsz(cg->cg_rss, r, sizeof(r)),
|
||||||
|
memsz(cg->cg_vmlib, l, sizeof(l)),
|
||||||
|
cg->cg_memshare, cg->cg_load, path);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
cg = cg_conf(path);
|
||||||
|
snprintf(row, rplen, "\r%6.6s [%-6.6s%6.6s] %6s [%-6.6s%6.6s] %s",
|
||||||
|
memsz(cg->cg_vmsize, s, sizeof(s)),
|
||||||
|
cg->cg_mem.min, cg->cg_mem.max, cg->cg_cpu.set,
|
||||||
|
cg->cg_cpu.weight, cg->cg_cpu.max, path);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
strlcpy(row, "\r", rplen);
|
||||||
|
strlcat(row, path, rplen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
puts(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num > 0) {
|
||||||
|
rewind(fp);
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
char comm[80] = { 0 };
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
pid = atoi(chomp(buf));
|
||||||
|
if (pid <= 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* skip kernel threads for now (no cmdline) */
|
||||||
|
pid_comm(pid, comm, sizeof(comm));
|
||||||
|
if (pid_cmdline(pid, buf, sizeof(buf))) {
|
||||||
|
char proc[ttcols];
|
||||||
|
int len;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case 1:
|
||||||
|
snprintf(row, rplen, "\r%37s", " ");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
snprintf(row, rplen, "\r --.-- [ ] [ ] ");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
strlcpy(row, "\r", rplen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
strlcat(row, pfx, rplen);
|
||||||
|
strlcat(row, ++i == num ? END : FORK, rlen);
|
||||||
|
|
||||||
|
snprintf(proc, sizeof(proc), " %d %s %s", pid, comm, buf);
|
||||||
|
|
||||||
|
if (plain) {
|
||||||
|
strlcat(row, proc, rplen);
|
||||||
|
} else {
|
||||||
|
strlcat(row, CDIM, rlen);
|
||||||
|
strlcat(row, proc, rlen);
|
||||||
|
|
||||||
|
len = strlen(row) + strlen(CRST);
|
||||||
|
if (len > (int)rlen)
|
||||||
|
row[rlen - strlen(CRST)] = 0;
|
||||||
|
|
||||||
|
strlcat(row, CRST, sizeof(row));
|
||||||
|
}
|
||||||
|
|
||||||
|
puts(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == 1) {
|
||||||
|
pos += i;
|
||||||
|
if (pos >= ttrows)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
n = scandir(path, &namelist, cgroup_filter, alphasort);
|
||||||
|
if (n > 0) {
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
char *nm = namelist[i]->d_name;
|
||||||
|
char prefix[80];
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf), "%s/%s", path, nm);
|
||||||
|
switch (mode) {
|
||||||
|
case 1:
|
||||||
|
cg = cg_stats(buf);
|
||||||
|
snprintf(row, rplen,
|
||||||
|
"\r %6.6s %6.6s %6.6s %5.1f %5.1f ",
|
||||||
|
memsz(cg->cg_vmsize, s, sizeof(s)),
|
||||||
|
memsz(cg->cg_rss, r, sizeof(r)),
|
||||||
|
memsz(cg->cg_vmlib, l, sizeof(l)),
|
||||||
|
cg->cg_memshare, cg->cg_load);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
cg = cg_conf(buf);
|
||||||
|
snprintf(row, rplen, "\r%6.6s [%-6.6s%6.6s] %6.6s [%-6.6s%6.6s] ",
|
||||||
|
memsz(cg->cg_vmsize, s, sizeof(s)),
|
||||||
|
cg->cg_mem.min, cg->cg_mem.max,
|
||||||
|
cg->cg_cpu.set, cg->cg_cpu.weight, cg->cg_cpu.max);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
strlcpy(row, "\r", rplen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
strlcat(row, pfx, rplen);
|
||||||
|
if (i + 1 == n) {
|
||||||
|
strlcat(row, END, rplen);
|
||||||
|
snprintf(prefix, sizeof(prefix), "%s ", pfx);
|
||||||
|
} else {
|
||||||
|
strlcat(row, FORK, rplen);
|
||||||
|
snprintf(prefix, sizeof(prefix), "%s%s ", pfx, PIPE);
|
||||||
|
}
|
||||||
|
strlcat(row, " ", rplen);
|
||||||
|
|
||||||
|
strlcat(row, nm, rplen);
|
||||||
|
strlcat(row, "/ ", rplen);
|
||||||
|
|
||||||
|
puts(row);
|
||||||
|
|
||||||
|
rc += cgroup_tree(buf, prefix, mode, pos + i);
|
||||||
|
|
||||||
|
free(namelist[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(namelist);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int show_cgps(char *arg)
|
||||||
|
{
|
||||||
|
char path[512];
|
||||||
|
|
||||||
|
if (!arg)
|
||||||
|
arg = FINIT_CGPATH;
|
||||||
|
else if (arg[0] != '/') {
|
||||||
|
paste(path, sizeof(path), FINIT_CGPATH, arg);
|
||||||
|
arg = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cgroup_tree(arg, NULL, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cgtop(uev_t *w, void *arg, int events)
|
||||||
|
{
|
||||||
|
(void)w;
|
||||||
|
(void)events;
|
||||||
|
|
||||||
|
fputs("\e[2J\e[1;1H", stdout);
|
||||||
|
if (heading)
|
||||||
|
print_header(" VmSIZE RSS VmLIB %%MEM %%CPU GROUP");
|
||||||
|
cgroup_tree(arg, NULL, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cleanup(void)
|
||||||
|
{
|
||||||
|
ttcooked();
|
||||||
|
showcursor();
|
||||||
|
puts("");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void leave(uev_t *w, void *arg, int events)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
(void)events;
|
||||||
|
|
||||||
|
uev_exit(w->ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void key(uev_t *w, void *arg, int events)
|
||||||
|
{
|
||||||
|
char ch;
|
||||||
|
|
||||||
|
(void)arg;
|
||||||
|
(void)events;
|
||||||
|
|
||||||
|
if (read(w->fd, &ch, sizeof(ch)) != -1) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'q':
|
||||||
|
uev_exit(w->ctx);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
dbg("Got char 0x%02x", ch);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int show_cgtop(char *arg)
|
||||||
|
{
|
||||||
|
struct sysinfo si = { 0 };
|
||||||
|
uev_t timer, input, sigint, sigterm, sigquit;
|
||||||
|
char path[512];
|
||||||
|
uev_ctx_t ctx;
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
if (!arg)
|
||||||
|
arg = FINIT_CGPATH;
|
||||||
|
else if (arg[0] != '/') {
|
||||||
|
paste(path, sizeof(path), FINIT_CGPATH, arg);
|
||||||
|
arg = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hcreate(ttrows + 25))
|
||||||
|
err(1, "failed creating hash table");
|
||||||
|
|
||||||
|
sysinfo(&si);
|
||||||
|
total_ram = si.totalram * si.mem_unit;
|
||||||
|
|
||||||
|
uev_init(&ctx);
|
||||||
|
uev_timer_init(&ctx, &timer, cgtop, arg, 1, ionce ? 0 : 1000);
|
||||||
|
|
||||||
|
if (!ionce && !plain) {
|
||||||
|
atexit(cleanup);
|
||||||
|
ttraw();
|
||||||
|
hidecursor();
|
||||||
|
|
||||||
|
flags = fcntl(STDIN_FILENO, F_GETFL);
|
||||||
|
if (flags != -1)
|
||||||
|
(void)fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
|
||||||
|
(void)uev_io_init(&ctx, &input, key, NULL, STDIN_FILENO, UEV_READ);
|
||||||
|
|
||||||
|
(void)uev_signal_init(&ctx, &sigint, leave, NULL, SIGINT);
|
||||||
|
(void)uev_signal_init(&ctx, &sigterm, leave, NULL, SIGTERM);
|
||||||
|
(void)uev_signal_init(&ctx, &sigquit, leave, NULL, SIGQUIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return uev_run(&ctx, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int show_cgroup(char *arg)
|
||||||
|
{
|
||||||
|
char path[512];
|
||||||
|
|
||||||
|
if (!arg)
|
||||||
|
arg = FINIT_CGPATH;
|
||||||
|
else if (arg[0] != '/') {
|
||||||
|
paste(path, sizeof(path), FINIT_CGPATH, arg);
|
||||||
|
arg = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* memory.current memory.min memory.max cpuset.cpus cpu.weight cpu.max */
|
||||||
|
if (heading)
|
||||||
|
print_header(" MEM [MIN MAX] CPU [WEIGHT MAX] GROUP");
|
||||||
|
|
||||||
|
return cgroup_tree(arg, NULL, 2, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Variables:
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/* Cgroup utility functions for initctl
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FINIT_CGUTIL_H_
|
||||||
|
#define FINIT_CGUTIL_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
struct cg {
|
||||||
|
struct cg *cg_next;
|
||||||
|
|
||||||
|
/* stats */
|
||||||
|
char *cg_path; /* path in /sys/fs/cgroup */
|
||||||
|
uint64_t cg_prev; /* cpuacct.usage */
|
||||||
|
uint64_t cg_rss; /* memory.stat */
|
||||||
|
uint64_t cg_vmlib; /* memory.stat */
|
||||||
|
uint64_t cg_vmsize; /* memory.current */
|
||||||
|
float cg_memshare; /* cg_rss / total_ram * 100 */
|
||||||
|
float cg_load; /* curr - prev / 10000000.0 */
|
||||||
|
|
||||||
|
/* config */
|
||||||
|
struct {
|
||||||
|
char min[32];
|
||||||
|
char max[32];
|
||||||
|
} cg_mem;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
char set[16];
|
||||||
|
char weight[32];
|
||||||
|
char max[32];
|
||||||
|
} cg_cpu;
|
||||||
|
};
|
||||||
|
|
||||||
|
int cgroup_avail(void);
|
||||||
|
|
||||||
|
char *pid_cmdline (int pid, char *buf, size_t len);
|
||||||
|
char *pid_comm (int pid, char *buf, size_t len);
|
||||||
|
char *pid_cgroup (int pid, char *buf, size_t len);
|
||||||
|
|
||||||
|
uint64_t cgroup_memory(char *group);
|
||||||
|
|
||||||
|
struct cg *cg_stats(char *path);
|
||||||
|
struct cg *cg_conf (char *path);
|
||||||
|
|
||||||
|
int cgroup_tree (char *path, char *pfx, int mode, int pos);
|
||||||
|
|
||||||
|
int show_cgroup (char *arg);
|
||||||
|
int show_cgtop (char *arg);
|
||||||
|
int show_cgps (char *arg);
|
||||||
|
|
||||||
|
#endif /* FINIT_CGUTIL_H_ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Variables:
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
+34
-16
@@ -21,7 +21,9 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <poll.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
|
||||||
@@ -36,19 +38,14 @@ int client_connect(void)
|
|||||||
.sun_path = INIT_SOCKET,
|
.sun_path = INIT_SOCKET,
|
||||||
};
|
};
|
||||||
|
|
||||||
sd = socket(AF_UNIX, SOCK_STREAM, 0);
|
sd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
|
||||||
if (-1 == sd)
|
if (-1 == sd)
|
||||||
goto error;
|
err(1, "Failed creating UNIX domain socket");
|
||||||
|
|
||||||
if (connect(sd, (struct sockaddr*)&sun, sizeof(sun)) == -1) {
|
if (connect(sd, (struct sockaddr*)&sun, sizeof(sun)) == -1)
|
||||||
close(sd);
|
err(1, "Failed connecting to finit");
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sd;
|
return sd;
|
||||||
error:
|
|
||||||
perror("Failed connecting to finit");
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int client_disconnect(void)
|
int client_disconnect(void)
|
||||||
@@ -68,27 +65,48 @@ int client_disconnect(void)
|
|||||||
|
|
||||||
int client_send(struct init_request *rq, ssize_t len)
|
int client_send(struct init_request *rq, ssize_t len)
|
||||||
{
|
{
|
||||||
|
struct pollfd pfd = { 0 };
|
||||||
int sd, result = 255;
|
int sd, result = 255;
|
||||||
|
int rc;
|
||||||
|
|
||||||
sd = client_connect();
|
sd = client_connect();
|
||||||
if (-1 == sd)
|
if (-1 == sd)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (write(sd, rq, len) != len)
|
pfd.fd = sd;
|
||||||
goto error;
|
pfd.events = POLLOUT;
|
||||||
|
if (poll(&pfd, 1, 2000) <= 0) {
|
||||||
|
warn("Timed out waiting for Finit, errno %d", errno);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
if (read(sd, rq, len) != len)
|
if (write(sd, rq, len) != len) {
|
||||||
goto error;
|
warn("Failed communicating with Finit, errno %d", errno);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
pfd.fd = sd;
|
||||||
|
pfd.events = POLLIN;
|
||||||
|
if ((rc = poll(&pfd, 1, 2000)) <= 0) {
|
||||||
|
if (rc)
|
||||||
|
warn("poll(), errno %d", errno);
|
||||||
|
else
|
||||||
|
warnx("Timed out waiting for reply from Finit.");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read(sd, rq, len) != len) {
|
||||||
|
warn("Failed reading reply from Finit, errno %d", errno);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
if (rq->cmd == INIT_CMD_NACK)
|
if (rq->cmd == INIT_CMD_NACK)
|
||||||
result = 1;
|
result = 1;
|
||||||
else
|
else
|
||||||
result = 0;
|
result = 0;
|
||||||
goto exit;
|
|
||||||
error:
|
|
||||||
perror("Failed communicating with finit");
|
|
||||||
exit:
|
exit:
|
||||||
client_disconnect();
|
client_disconnect();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+98
-35
@@ -23,8 +23,12 @@
|
|||||||
|
|
||||||
#include <ftw.h>
|
#include <ftw.h>
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <lite/lite.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
@@ -99,13 +103,14 @@ static void cond_bump_reconf(void)
|
|||||||
unsigned int rgen;
|
unsigned int rgen;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If %COND_RECONF does not exist, cond_get_gen() returns 0
|
* If %_PATH_RECONF does not exist, cond_get_gen() returns 0
|
||||||
* meaning that rgen++ is always what we want.
|
* meaning that rgen++ is always what we want.
|
||||||
*/
|
*/
|
||||||
rgen = cond_get_gen(COND_RECONF);
|
rgen = cond_get_gen(_PATH_RECONF);
|
||||||
rgen++;
|
rgen++;
|
||||||
|
|
||||||
cond_set_gen(COND_RECONF, rgen);
|
if (cond_set_gen(_PATH_RECONF, rgen))
|
||||||
|
_pe("Failed setting %s to gen %d", _PATH_RECONF, rgen);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cond_checkpath(const char *path)
|
static int cond_checkpath(const char *path)
|
||||||
@@ -119,7 +124,7 @@ static int cond_checkpath(const char *path)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (makepath(dir) && errno != EEXIST) {
|
if (mkpath(dir, 0755) && errno != EEXIST) {
|
||||||
_pe("Failed creating dir '%s' for condition '%s'", dir, path);
|
_pe("Failed creating dir '%s' for condition '%s'", dir, path);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -127,22 +132,22 @@ static int cond_checkpath(const char *path)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cond_set_path(const char *path, enum cond_state new)
|
int cond_set_path(const char *path, enum cond_state next)
|
||||||
{
|
{
|
||||||
enum cond_state old;
|
enum cond_state prev;
|
||||||
unsigned int rgen;
|
unsigned int rgen;
|
||||||
|
|
||||||
_d("%s", path);
|
_d("%s <= %d", path, next);
|
||||||
|
|
||||||
rgen = cond_get_gen(COND_RECONF);
|
rgen = cond_get_gen(_PATH_RECONF);
|
||||||
if (!rgen) {
|
if (!rgen) {
|
||||||
_e("Unable to read configuration generation (%s)", path);
|
_e("Unable to read configuration generation (%s)", path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
old = cond_get_path(path);
|
prev = cond_get_path(path);
|
||||||
|
|
||||||
switch (new) {
|
switch (next) {
|
||||||
case COND_ON:
|
case COND_ON:
|
||||||
if (cond_checkpath(path))
|
if (cond_checkpath(path))
|
||||||
return 0;
|
return 0;
|
||||||
@@ -159,59 +164,95 @@ int cond_set_path(const char *path, enum cond_state new)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new != old;
|
return next != prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cond_update(const char *name)
|
/* Should only be used by cond_set*(), cond_clear(), and usr/sys plugins! */
|
||||||
|
int cond_update(const char *name)
|
||||||
{
|
{
|
||||||
svc_t *svc, *iter = NULL;
|
svc_t *svc, *iter = NULL;
|
||||||
|
int affects = 0;
|
||||||
|
|
||||||
_d("%s", name);
|
_d("%s", name);
|
||||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
if (!svc_has_cond(svc) || !cond_affects(name, svc->cond))
|
if (!svc_has_cond(svc) || !cond_affects(name, svc->cond))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
affects++;
|
||||||
_d("%s: match <%s> %s(%s)", name ?: "nil", svc->cond, svc->desc, svc->cmd);
|
_d("%s: match <%s> %s(%s)", name ?: "nil", svc->cond, svc->desc, svc->cmd);
|
||||||
service_step(svc);
|
service_step(svc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return affects;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cond_set_noupdate(const char *name)
|
||||||
|
{
|
||||||
|
_d("%s", name);
|
||||||
|
if (string_compare(name, "nop"))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!cond_set_path(cond_path(name), COND_ON))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cond_set(const char *name)
|
void cond_set(const char *name)
|
||||||
{
|
{
|
||||||
_d("%s", name);
|
_d("%s", name);
|
||||||
if (string_compare(name, "nop"))
|
if (cond_set_noupdate(name))
|
||||||
return;
|
|
||||||
|
|
||||||
if (!cond_set_path(cond_path(name), COND_ON))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cond_update(name);
|
cond_update(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cond_set_oneshot(const char *name)
|
int cond_set_oneshot_noupdate(const char *name)
|
||||||
{
|
{
|
||||||
const char *path;
|
const char *path;
|
||||||
|
|
||||||
if (string_compare(name, "nop"))
|
if (string_compare(name, "nop"))
|
||||||
return;
|
return 1;
|
||||||
|
|
||||||
path = cond_path(name);
|
path = cond_path(name);
|
||||||
_d("%s => %s", name, path);
|
_d("%s => %s", name, path);
|
||||||
|
|
||||||
if (cond_checkpath(path))
|
if (cond_checkpath(path))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (symlink(_PATH_RECONF, path) && errno != EEXIST) {
|
||||||
|
_pe("Failed creating onshot cond %s", name);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cond_set_oneshot(const char *name)
|
||||||
|
{
|
||||||
|
_d("%s", name);
|
||||||
|
if (cond_set_oneshot_noupdate(name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
symlink(COND_RECONF, path);
|
|
||||||
cond_update(name);
|
cond_update(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cond_clear_noupdate(const char *name)
|
||||||
|
{
|
||||||
|
_d("%s", name);
|
||||||
|
if (string_compare(name, "nop"))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!cond_set_path(cond_path(name), COND_OFF))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void cond_clear(const char *name)
|
void cond_clear(const char *name)
|
||||||
{
|
{
|
||||||
_d("%s", name);
|
_d("%s", name);
|
||||||
if (string_compare(name, "nop"))
|
if (cond_clear_noupdate(name))
|
||||||
return;
|
|
||||||
|
|
||||||
if (!cond_set_path(cond_path(name), COND_OFF))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cond_update(name);
|
cond_update(name);
|
||||||
@@ -224,7 +265,7 @@ void cond_reload(void)
|
|||||||
cond_bump_reconf();
|
cond_bump_reconf();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int reassert(const char *fpath, const struct stat *sb, int tflg, struct FTW *ftw)
|
static int do_assert(const char *fpath, const struct stat *sb, int tflg, struct FTW *ftw, int set)
|
||||||
{
|
{
|
||||||
char *nm;
|
char *nm;
|
||||||
|
|
||||||
@@ -234,35 +275,57 @@ static int reassert(const char *fpath, const struct stat *sb, int tflg, struct F
|
|||||||
if (tflg != FTW_F)
|
if (tflg != FTW_F)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
nm = strstr((char *)fpath, COND_DIR);
|
nm = strstr((char *)fpath, COND_BASE);
|
||||||
if (!nm) {
|
if (!nm) {
|
||||||
_e("Incorrect condtion path %s, cannot reassert", fpath);
|
_e("Incorrect condition path %s, cannot %sassert", fpath, set ? "re" : "de");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
nm += sizeof(COND_DIR);
|
nm += strlen(COND_BASE);
|
||||||
_d("Reasserting %s => %s", fpath, nm);
|
_d("%sasserting %s => %s", set ? "Re" : "De", fpath, nm);
|
||||||
cond_set(nm);
|
if (set)
|
||||||
|
cond_set(nm);
|
||||||
|
else
|
||||||
|
cond_clear_noupdate(nm); /* important, see netlink plugin! */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int reassert(const char *fpath, const struct stat *sb, int tflg, struct FTW *ftw)
|
||||||
|
{
|
||||||
|
return do_assert(fpath, sb, tflg, ftw, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int deassert(const char *fpath, const struct stat *sb, int tflg, struct FTW *ftw)
|
||||||
|
{
|
||||||
|
return do_assert(fpath, sb, tflg, ftw, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Used only by netlink plugin atm.
|
* Used only by netlink plugin atm.
|
||||||
* type: is a one of pid/, net/, etc.
|
* type: is a one of pid/, net/, etc.
|
||||||
*/
|
*/
|
||||||
void cond_reassert(const char *type)
|
void cond_reassert(const char *pat)
|
||||||
{
|
{
|
||||||
_d("%s", type);
|
_d("%s", pat);
|
||||||
nftw(cond_path(type), reassert, 20, FTW_DEPTH);
|
nftw(cond_path(pat), reassert, 20, FTW_DEPTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used only by netlink plugin atm.
|
||||||
|
*/
|
||||||
|
void cond_deassert(const char *pat)
|
||||||
|
{
|
||||||
|
_d("%s", pat);
|
||||||
|
nftw(cond_path(pat), deassert, 20, FTW_DEPTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cond_init(void)
|
void cond_init(void)
|
||||||
{
|
{
|
||||||
char path[MAX_ARG_LEN];
|
char path[MAX_ARG_LEN];
|
||||||
|
|
||||||
if (makepath(pid_runpath(COND_PATH, path, sizeof(path))) && errno != EEXIST) {
|
if (mkpath(pid_runpath(_PATH_COND, path, sizeof(path)), 0755) && errno != EEXIST) {
|
||||||
_pe("Failed creating condition base directory '%s'", COND_PATH);
|
_pe("Failed creating condition base directory '%s'", _PATH_COND);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-7
@@ -21,8 +21,12 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <lite/lite.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
@@ -45,15 +49,15 @@ const char *cond_path(const char *name)
|
|||||||
static char path[256];
|
static char path[256];
|
||||||
char tmp[MAX_ARG_LEN];
|
char tmp[MAX_ARG_LEN];
|
||||||
|
|
||||||
snprintf(tmp, sizeof(tmp), COND_PATH "/%s", name);
|
snprintf(tmp, sizeof(tmp), _PATH_COND "%s", name);
|
||||||
|
|
||||||
return pid_runpath(tmp, path, sizeof(path));
|
return pid_runpath(tmp, path, sizeof(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int cond_get_gen(const char *file)
|
unsigned int cond_get_gen(const char *file)
|
||||||
{
|
{
|
||||||
unsigned int gen;
|
|
||||||
char *ptr, path[256];
|
char *ptr, path[256];
|
||||||
|
unsigned int gen;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -74,14 +78,14 @@ enum cond_state cond_get_path(const char *path)
|
|||||||
{
|
{
|
||||||
int cgen, rgen;
|
int cgen, rgen;
|
||||||
|
|
||||||
rgen = cond_get_gen(COND_RECONF);
|
|
||||||
if (!rgen)
|
|
||||||
return COND_OFF;
|
|
||||||
|
|
||||||
cgen = cond_get_gen(path);
|
cgen = cond_get_gen(path);
|
||||||
if (!cgen)
|
if (!cgen)
|
||||||
return COND_OFF;
|
return COND_OFF;
|
||||||
|
|
||||||
|
rgen = cond_get_gen(_PATH_RECONF);
|
||||||
|
if (!rgen)
|
||||||
|
return COND_OFF;
|
||||||
|
|
||||||
return (cgen == rgen) ? COND_ON : COND_FLUX;
|
return (cgen == rgen) ? COND_ON : COND_FLUX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+20
-4
@@ -2,11 +2,19 @@
|
|||||||
#define FINIT_COND_H_
|
#define FINIT_COND_H_
|
||||||
|
|
||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
#include <svc.h>
|
|
||||||
|
|
||||||
#define COND_DIR "finit/cond"
|
#include "svc.h"
|
||||||
#define COND_PATH _PATH_VARRUN COND_DIR
|
|
||||||
#define COND_RECONF COND_PATH "/reconf"
|
#define COND_BASE "finit/cond"
|
||||||
|
#define COND_PID "pid/"
|
||||||
|
#define COND_SYS "sys/"
|
||||||
|
#define COND_USR "usr/"
|
||||||
|
|
||||||
|
#define _PATH_COND _PATH_VARRUN COND_BASE "/"
|
||||||
|
#define _PATH_CONDPID _PATH_COND COND_PID
|
||||||
|
#define _PATH_CONDSYS _PATH_COND COND_SYS
|
||||||
|
#define _PATH_CONDUSR _PATH_COND COND_USR
|
||||||
|
#define _PATH_RECONF _PATH_COND "reconf"
|
||||||
|
|
||||||
typedef enum cond_state {
|
typedef enum cond_state {
|
||||||
COND_OFF = 0,
|
COND_OFF = 0,
|
||||||
@@ -23,12 +31,20 @@ enum cond_state cond_get (const char *name);
|
|||||||
enum cond_state cond_get_agg (const char *names);
|
enum cond_state cond_get_agg (const char *names);
|
||||||
int cond_affects (const char *name, const char *names);
|
int cond_affects (const char *name, const char *names);
|
||||||
|
|
||||||
|
int cond_update (const char *name);
|
||||||
int cond_set_path (const char *path, enum cond_state new);
|
int cond_set_path (const char *path, enum cond_state new);
|
||||||
void cond_set (const char *name);
|
void cond_set (const char *name);
|
||||||
void cond_set_oneshot (const char *name);
|
void cond_set_oneshot (const char *name);
|
||||||
void cond_clear (const char *name);
|
void cond_clear (const char *name);
|
||||||
void cond_reload (void);
|
void cond_reload (void);
|
||||||
|
|
||||||
|
int cond_set_noupdate (const char *name);
|
||||||
|
int cond_set_oneshot_noupdate(const char *name);
|
||||||
|
int cond_clear_noupdate(const char *name);
|
||||||
|
|
||||||
void cond_reassert (const char *pat);
|
void cond_reassert (const char *pat);
|
||||||
|
void cond_deassert (const char *pat);
|
||||||
|
|
||||||
void cond_init (void);
|
void cond_init (void);
|
||||||
|
|
||||||
#endif /* FINIT_COND_H_ */
|
#endif /* FINIT_COND_H_ */
|
||||||
|
|||||||
+154
-43
@@ -23,18 +23,25 @@
|
|||||||
|
|
||||||
#include "config.h" /* Generated by configure script */
|
#include "config.h" /* Generated by configure script */
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/inotify.h>
|
#include <sys/inotify.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
#include <lite/queue.h> /* BSD sys/queue.h API */
|
# include <libite/lite.h>
|
||||||
|
# include <libite/queue.h> /* BSD sys/queue.h API */
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
# include <lite/queue.h> /* BSD sys/queue.h API */
|
||||||
|
#endif
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <glob.h>
|
#include <glob.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
#include "iwatch.h"
|
#include "iwatch.h"
|
||||||
|
#include "private.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
@@ -50,6 +57,8 @@ int logfile_count_max = 5;
|
|||||||
struct rlimit initial_rlimit[RLIMIT_NLIMITS];
|
struct rlimit initial_rlimit[RLIMIT_NLIMITS];
|
||||||
struct rlimit global_rlimit[RLIMIT_NLIMITS];
|
struct rlimit global_rlimit[RLIMIT_NLIMITS];
|
||||||
|
|
||||||
|
char cgroup_current[16]; /* cgroup.NAME sets current cgroup for a set of services */
|
||||||
|
|
||||||
struct conf_change {
|
struct conf_change {
|
||||||
TAILQ_ENTRY(conf_change) link;
|
TAILQ_ENTRY(conf_change) link;
|
||||||
char *name;
|
char *name;
|
||||||
@@ -63,22 +72,6 @@ static TAILQ_HEAD(head, conf_change) conf_change_list = TAILQ_HEAD_INITIALIZER(c
|
|||||||
static int parse_conf(char *file, int is_rcsd);
|
static int parse_conf(char *file, int is_rcsd);
|
||||||
static void drop_changes(void);
|
static void drop_changes(void);
|
||||||
|
|
||||||
static void hide_args(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Hide command line arguments from ps (in particular for
|
|
||||||
* forked children that don't execv()). This is an ugly
|
|
||||||
* hack that only works on Linux.
|
|
||||||
* https://web.archive.org/web/20110227041321/http://netsplit.com/2007/01/10/hiding-arguments-from-ps/
|
|
||||||
*/
|
|
||||||
if (argc > 1) {
|
|
||||||
char *arg_end;
|
|
||||||
|
|
||||||
arg_end = argv[argc-1] + strlen (argv[argc-1]);
|
|
||||||
*arg_end = ' ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int get_bool(char *arg, int default_value)
|
int get_bool(char *arg, int default_value)
|
||||||
{
|
{
|
||||||
if (!arg)
|
if (!arg)
|
||||||
@@ -95,6 +88,7 @@ fallback:
|
|||||||
/*
|
/*
|
||||||
* finit.debug = [on,off]
|
* finit.debug = [on,off]
|
||||||
* finit.show_status = [on,off]
|
* finit.show_status = [on,off]
|
||||||
|
* finit.status_style = [old,classic,modern]
|
||||||
*/
|
*/
|
||||||
static void parse_finit_opts(char *opt)
|
static void parse_finit_opts(char *opt)
|
||||||
{
|
{
|
||||||
@@ -142,24 +136,27 @@ static void parse_arg(char *arg)
|
|||||||
single = 1;
|
single = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void conf_parse_cmdline(int argc, char *argv[])
|
#ifdef KERNEL_CMDLINE
|
||||||
|
/*
|
||||||
|
* Parse /proc/cmdline to find args for init. Don't use this!
|
||||||
|
*
|
||||||
|
* Instead, rely on the kernel to give Finit its arguments as
|
||||||
|
* regular argc + argv[]. Only use this if the system you run
|
||||||
|
* on has a broken initramfs system that cannot forward args
|
||||||
|
* to Finit properly.
|
||||||
|
*/
|
||||||
|
static void parse_kernel_cmdline(void)
|
||||||
{
|
{
|
||||||
int dbg = 0;
|
|
||||||
FILE *fp;
|
|
||||||
char line[LINE_SIZE], *cmdline, *tok;
|
char line[LINE_SIZE], *cmdline, *tok;
|
||||||
|
FILE *fp;
|
||||||
for (int i = 1; i < argc; i++)
|
|
||||||
parse_arg(argv[i]);
|
|
||||||
|
|
||||||
hide_args(argc, argv);
|
|
||||||
|
|
||||||
fp = fopen("/proc/cmdline", "r");
|
fp = fopen("/proc/cmdline", "r");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
goto done;
|
return;
|
||||||
|
|
||||||
if (!fgets(line, sizeof(line), fp)) {
|
if (!fgets(line, sizeof(line), fp)) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
goto done;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdline = chomp(line);
|
cmdline = chomp(line);
|
||||||
@@ -170,9 +167,46 @@ void conf_parse_cmdline(int argc, char *argv[])
|
|||||||
parse_arg(tok);
|
parse_arg(tok);
|
||||||
}
|
}
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define parse_kernel_cmdline()
|
||||||
|
#endif
|
||||||
|
|
||||||
done:
|
static void parse_kernel_loglevel(void)
|
||||||
log_init(dbg);
|
{
|
||||||
|
char line[LINE_SIZE], *ptr;
|
||||||
|
FILE *fp;
|
||||||
|
int val;
|
||||||
|
|
||||||
|
fp = fopen("/proc/sys/kernel/printk", "r");
|
||||||
|
if (!fp)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!fgets(line, sizeof(line), fp)) {
|
||||||
|
fclose(fp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
ptr = chomp(line);
|
||||||
|
_d("%s", ptr);
|
||||||
|
val = atoi(ptr);
|
||||||
|
if (val >= 7)
|
||||||
|
kerndebug = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Kernel gives us all non-kernel options on our cmdline
|
||||||
|
*/
|
||||||
|
void conf_parse_cmdline(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
for (int i = 1; i < argc; i++)
|
||||||
|
parse_arg(argv[i]);
|
||||||
|
|
||||||
|
parse_kernel_cmdline();
|
||||||
|
parse_kernel_loglevel();
|
||||||
|
|
||||||
|
log_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int kmod_exists(char *mod)
|
static int kmod_exists(char *mod)
|
||||||
@@ -352,7 +386,7 @@ char *lim2str(struct rlimit *rlim)
|
|||||||
char tmp[25];
|
char tmp[25];
|
||||||
static char buf[42];
|
static char buf[42];
|
||||||
|
|
||||||
memset(buf, 0, sizeof(buf));
|
buf[0] = 0;
|
||||||
if (RLIM_INFINITY == rlim->rlim_cur)
|
if (RLIM_INFINITY == rlim->rlim_cur)
|
||||||
snprintf(tmp, sizeof(tmp), "unlimited, ");
|
snprintf(tmp, sizeof(tmp), "unlimited, ");
|
||||||
else
|
else
|
||||||
@@ -423,6 +457,29 @@ error:
|
|||||||
logit(LOG_WARNING, "rlimit: parse error");
|
logit(LOG_WARNING, "rlimit: parse error");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* cgroup NAME ctrl.prop:value,ctrl.prop:value ... */
|
||||||
|
static void conf_parse_cgroup(char *line)
|
||||||
|
{
|
||||||
|
char config[strlen(line) + 1];
|
||||||
|
char *ptr, *name;
|
||||||
|
|
||||||
|
name = strtok(line, " \t");
|
||||||
|
if (!name)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (strstr(name, "..") || strchr(name, '/'))
|
||||||
|
return; /* illegal */
|
||||||
|
|
||||||
|
config[0] = 0;
|
||||||
|
while ((ptr = strtok(NULL, " \t"))) {
|
||||||
|
if (config[0])
|
||||||
|
strlcat(config, ",", sizeof(config));
|
||||||
|
strlcat(config, ptr, sizeof(config));
|
||||||
|
}
|
||||||
|
|
||||||
|
cgroup_add(name, config, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static void parse_static(char *line, int is_rcsd)
|
static void parse_static(char *line, int is_rcsd)
|
||||||
{
|
{
|
||||||
char cmd[CMD_SIZE];
|
char cmd[CMD_SIZE];
|
||||||
@@ -516,6 +573,26 @@ static void parse_static(char *line, int is_rcsd)
|
|||||||
cfglevel = 2; /* Fallback */
|
cfglevel = 2; /* Fallback */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Periodic check and instability index leveler, seconds
|
||||||
|
*/
|
||||||
|
if (MATCH_CMD(line, "service-interval ", x)) {
|
||||||
|
char *token = strip_line(x);
|
||||||
|
const char *err = NULL;
|
||||||
|
int val;
|
||||||
|
|
||||||
|
/* 0 min to 1 day, should check at least daily */
|
||||||
|
val = strtonum(token, 0, 1440, &err);
|
||||||
|
if (!err) {
|
||||||
|
int disabled = !service_interval;
|
||||||
|
|
||||||
|
service_interval = val * 1000; /* to milliseconds */
|
||||||
|
if (disabled)
|
||||||
|
service_init();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_dynamic(char *line, struct rlimit rlimit[], char *file)
|
static void parse_dynamic(char *line, struct rlimit rlimit[], char *file)
|
||||||
@@ -552,9 +629,21 @@ static void parse_dynamic(char *line, struct rlimit rlimit[], char *file)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Read control group limits */
|
||||||
|
if (MATCH_CMD(line, "cgroup ", x)) {
|
||||||
|
conf_parse_cgroup(x);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set current cgroup for the following services/run/tasks */
|
||||||
|
if (MATCH_CMD(line, "cgroup.", x)) {
|
||||||
|
strlcpy(cgroup_current, x, sizeof(cgroup_current));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Regular or serial TTYs to run getty */
|
/* Regular or serial TTYs to run getty */
|
||||||
if (MATCH_CMD(line, "tty ", x)) {
|
if (MATCH_CMD(line, "tty ", x)) {
|
||||||
tty_register(strip_line(x), rlimit, file);
|
service_register(SVC_TYPE_TTY, strip_line(x), rlimit, file);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -580,9 +669,11 @@ static int parse_conf(char *file, int is_rcsd)
|
|||||||
if (!fp)
|
if (!fp)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* Prepare default limits for each service in /etc/finit.d/ */
|
/* Prepare default limits and group for each service in /etc/finit.d/ */
|
||||||
if (is_rcsd)
|
if (is_rcsd) {
|
||||||
memcpy(rlimit, global_rlimit, sizeof(rlimit));
|
memcpy(rlimit, global_rlimit, sizeof(rlimit));
|
||||||
|
cgroup_current[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
_d("*** Parsing %s", file);
|
_d("*** Parsing %s", file);
|
||||||
while (!feof(fp)) {
|
while (!feof(fp)) {
|
||||||
@@ -622,8 +713,8 @@ int conf_reload(void)
|
|||||||
daylight, timezone, tzname[0], tzname[1]);
|
daylight, timezone, tzname[0], tzname[1]);
|
||||||
|
|
||||||
/* Mark and sweep */
|
/* Mark and sweep */
|
||||||
|
cgroup_mark_all();
|
||||||
svc_mark_dynamic();
|
svc_mark_dynamic();
|
||||||
tty_mark();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reset global rlimit to bootstrap values from conf_init().
|
* Reset global rlimit to bootstrap values from conf_init().
|
||||||
@@ -632,12 +723,12 @@ int conf_reload(void)
|
|||||||
|
|
||||||
if (rescue) {
|
if (rescue) {
|
||||||
int rc;
|
int rc;
|
||||||
char line[80] = "tty [12345] @console noclear nologin";
|
char line[80] = "tty [12345] rescue";
|
||||||
|
|
||||||
/* If rescue.conf is missing, fall back to a root shell */
|
/* If rescue.conf is missing, fall back to a root shell */
|
||||||
rc = parse_conf(RESCUE_CONF, 0);
|
rc = parse_conf(RESCUE_CONF, 0);
|
||||||
if (rc)
|
if (rc)
|
||||||
tty_register(line, global_rlimit, NULL);
|
service_register(SVC_TYPE_TTY, line, global_rlimit, NULL);
|
||||||
|
|
||||||
print(rc, "Entering rescue mode");
|
print(rc, "Entering rescue mode");
|
||||||
goto done;
|
goto done;
|
||||||
@@ -677,7 +768,7 @@ int conf_reload(void)
|
|||||||
|
|
||||||
/* Check for dangling symlinks */
|
/* Check for dangling symlinks */
|
||||||
if (S_ISLNK(st.st_mode)) {
|
if (S_ISLNK(st.st_mode)) {
|
||||||
path = rp = realpath(path, NULL);
|
rp = realpath(path, NULL);
|
||||||
if (!rp) {
|
if (!rp) {
|
||||||
logit(LOG_WARNING, "Skipping %s, dangling symlink: %s", path, strerror(errno));
|
logit(LOG_WARNING, "Skipping %s, dangling symlink: %s", path, strerror(errno));
|
||||||
continue;
|
continue;
|
||||||
@@ -687,7 +778,7 @@ int conf_reload(void)
|
|||||||
/* Check that file ends with '.conf' */
|
/* Check that file ends with '.conf' */
|
||||||
len = strlen(path);
|
len = strlen(path);
|
||||||
if (len < 6 || strcmp(&path[len - 5], ".conf"))
|
if (len < 6 || strcmp(&path[len - 5], ".conf"))
|
||||||
_d("Skipping %s, not a valid .conf ... ", path);
|
_d("Skipping %s, not a Finit .conf file ... ", path);
|
||||||
else
|
else
|
||||||
parse_conf(path, 1);
|
parse_conf(path, 1);
|
||||||
|
|
||||||
@@ -699,7 +790,13 @@ int conf_reload(void)
|
|||||||
|
|
||||||
/* Mark any reverse deps as chenaged. */
|
/* Mark any reverse deps as chenaged. */
|
||||||
service_update_rdeps();
|
service_update_rdeps();
|
||||||
|
|
||||||
|
/* Set up top-level cgroups */
|
||||||
|
cgroup_config();
|
||||||
done:
|
done:
|
||||||
|
/* Remove all unused top-level cgroups */
|
||||||
|
cgroup_cleanup();
|
||||||
|
|
||||||
/* Drop record of all .conf changes */
|
/* Drop record of all .conf changes */
|
||||||
drop_changes();
|
drop_changes();
|
||||||
|
|
||||||
@@ -792,13 +889,21 @@ int conf_any_change(void)
|
|||||||
|
|
||||||
int conf_changed(char *file)
|
int conf_changed(char *file)
|
||||||
{
|
{
|
||||||
|
int rc = 0;
|
||||||
|
char *rp;
|
||||||
|
|
||||||
if (!file)
|
if (!file)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (conf_find(file))
|
rp = realpath(file, NULL);
|
||||||
return 1;
|
if (!rp)
|
||||||
|
return 0;
|
||||||
|
|
||||||
return 0;
|
if (conf_find(rp))
|
||||||
|
rc = 1;
|
||||||
|
free(rp);
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void conf_cb(uev_t *w, void *arg, int events)
|
static void conf_cb(uev_t *w, void *arg, int events)
|
||||||
@@ -880,7 +985,7 @@ int conf_monitor(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prepare .conf parser and load all .conf files
|
* Prepare .conf parser and load /etc/finit.conf for global settings
|
||||||
*/
|
*/
|
||||||
int conf_init(uev_ctx_t *ctx)
|
int conf_init(uev_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
@@ -900,6 +1005,12 @@ int conf_init(uev_ctx_t *ctx)
|
|||||||
rlim2str(i), strerror(errno));
|
rlim2str(i), strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Initialize global rlimits, e.g. for built-in services */
|
||||||
|
memcpy(global_rlimit, initial_rlimit, sizeof(global_rlimit));
|
||||||
|
|
||||||
|
/* Read global rlimits and global cgroup setup from /etc/finit.conf */
|
||||||
|
parse_conf(FINIT_CONF, 0);
|
||||||
|
|
||||||
/* prepare /etc watcher */
|
/* prepare /etc watcher */
|
||||||
fd = iwatch_init(&iw_conf);
|
fd = iwatch_init(&iw_conf);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
|
|||||||
@@ -24,12 +24,14 @@
|
|||||||
#ifndef FINIT_CONF_H_
|
#ifndef FINIT_CONF_H_
|
||||||
#define FINIT_CONF_H_
|
#define FINIT_CONF_H_
|
||||||
|
|
||||||
|
#include "cgroup.h"
|
||||||
#include "svc.h"
|
#include "svc.h"
|
||||||
|
|
||||||
extern int logfile_size_max;
|
extern int logfile_size_max;
|
||||||
extern int logfile_count_max;
|
extern int logfile_count_max;
|
||||||
|
|
||||||
extern struct rlimit global_rlimit[];
|
extern struct rlimit global_rlimit[];
|
||||||
|
extern char cgroup_current[];
|
||||||
|
|
||||||
int str2rlim(char *str);
|
int str2rlim(char *str);
|
||||||
char *rlim2str(int rlim);
|
char *rlim2str(int rlim);
|
||||||
|
|||||||
+68
-106
@@ -26,15 +26,22 @@
|
|||||||
|
|
||||||
#include <ctype.h> /* isdigit() */
|
#include <ctype.h> /* isdigit() */
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <err.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
|
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
#include <linux/vt.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
|
#include "cgroup.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "sig.h"
|
#include "sig.h"
|
||||||
@@ -105,8 +112,6 @@ int run(char *cmd)
|
|||||||
if (0 == pid) {
|
if (0 == pid) {
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
/* Reset signal handlers that were set by the parent process */
|
|
||||||
sig_unblock();
|
|
||||||
setsid();
|
setsid();
|
||||||
|
|
||||||
/* Always redirect stdio for run() */
|
/* Always redirect stdio for run() */
|
||||||
@@ -239,14 +244,8 @@ int exec_runtask(char *cmd, char *args[])
|
|||||||
|
|
||||||
static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit rlimit[])
|
static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit rlimit[])
|
||||||
{
|
{
|
||||||
struct sigaction sa;
|
|
||||||
struct termios term;
|
|
||||||
char name[80];
|
char name[80];
|
||||||
int fd;
|
int fd, dummy;
|
||||||
|
|
||||||
/* Detach from initial controlling TTY and become session leader */
|
|
||||||
vhangup();
|
|
||||||
setsid();
|
|
||||||
|
|
||||||
fd = open(tty, O_RDWR);
|
fd = open(tty, O_RDWR);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
@@ -257,40 +256,18 @@ static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit
|
|||||||
dup2(fd, STDIN_FILENO);
|
dup2(fd, STDIN_FILENO);
|
||||||
dup2(fd, STDOUT_FILENO);
|
dup2(fd, STDOUT_FILENO);
|
||||||
dup2(fd, STDERR_FILENO);
|
dup2(fd, STDERR_FILENO);
|
||||||
close(fd);
|
|
||||||
|
|
||||||
if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0)
|
/* Set default TERM, run_getty() below allows override */
|
||||||
logit(LOG_WARNING, "Failed TIOCSCTTY on %s: %s", tty, strerror(errno));
|
if (ioctl(fd, VT_OPENQRY, &dummy) == -1)
|
||||||
|
setenv("TERM", "vt102", 1); /* likely a serial line */
|
||||||
|
else
|
||||||
|
setenv("TERM", "linux", 1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reset to sane defaults in case of messup from prev. session
|
* Reset to sane defaults in case of messup from prev. session
|
||||||
*/
|
*/
|
||||||
stty(STDIN_FILENO, speed);
|
stty(fd, speed);
|
||||||
|
close(fd);
|
||||||
/*
|
|
||||||
* Disable ISIG (INTR, QUIT, SUSP) before handing over to getty.
|
|
||||||
* It is up to the getty process to allow them again.
|
|
||||||
*/
|
|
||||||
if (!tcgetattr(STDIN_FILENO, &term)) {
|
|
||||||
term.c_lflag &= ~ISIG;
|
|
||||||
term.c_cc[VEOF] = _POSIX_VDISABLE;
|
|
||||||
term.c_cc[VINTR] = _POSIX_VDISABLE;
|
|
||||||
tcsetattr(STDIN_FILENO, TCSAFLUSH, &term);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reset signal handlers that were set by the parent process */
|
|
||||||
sig_unblock();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Ignore a few signals, needed to prevent Ctrl-C at login:
|
|
||||||
* prompt and to prevent QUIT from dumping core.
|
|
||||||
*/
|
|
||||||
sigemptyset(&sa.sa_mask);
|
|
||||||
sa.sa_flags = SA_RESTART;
|
|
||||||
sa.sa_handler = SIG_IGN;
|
|
||||||
sigaction(SIGHUP, &sa, NULL);
|
|
||||||
sigaction(SIGINT, &sa, NULL);
|
|
||||||
sigaction(SIGQUIT, &sa, NULL);
|
|
||||||
|
|
||||||
/* Set configured limits */
|
/* Set configured limits */
|
||||||
for (int i = 0; i < RLIMIT_NLIMITS; i++) {
|
for (int i = 0; i < RLIMIT_NLIMITS; i++) {
|
||||||
@@ -308,14 +285,18 @@ static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit
|
|||||||
|
|
||||||
static int activate_console(int noclear, int nowait)
|
static int activate_console(int noclear, int nowait)
|
||||||
{
|
{
|
||||||
|
static const char msg[] = "\nPlease press Enter to activate this console.";
|
||||||
|
static const char clr[] = "\r\e[K";
|
||||||
|
static const char cup[] = "\e[A";
|
||||||
struct termios orig;
|
struct termios orig;
|
||||||
int ret = 0;
|
char c;
|
||||||
|
int rc;
|
||||||
|
|
||||||
if (nowait || rescue)
|
if (nowait || rescue)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (!noclear)
|
if (!noclear)
|
||||||
(void)write(STDERR_FILENO, "\e[r\e[H\e[J", 9);
|
dprint(STDERR_FILENO, "\e[r\e[H\e[J", 9);
|
||||||
|
|
||||||
/* Disable ECHO, XON/OFF while waiting for <CR> */
|
/* Disable ECHO, XON/OFF while waiting for <CR> */
|
||||||
if (!tcgetattr(STDIN_FILENO, &orig)) {
|
if (!tcgetattr(STDIN_FILENO, &orig)) {
|
||||||
@@ -328,36 +309,24 @@ static int activate_console(int noclear, int nowait)
|
|||||||
tcsetattr(STDIN_FILENO, TCSAFLUSH, &c);
|
tcsetattr(STDIN_FILENO, TCSAFLUSH, &c);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!fexist(SYNC_SHUTDOWN)) {
|
dprint(STDERR_FILENO, clr, strlen(clr));
|
||||||
char c;
|
dprint(STDERR_FILENO, msg, strlen(msg));
|
||||||
static const char clr[] = "\r\e[2K";
|
while ((rc = read(STDIN_FILENO, &c, 1)) > 0 && c != '\r' && c != '\n')
|
||||||
static const char cup[] = "\e[A";
|
continue;
|
||||||
static const char msg[] = "\nPlease press Enter to activate this console.";
|
|
||||||
|
|
||||||
if (fexist(SYNC_STOPPED)) {
|
/* On any error (likely EINTR), we avoid starting getty */
|
||||||
sleep(5);
|
if (rc == -1)
|
||||||
continue;
|
rc = 0;
|
||||||
}
|
|
||||||
|
|
||||||
(void)write(STDERR_FILENO, clr, strlen(clr));
|
/* Clear msg and move cursor up for next message/login: */
|
||||||
(void)write(STDERR_FILENO, msg, strlen(msg));
|
dprint(STDERR_FILENO, clr, strlen(clr));
|
||||||
while (read(STDIN_FILENO, &c, 1) == 1 && c != '\r')
|
dprint(STDERR_FILENO, cup, strlen(cup));
|
||||||
continue;
|
|
||||||
|
|
||||||
if (fexist(SYNC_STOPPED))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
(void)write(STDERR_FILENO, clr, strlen(clr));
|
|
||||||
(void)write(STDERR_FILENO, cup, strlen(cup));
|
|
||||||
ret = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Restore TTY */
|
/* Restore TTY */
|
||||||
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig) == -1)
|
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig) == -1)
|
||||||
ret = 0;
|
rc = 0; /* TTY in bad shape, restart */
|
||||||
|
|
||||||
return ret;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -379,64 +348,57 @@ static int activate_console(int noclear, int nowait)
|
|||||||
* since /bin/login usually only disables ECHO until a password line has
|
* since /bin/login usually only disables ECHO until a password line has
|
||||||
* been entered. Upon starting the user's $SHELL the ISIG flag is reset
|
* been entered. Upon starting the user's $SHELL the ISIG flag is reset
|
||||||
*/
|
*/
|
||||||
pid_t run_getty(char *tty, char *baud, char *term, int noclear, int nowait, struct rlimit rlimit[])
|
pid_t run_getty(char *tty, char *cmd, char *args[], int noclear, int nowait, struct rlimit rlimit[])
|
||||||
{
|
{
|
||||||
pid_t pid;
|
int rc = 1;
|
||||||
|
|
||||||
pid = fork();
|
/* Dunno speed, tell stty() to not mess with it */
|
||||||
if (!pid) {
|
prepare_tty(tty, B0, "getty", rlimit);
|
||||||
speed_t speed;
|
if (activate_console(noclear, nowait)) {
|
||||||
int rc = 1;
|
logit(LOG_INFO, "Starting getty on %s", tty);
|
||||||
|
rc = execv(cmd, args);
|
||||||
speed = stty_parse_speed(baud);
|
|
||||||
logit(LOG_INFO, "Starting built-in getty on %s, speed %u", tty, speed);
|
|
||||||
prepare_tty(tty, speed, "tty", rlimit);
|
|
||||||
if (activate_console(noclear, nowait))
|
|
||||||
rc = getty(tty, speed, term, NULL);
|
|
||||||
|
|
||||||
_exit(rc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return pid;
|
vhangup();
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_t run_getty2(char *tty, char *cmd, char *args[], int noclear, int nowait, struct rlimit rlimit[])
|
int sh(char *tty)
|
||||||
{
|
{
|
||||||
pid_t pid;
|
char *args[2] = {
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
char *arg0;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
pid = fork();
|
/* The getty process is usually responsible for the UTMP login record */
|
||||||
if (!pid) {
|
utmp_set_login(tty, NULL);
|
||||||
int rc = 1;
|
|
||||||
|
|
||||||
/* Dunno speed, tell stty() to not mess with it */
|
/* Start /bin/sh as a login shell, i.e. with a prefix '-' */
|
||||||
logit(LOG_INFO, "Starting external getty on %s, speed %u", tty, B0);
|
len = strlen(_PATH_BSHELL) + 2;
|
||||||
prepare_tty(tty, B0, "getty", rlimit);
|
arg0 = malloc(len);
|
||||||
if (activate_console(noclear, nowait))
|
if (!arg0)
|
||||||
rc = execv(cmd, args);
|
err(1, "Failed allocating memory");
|
||||||
|
snprintf(arg0, len, "-%s", _PATH_BSHELL);
|
||||||
|
args[0] = arg0;
|
||||||
|
|
||||||
vhangup();
|
/* Unblock signals inherited from parent */
|
||||||
_exit(rc);
|
sig_unblock();
|
||||||
}
|
|
||||||
|
|
||||||
return pid;
|
return execv(_PATH_BSHELL, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_t run_sh(char *tty, int noclear, int nowait, struct rlimit rlimit[])
|
pid_t run_sh(char *tty, int noclear, int nowait, struct rlimit rlimit[])
|
||||||
{
|
{
|
||||||
pid_t pid;
|
int rc = 1;
|
||||||
|
|
||||||
pid = fork();
|
prepare_tty(tty, B0, "finitsh", rlimit);
|
||||||
if (!pid) {
|
if (activate_console(noclear, nowait))
|
||||||
int rc = 1;
|
rc = sh(tty);
|
||||||
|
|
||||||
prepare_tty(tty, B0, "finit-sh", rlimit);
|
return rc;
|
||||||
if (activate_console(noclear, nowait))
|
|
||||||
rc = sh(tty);
|
|
||||||
|
|
||||||
_exit(rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
return pid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int run_parts(char *dir, char *cmd)
|
int run_parts(char *dir, char *cmd)
|
||||||
|
|||||||
+265
-111
@@ -36,7 +36,11 @@
|
|||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#include <sys/stat.h> /* umask(), mkdir() */
|
#include <sys/stat.h> /* umask(), mkdir() */
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "cgroup.h"
|
#include "cgroup.h"
|
||||||
@@ -52,6 +56,7 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "utmp-api.h"
|
#include "utmp-api.h"
|
||||||
#include "schedule.h"
|
#include "schedule.h"
|
||||||
|
#include "watchdog.h"
|
||||||
|
|
||||||
int runlevel = 0; /* Bootstrap 'S' */
|
int runlevel = 0; /* Bootstrap 'S' */
|
||||||
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
|
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
|
||||||
@@ -59,11 +64,14 @@ int prevlevel = -1;
|
|||||||
int debug = 0; /* debug mode from kernel cmdline */
|
int debug = 0; /* debug mode from kernel cmdline */
|
||||||
int rescue = 0; /* rescue mode from kernel cmdline */
|
int rescue = 0; /* rescue mode from kernel cmdline */
|
||||||
int single = 0; /* single user mode from kernel cmdline */
|
int single = 0; /* single user mode from kernel cmdline */
|
||||||
|
int bootstrap = 1; /* set while bootrapping (for TTYs) */
|
||||||
|
int kerndebug = 0; /* set if /proc/sys/kernel/printk > 7 */
|
||||||
char *sdown = NULL;
|
char *sdown = NULL;
|
||||||
char *network = NULL;
|
char *network = NULL;
|
||||||
char *hostname = NULL;
|
char *hostname = NULL;
|
||||||
char *rcsd = FINIT_RCSD;
|
char *rcsd = FINIT_RCSD;
|
||||||
char *runparts = NULL;
|
char *runparts = NULL;
|
||||||
|
char *osheading = NULL;
|
||||||
|
|
||||||
uev_ctx_t *ctx = NULL; /* Main loop context */
|
uev_ctx_t *ctx = NULL; /* Main loop context */
|
||||||
svc_t *wdog = NULL; /* No watchdog by default */
|
svc_t *wdog = NULL; /* No watchdog by default */
|
||||||
@@ -79,7 +87,7 @@ static void banner(void)
|
|||||||
* similar enabled to start emptying /dev/kmsg, but for
|
* similar enabled to start emptying /dev/kmsg, but for
|
||||||
* our progress we want to own the console.
|
* our progress we want to own the console.
|
||||||
*/
|
*/
|
||||||
if (!debug)
|
if (!debug && !kerndebug)
|
||||||
klogctl(6, NULL, 0);
|
klogctl(6, NULL, 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -88,7 +96,14 @@ static void banner(void)
|
|||||||
*/
|
*/
|
||||||
plugin_run_hooks(HOOK_BANNER);
|
plugin_run_hooks(HOOK_BANNER);
|
||||||
|
|
||||||
print_banner(INIT_HEADING);
|
#ifdef INIT_OSHEADING
|
||||||
|
osheading = INIT_OSHEADING;
|
||||||
|
if (osheading) {
|
||||||
|
if (!osheading[0])
|
||||||
|
osheading = release_heading();
|
||||||
|
print_banner(osheading);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -107,6 +122,7 @@ static int fsck(int pass)
|
|||||||
while ((fs = getfsent())) {
|
while ((fs = getfsent())) {
|
||||||
char cmd[80];
|
char cmd[80];
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
int fsck_rc = 0;
|
||||||
|
|
||||||
if (fs->fs_passno != pass)
|
if (fs->fs_passno != pass)
|
||||||
continue;
|
continue;
|
||||||
@@ -124,8 +140,33 @@ static int fsck(int pass)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef FSCK_FIX
|
||||||
|
snprintf(cmd, sizeof(cmd), "fsck -yf %s", fs->fs_spec);
|
||||||
|
#else
|
||||||
snprintf(cmd, sizeof(cmd), "fsck -a %s", fs->fs_spec);
|
snprintf(cmd, sizeof(cmd), "fsck -a %s", fs->fs_spec);
|
||||||
rc += run_interactive(cmd, "Checking filesystem %.13s", fs->fs_spec);
|
#endif
|
||||||
|
fsck_rc = run_interactive(cmd, "Checking filesystem %.13s", fs->fs_spec);
|
||||||
|
/*
|
||||||
|
* "failure" is defined as exiting with a return code of
|
||||||
|
* 2 or larger. A return code of 1 indicates that filesystem
|
||||||
|
* errors were corrected but that the boot may proceed.
|
||||||
|
*/
|
||||||
|
if (fsck_rc > 1) {
|
||||||
|
char *sulogin[] = {
|
||||||
|
_PATH_SULOGIN,
|
||||||
|
"sulogin",
|
||||||
|
};
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < NELEMS(sulogin); i++) {
|
||||||
|
if (systemf(sulogin[i]))
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
do_shutdown(SHUT_REBOOT);
|
||||||
|
}
|
||||||
|
rc += fsck_rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
endfsent();
|
endfsent();
|
||||||
@@ -135,18 +176,51 @@ static int fsck(int pass)
|
|||||||
|
|
||||||
static int fsck_all(void)
|
static int fsck_all(void)
|
||||||
{
|
{
|
||||||
int pass, rc = 0;
|
int rc = 0;
|
||||||
|
#ifndef FAST_BOOT
|
||||||
|
int pass;
|
||||||
|
|
||||||
for (pass = 1; pass < 10; pass++) {
|
for (pass = 1; pass < 10; pass++) {
|
||||||
rc = fsck(pass);
|
rc = fsck(pass);
|
||||||
if (rc)
|
if (rc)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Wrapper for mount(2), logs any errors to stderr */
|
||||||
|
static void fs_mount(const char *src, const char *tgt, const char *fstype,
|
||||||
|
unsigned long flags, const void *data)
|
||||||
|
{
|
||||||
|
const char *msg = !fstype ? "MS_MOVE" : "mounting";
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = mount(src, tgt, fstype, flags, data);
|
||||||
|
if (rc && errno != EBUSY)
|
||||||
|
_pe("Failed %s %s on %s", msg, src, tgt);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef SYSROOT
|
#ifndef SYSROOT
|
||||||
|
/* If / is not listed in fstab, or listed as 'ro', leave it alone */
|
||||||
|
static int fs_readonly_root(struct fstab *fs)
|
||||||
|
{
|
||||||
|
char *tok, *str;
|
||||||
|
|
||||||
|
if (!fs)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
str = fs->fs_mntops;
|
||||||
|
while ((tok = strtok(str, ","))) {
|
||||||
|
if (!strcmp(tok, "ro"))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
str = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void fs_remount_root(int fsckerr)
|
static void fs_remount_root(int fsckerr)
|
||||||
{
|
{
|
||||||
struct fstab *fs;
|
struct fstab *fs;
|
||||||
@@ -159,8 +233,7 @@ static void fs_remount_root(int fsckerr)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If / is not listed in fstab, or listed as 'ro', leave it alone */
|
if (fs_readonly_root(fs))
|
||||||
if (!fs || !strcmp(fs->fs_type, "ro"))
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (fsckerr)
|
if (fsckerr)
|
||||||
@@ -179,12 +252,74 @@ static void fs_remount_root(int fsckerr)
|
|||||||
* XXX: Untested, in the initramfs age we should
|
* XXX: Untested, in the initramfs age we should
|
||||||
* probably use switch_root instead.
|
* probably use switch_root instead.
|
||||||
*/
|
*/
|
||||||
if (mount(SYSROOT, "/", NULL, MS_MOVE, NULL))
|
fs_mount(SYSROOT, "/", NULL, MS_MOVE, NULL);
|
||||||
_pe("Failed %s / MS_MOVE");
|
|
||||||
}
|
}
|
||||||
#endif /* SYSROOT */
|
#endif /* SYSROOT */
|
||||||
|
|
||||||
static void fs_mount(void)
|
/*
|
||||||
|
* Opinionated file system setup. Checks for critical mount points and
|
||||||
|
* mounts them as most users expect. All file systems are checked with
|
||||||
|
* /proc/mounts before mounting.
|
||||||
|
*
|
||||||
|
* Embedded systems, and other people who want full control, can set up
|
||||||
|
* their system with /etc/fstab, which is handled before this function
|
||||||
|
* is called. For systems like Debian/Ubuntu, who only have / and swap
|
||||||
|
* in their /etc/fstab, this function does all the magic necessary.
|
||||||
|
*/
|
||||||
|
static void fs_finalize(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Some systems rely on us to both create /dev/shm and, to mount
|
||||||
|
* a tmpfs there. Any system with dbus needs shared memory, so
|
||||||
|
* mount it, unless its already mounted, but not if listed in
|
||||||
|
* the /etc/fstab file already.
|
||||||
|
*/
|
||||||
|
if (!fismnt("/dev/shm")) {
|
||||||
|
makedir("/dev/shm", 0777);
|
||||||
|
fs_mount("shm", "/dev/shm", "tmpfs", 0, "mode=0777");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Modern systems use /dev/pts */
|
||||||
|
if (!fismnt("/dev/pts")) {
|
||||||
|
char opts[32];
|
||||||
|
int mode;
|
||||||
|
int gid;
|
||||||
|
|
||||||
|
gid = getgroup("tty");
|
||||||
|
if (gid == -1)
|
||||||
|
gid = 0;
|
||||||
|
|
||||||
|
/* 0600 is default on Debian, use 0620 to get mesg y by default */
|
||||||
|
mode = 0620;
|
||||||
|
snprintf(opts, sizeof(opts), "gid=%d,mode=%d,ptmxmode=0666", gid, mode);
|
||||||
|
|
||||||
|
makedir("/dev/pts", 0755);
|
||||||
|
fs_mount("devpts", "/dev/pts", "devpts", MS_NOSUID | MS_NOEXEC, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Modern systems use tmpfs for /run. Fallback to /var/run if
|
||||||
|
* /run doesn't exist is handled by the bootmisc plugin. It
|
||||||
|
* also sets up compat symlinks.
|
||||||
|
*
|
||||||
|
* The unconditional mount of /run/lock is for DoS prevention.
|
||||||
|
* To override any of this behavior, add entries to /etc/fstab
|
||||||
|
* for /run (and optionally /run/lock).
|
||||||
|
*/
|
||||||
|
if (fisdir("/run") && !fismnt("/run")) {
|
||||||
|
fs_mount("tmpfs", "/run", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME, "mode=0755,size=10%");
|
||||||
|
|
||||||
|
/* This prevents user DoS of /run by filling /run/lock at the expense of another tmpfs, max 5MiB */
|
||||||
|
makedir("/run/lock", 1777);
|
||||||
|
fs_mount("tmpfs", "/run/lock", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME, "mode=0777,size=5252880");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Modern systems use tmpfs for /tmp */
|
||||||
|
if (!fismnt("/tmp"))
|
||||||
|
fs_mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_NODEV, "mode=1777");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fs_mount_all(void)
|
||||||
{
|
{
|
||||||
if (!rescue)
|
if (!rescue)
|
||||||
fs_remount_root(fsck_all());
|
fs_remount_root(fsck_all());
|
||||||
@@ -199,16 +334,18 @@ static void fs_mount(void)
|
|||||||
plugin_run_hooks(HOOK_MOUNT_POST);
|
plugin_run_hooks(HOOK_MOUNT_POST);
|
||||||
|
|
||||||
run("swapon -ea");
|
run("swapon -ea");
|
||||||
umask(0022);
|
|
||||||
|
_d("Finalize, ensure common file systems are available ...");
|
||||||
|
fs_finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need /proc for rs_remount_root() and conf_parse_cmdline(), /dev
|
* We need /proc for rs_remount_root() and conf_parse_cmdline(), /dev
|
||||||
* for early multi-console, and /sys for the cgroups support. Any
|
* for early multi-console, and /sys for the cgroups support. Any
|
||||||
* occurrence of these file systems in /etc/fstab will replace these
|
* occurrence of these file systems in /etc/fstab will replace these
|
||||||
* mounts later in fs_mount()
|
* mounts later in fs_mount_all()
|
||||||
*
|
*
|
||||||
* Ignore any mount errors with EBUSY, kernel likely alread mounted
|
* Ignore any mount errors with EBUSY, kernel likely already mounted
|
||||||
* the filesystem for us automatically, e.g., CONFIG_DEVTMPFS_MOUNT.
|
* the filesystem for us automatically, e.g., CONFIG_DEVTMPFS_MOUNT.
|
||||||
*/
|
*/
|
||||||
static void fs_init(void)
|
static void fs_init(void)
|
||||||
@@ -222,58 +359,24 @@ static void fs_init(void)
|
|||||||
};
|
};
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
|
/* mask writable bit for g and o */
|
||||||
|
umask(022);
|
||||||
|
|
||||||
for (i = 0; i < NELEMS(fs); i++) {
|
for (i = 0; i < NELEMS(fs); i++) {
|
||||||
int rc;
|
|
||||||
|
|
||||||
rc = mount(fs[i].spec, fs[i].file, fs[i].type, 0, NULL);
|
|
||||||
if (rc && errno != EBUSY)
|
|
||||||
_pe("Failed mounting %s on %s", fs[i].spec, fs[i].file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If everything goes south we can use this to give the operator an
|
|
||||||
* emergency shell to debug the problem -- Finit should not crash!
|
|
||||||
*
|
|
||||||
* Note: Only use this for debugging a new Finit setup, don't use
|
|
||||||
* this in production since it gives a root shell to anyone
|
|
||||||
* if Finit crashes.
|
|
||||||
*
|
|
||||||
* This emergency shell steps in to prevent "Aieee, PID 1 crashed"
|
|
||||||
* messages from the kernel, which usually results in a reboot, so
|
|
||||||
* that the operator instead can debug the problem.
|
|
||||||
*/
|
|
||||||
static void emergency_shell(void)
|
|
||||||
{
|
|
||||||
#ifdef EMERGENCY_SHELL
|
|
||||||
pid_t pid;
|
|
||||||
|
|
||||||
pid = fork();
|
|
||||||
if (pid) {
|
|
||||||
while (1) {
|
|
||||||
pid_t id;
|
|
||||||
|
|
||||||
/* Reap 'em (prevents Zombies) */
|
|
||||||
id = waitpid(-1, NULL, WNOHANG);
|
|
||||||
if (id == pid)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, "\n=> Embarrassingly, Finit has crashed. Check /dev/kmsg for details.\n");
|
|
||||||
fprintf(stderr, "=> To debug, add 'debug' to the kernel command line.\n\n");
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Become session leader and set controlling TTY
|
* Check if already mounted, we may be running in a
|
||||||
* to enable Ctrl-C and job control in shell.
|
* container, or an initramfs ran before us. The
|
||||||
|
* function fismnt() reliles on /proc/mounts being
|
||||||
|
* unique for each chroot/container.
|
||||||
*/
|
*/
|
||||||
setsid();
|
if (fismnt(fs[i].file))
|
||||||
ioctl(STDIN_FILENO, TIOCSCTTY, 1);
|
continue;
|
||||||
|
|
||||||
execl(_PATH_BSHELL, _PATH_BSHELL, NULL);
|
fs_mount(fs[i].spec, fs[i].file, fs[i].type, 0, NULL);
|
||||||
}
|
}
|
||||||
#endif /* EMERGENCY_SHELL */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle bootstrap transition to configured runlevel, start TTYs
|
* Handle bootstrap transition to configured runlevel, start TTYs
|
||||||
*
|
*
|
||||||
@@ -285,20 +388,8 @@ static void emergency_shell(void)
|
|||||||
* finit.conf, or *.conf in finit.d/, run to completion before we
|
* finit.conf, or *.conf in finit.d/, run to completion before we
|
||||||
* finalize the bootstrap process by calling this function.
|
* finalize the bootstrap process by calling this function.
|
||||||
*/
|
*/
|
||||||
static void finalize(void)
|
static void finalize(void *unused)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* Run startup scripts in the runparts directory, if any.
|
|
||||||
*/
|
|
||||||
if (runparts && fisdir(runparts) && !rescue)
|
|
||||||
run_parts(runparts, NULL);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Start all tasks/services in the configured runlevel
|
|
||||||
*/
|
|
||||||
_d("Change to default runlevel, start all services ...");
|
|
||||||
service_runlevel(cfglevel);
|
|
||||||
|
|
||||||
/* Clean up bootstrap-only tasks/services that never started */
|
/* Clean up bootstrap-only tasks/services that never started */
|
||||||
_d("Clean up all bootstrap-only tasks/services ...");
|
_d("Clean up all bootstrap-only tasks/services ...");
|
||||||
svc_prune_bootstrap();
|
svc_prune_bootstrap();
|
||||||
@@ -320,9 +411,9 @@ static void finalize(void)
|
|||||||
/* Disable progress output at normal runtime */
|
/* Disable progress output at normal runtime */
|
||||||
enable_progress(0);
|
enable_progress(0);
|
||||||
|
|
||||||
/* Delayed start of TTYs at bootstrap */
|
/* System bootrapped, launch TTYs et al */
|
||||||
_d("Launching all getty services ...");
|
bootstrap = 0;
|
||||||
tty_runlevel();
|
service_step_all(SVC_TYPE_RESPAWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -331,7 +422,7 @@ static void finalize(void)
|
|||||||
static void crank_worker(void *unused)
|
static void crank_worker(void *unused)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Initalize state machine and start all bootstrap tasks
|
* Initialize state machine and start all bootstrap tasks
|
||||||
* NOTE: no network available!
|
* NOTE: no network available!
|
||||||
*/
|
*/
|
||||||
sm_init(&sm);
|
sm_init(&sm);
|
||||||
@@ -340,12 +431,17 @@ static void crank_worker(void *unused)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Wait for system bootstrap to complete, all SVC_TYPE_RUNTASK must be
|
* Wait for system bootstrap to complete, all SVC_TYPE_RUNTASK must be
|
||||||
* allowed to complete their work in [S], or timeout, before we call
|
* allowed to complete their work in [S], or timeout, before we switch
|
||||||
* finalize(), should not take more than 120 sec.
|
* to the configured runlevel and call finalize(), should not take more
|
||||||
|
* than 120 sec.
|
||||||
*/
|
*/
|
||||||
static void final_worker(void *work)
|
static void bootstrap_worker(void *work)
|
||||||
{
|
{
|
||||||
static int cnt = 120;
|
static int cnt = 120;
|
||||||
|
static struct wq final = {
|
||||||
|
.cb = finalize,
|
||||||
|
.delay = 10
|
||||||
|
};
|
||||||
|
|
||||||
_d("Step all services ...");
|
_d("Step all services ...");
|
||||||
service_step_all(SVC_TYPE_ANY);
|
service_step_all(SVC_TYPE_ANY);
|
||||||
@@ -361,12 +457,36 @@ static void final_worker(void *work)
|
|||||||
else
|
else
|
||||||
_d("Timeout, resuming bootstrap.");
|
_d("Timeout, resuming bootstrap.");
|
||||||
|
|
||||||
finalize();
|
_d("Starting runlevel change finalize ...");
|
||||||
|
schedule_work(&final);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Run startup scripts in the runparts directory, if any.
|
||||||
|
*/
|
||||||
|
if (runparts && fisdir(runparts) && !rescue)
|
||||||
|
run_parts(runparts, NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start all tasks/services in the configured runlevel
|
||||||
|
*/
|
||||||
|
_d("Change to default runlevel(%d), starting all services ...", cfglevel);
|
||||||
|
service_runlevel(cfglevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int version(int rc)
|
||||||
|
{
|
||||||
|
puts(PACKAGE_STRING);
|
||||||
|
printf("Bug report address: %-40s\n", PACKAGE_BUGREPORT);
|
||||||
|
#ifdef PACKAGE_URL
|
||||||
|
printf("Project homepage: %s\n", PACKAGE_URL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int usage(int rc)
|
static int usage(int rc)
|
||||||
{
|
{
|
||||||
printf("Usage: telinit [OPTIONS] [q | Q | 0-9]\n\n"
|
printf("Usage: %s [OPTIONS] [q | Q | 0-9]\n\n"
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
// " -a Ignored, compat SysV init\n"
|
// " -a Ignored, compat SysV init\n"
|
||||||
// " -b Ignored, compat SysV init\n"
|
// " -b Ignored, compat SysV init\n"
|
||||||
@@ -384,12 +504,7 @@ static int usage(int rc)
|
|||||||
" q, Q Reload /etc/finit.conf and/or any *.conf in /etc/finit.d/\n"
|
" q, Q Reload /etc/finit.conf and/or any *.conf in /etc/finit.d/\n"
|
||||||
" if modified, same as initctl reload or SIGHUP to PID 1\n"
|
" if modified, same as initctl reload or SIGHUP to PID 1\n"
|
||||||
" 1, s, S Enter system rescue mode, runlevel 1\n"
|
" 1, s, S Enter system rescue mode, runlevel 1\n"
|
||||||
"\n");
|
"\n", prognm);
|
||||||
|
|
||||||
printf("Bug report address: %-40s\n", PACKAGE_BUGREPORT);
|
|
||||||
#ifdef PACKAGE_URL
|
|
||||||
printf("Project homepage: %s\n", PACKAGE_URL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -402,6 +517,7 @@ static int telinit(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
|
progname(argv[0]);
|
||||||
while ((c = getopt(argc, argv, "abe:h?st:vVz:")) != EOF) {
|
while ((c = getopt(argc, argv, "abe:h?st:vVz:")) != EOF) {
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case 'a': case 'b': case 'e': case 's': case 'z':
|
case 'a': case 'b': case 'e': case 's': case 'z':
|
||||||
@@ -411,7 +527,7 @@ static int telinit(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'v': case 'V':
|
case 'v': case 'V':
|
||||||
return puts("v" VERSION) == EOF;
|
return version(0);
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
case '?':
|
case '?':
|
||||||
@@ -423,13 +539,13 @@ static int telinit(int argc, char *argv[])
|
|||||||
int req = (int)argv[optind][0];
|
int req = (int)argv[optind][0];
|
||||||
|
|
||||||
if (isdigit(req))
|
if (isdigit(req))
|
||||||
return systemf("initctl runlevel %c", req);
|
return systemf("initctl -b runlevel %c", req);
|
||||||
|
|
||||||
if (req == 'q' || req == 'Q')
|
if (req == 'q' || req == 'Q')
|
||||||
return systemf("initctl reload");
|
return systemf("initctl -b reload");
|
||||||
|
|
||||||
if (req == 's' || req == 'S')
|
if (req == 's' || req == 'S')
|
||||||
return systemf("initctl runlevel %c", req);
|
return systemf("initctl -b runlevel %c", req);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: add non-pid1 process monitor here
|
/* XXX: add non-pid1 process monitor here
|
||||||
@@ -443,12 +559,13 @@ static int telinit(int argc, char *argv[])
|
|||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct wq crank = {
|
struct wq crank_work = {
|
||||||
.cb = crank_worker
|
.cb = crank_worker,
|
||||||
|
.delay = 10
|
||||||
};
|
};
|
||||||
struct wq final = {
|
struct wq bootstrap_work = {
|
||||||
.cb = final_worker,
|
.cb = bootstrap_worker,
|
||||||
.delay = 1000
|
.delay = 100
|
||||||
};
|
};
|
||||||
uev_ctx_t loop;
|
uev_ctx_t loop;
|
||||||
|
|
||||||
@@ -473,28 +590,40 @@ int main(int argc, char *argv[])
|
|||||||
console_init();
|
console_init();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initalize event context.
|
* Initialize event context.
|
||||||
*/
|
*/
|
||||||
uev_init1(&loop, 1);
|
uev_init1(&loop, 1);
|
||||||
ctx = &loop;
|
ctx = &loop;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set PATH, SHELL, PWD, and umask early to something sane
|
* Set PATH, SHELL, and PWD early to something sane
|
||||||
*/
|
*/
|
||||||
setenv("PATH", _PATH_STDPATH, 1);
|
setenv("PATH", _PATH_STDPATH, 1);
|
||||||
setenv("SHELL", _PATH_BSHELL, 1);
|
setenv("SHELL", _PATH_BSHELL, 1);
|
||||||
|
setenv("LOGNAME", "root", 1);
|
||||||
|
setenv("USER", "root", 1);
|
||||||
|
|
||||||
if (chdir("/"))
|
if (chdir("/"))
|
||||||
_pe("Failed cd /");
|
_pe("Failed cd /");
|
||||||
umask(0);
|
|
||||||
|
|
||||||
/* Allow progress, if enabled */
|
|
||||||
enable_progress(1);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In case of emergency.
|
* In case of emergency.
|
||||||
*/
|
*/
|
||||||
emergency_shell();
|
if (rescue) {
|
||||||
|
char *sulogin[] = {
|
||||||
|
_PATH_SULOGIN,
|
||||||
|
"sulogin",
|
||||||
|
};
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < NELEMS(sulogin); i++) {
|
||||||
|
if (systemf(sulogin[i]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
rescue = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Load plugins early, the first hook is in banner(), so we
|
* Load plugins early, the first hook is in banner(), so we
|
||||||
@@ -505,8 +634,14 @@ int main(int argc, char *argv[])
|
|||||||
/*
|
/*
|
||||||
* Hello world.
|
* Hello world.
|
||||||
*/
|
*/
|
||||||
|
enable_progress(1); /* Allow progress, if enabled */
|
||||||
banner();
|
banner();
|
||||||
|
|
||||||
|
if (osheading)
|
||||||
|
logit(LOG_CONSOLE | LOG_NOTICE, "%s, entering runlevel S", osheading);
|
||||||
|
else
|
||||||
|
logit(LOG_CONSOLE | LOG_NOTICE, "Entering runlevel S");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initial setup of signals, ignore all until we're up.
|
* Initial setup of signals, ignore all until we're up.
|
||||||
*/
|
*/
|
||||||
@@ -515,17 +650,18 @@ int main(int argc, char *argv[])
|
|||||||
/*
|
/*
|
||||||
* Initialize default control groups, if available
|
* Initialize default control groups, if available
|
||||||
*/
|
*/
|
||||||
cgroup_init();
|
cgroup_init(&loop);
|
||||||
|
|
||||||
|
|
||||||
/* Check and mount filesystems. */
|
/* Check and mount filesystems. */
|
||||||
fs_mount();
|
fs_mount_all();
|
||||||
|
|
||||||
/* Bootstrap conditions, needed for hooks */
|
/* Bootstrap conditions, needed for hooks */
|
||||||
cond_init();
|
cond_init();
|
||||||
|
|
||||||
/* Emit conditions for early hooks that ran before the
|
/*
|
||||||
* condition system was initialized in case anyone . */
|
* Emit conditions for early hooks that ran before the condition
|
||||||
|
* system was initialized in case anyone.
|
||||||
|
*/
|
||||||
cond_set_oneshot(plugin_hook_str(HOOK_BANNER));
|
cond_set_oneshot(plugin_hook_str(HOOK_BANNER));
|
||||||
cond_set_oneshot(plugin_hook_str(HOOK_ROOTFS_UP));
|
cond_set_oneshot(plugin_hook_str(HOOK_ROOTFS_UP));
|
||||||
|
|
||||||
@@ -534,6 +670,20 @@ int main(int argc, char *argv[])
|
|||||||
*/
|
*/
|
||||||
conf_init(&loop);
|
conf_init(&loop);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start built-in watchdogd as soon as possible, if enabled
|
||||||
|
*/
|
||||||
|
if (whichp(FINIT_LIBPATH_ "/watchdogd") && fexist(WDT_DEVNODE)) {
|
||||||
|
service_register(SVC_TYPE_SERVICE, "[123456789] cgroup.init name:watchdog :finit " FINIT_LIBPATH_ "/watchdogd -- Finit watchdog daemon", global_rlimit, NULL);
|
||||||
|
wdog = svc_find_by_nameid("watchdog", "finit");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start kernel event daemon as soon as possible, if enabled
|
||||||
|
*/
|
||||||
|
if (whichp(FINIT_LIBPATH_ "/keventd"))
|
||||||
|
service_register(SVC_TYPE_SERVICE, "[123456789] cgroup.init " FINIT_LIBPATH_ "/keventd -- Finit kernel event daemon", global_rlimit, NULL);
|
||||||
|
|
||||||
/* Base FS up, enable standard SysV init signals */
|
/* Base FS up, enable standard SysV init signals */
|
||||||
sig_setup(&loop);
|
sig_setup(&loop);
|
||||||
|
|
||||||
@@ -548,13 +698,17 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
_d("Starting initctl API responder ...");
|
_d("Starting initctl API responder ...");
|
||||||
api_init(&loop);
|
api_init(&loop);
|
||||||
umask(022);
|
|
||||||
|
|
||||||
_d("Starting the big state machine ...");
|
_d("Starting the big state machine ...");
|
||||||
schedule_work(&crank);
|
schedule_work(&crank_work);
|
||||||
|
|
||||||
_d("Starting bootstrap finalize timer ...");
|
_d("Starting bootstrap finalize timer ...");
|
||||||
schedule_work(&final);
|
schedule_work(&bootstrap_work);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Background service tasks
|
||||||
|
*/
|
||||||
|
service_init();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enter main loop to monitor /dev/initctl and services
|
* Enter main loop to monitor /dev/initctl and services
|
||||||
|
|||||||
+16
-5
@@ -30,10 +30,15 @@
|
|||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <sysexits.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
#include <uev/uev.h>
|
#include <uev/uev.h>
|
||||||
|
|
||||||
/* just in case */
|
/* just in case */
|
||||||
@@ -46,10 +51,13 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef FINIT_CGPATH
|
#ifndef FINIT_CGPATH
|
||||||
#define FINIT_CGPATH "/sys/fs/cgroup/finit"
|
#define FINIT_CGPATH "/sys/fs/cgroup"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define LOGIT_PATH FINIT_LIBPATH_ "/logit"
|
/* To use these, include config.h, or define FINIT_LIBPATH_ */
|
||||||
|
#define _PATH_LOGIT FINIT_LIBPATH_ "/logit"
|
||||||
|
#define _PATH_SULOGIN FINIT_LIBPATH_ "/sulogin"
|
||||||
|
#define _PATH_GETTY FINIT_LIBPATH_ "/getty"
|
||||||
|
|
||||||
#define CMD_SIZE 256
|
#define CMD_SIZE 256
|
||||||
#define LINE_SIZE 1024
|
#define LINE_SIZE 1024
|
||||||
@@ -71,10 +79,10 @@
|
|||||||
/* Finit extensions over std SysV */
|
/* Finit extensions over std SysV */
|
||||||
#define INIT_CMD_DEBUG 8 /* Toggle Finit debug */
|
#define INIT_CMD_DEBUG 8 /* Toggle Finit debug */
|
||||||
#define INIT_CMD_RELOAD 9 /* Reload *.conf in /etc/finit.d/ */
|
#define INIT_CMD_RELOAD 9 /* Reload *.conf in /etc/finit.d/ */
|
||||||
#define INIT_CMD_START_SVC 10
|
#define INIT_CMD_START_SVC 10 /* START service */
|
||||||
#define INIT_CMD_STOP_SVC 11
|
#define INIT_CMD_STOP_SVC 11
|
||||||
#define INIT_CMD_RELOAD_SVC 12 /* SIGHUP service */
|
#define INIT_CMD_RELOAD_SVC 12 /* SIGHUP service */
|
||||||
#define INIT_CMD_RESTART_SVC 13 /* STOP + START service */
|
#define INIT_CMD_RESTART_SVC 13 /* START service, clearing blocks */
|
||||||
#define INIT_CMD_UNUSED2 14 /* Unused, was INIT_CMD_QUERY_INETD */
|
#define INIT_CMD_UNUSED2 14 /* Unused, was INIT_CMD_QUERY_INETD */
|
||||||
#define INIT_CMD_UNUSED1 15 /* Unused, was INIT_CMD_EMIT */
|
#define INIT_CMD_UNUSED1 15 /* Unused, was INIT_CMD_EMIT */
|
||||||
#define INIT_CMD_GET_RUNLEVEL 16
|
#define INIT_CMD_GET_RUNLEVEL 16
|
||||||
@@ -105,11 +113,14 @@ extern int prevlevel;
|
|||||||
extern int debug;
|
extern int debug;
|
||||||
extern int rescue;
|
extern int rescue;
|
||||||
extern int single;
|
extern int single;
|
||||||
|
extern int bootstrap;
|
||||||
|
extern int kerndebug;
|
||||||
extern char *rcsd;
|
extern char *rcsd;
|
||||||
extern char *sdown;
|
extern char *sdown;
|
||||||
extern char *network;
|
extern char *network;
|
||||||
extern char *hostname;
|
extern char *hostname;
|
||||||
extern char *runparts;
|
extern char *runparts;
|
||||||
|
extern char *osheading;
|
||||||
extern uev_ctx_t *ctx;
|
extern uev_ctx_t *ctx;
|
||||||
|
|
||||||
#endif /* FINIT_H_ */
|
#endif /* FINIT_H_ */
|
||||||
|
|||||||
+90
-78
@@ -21,45 +21,46 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <limits.h> /* LOGIN_NAME_MAX */
|
||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
|
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
|
#include <unistd.h> /* sysconf() */
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "cgroup.h"
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "sig.h"
|
|
||||||
#include "utmp-api.h"
|
#include "utmp-api.h"
|
||||||
|
|
||||||
#ifndef _PATH_LOGIN
|
#ifndef _PATH_LOGIN
|
||||||
#define _PATH_LOGIN "/bin/login"
|
#define _PATH_LOGIN "/bin/login"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define print(s) (void)write(STDOUT_FILENO, s, strlen(s))
|
#ifndef LOGIN_NAME_MIN
|
||||||
|
#define LOGIN_NAME_MIN 64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static long logname_len = 32; /* useradd(1) limit at 32 chars */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read one character from stdin.
|
* Read one character from stdin.
|
||||||
*/
|
*/
|
||||||
static int readch(char *tty)
|
static int readch(void)
|
||||||
{
|
{
|
||||||
int st;
|
|
||||||
char ch1;
|
char ch1;
|
||||||
|
int st;
|
||||||
|
|
||||||
st = read(STDIN_FILENO, &ch1, 1);
|
st = read(STDIN_FILENO, &ch1, 1);
|
||||||
if (st == 0) {
|
if (st <= 0)
|
||||||
print("\n");
|
return -1;
|
||||||
_exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (st < 0)
|
|
||||||
errx(1, "getty: %s: read error", tty);
|
|
||||||
|
|
||||||
return ch1 & 0xFF;
|
return ch1 & 0xFF;
|
||||||
}
|
}
|
||||||
@@ -74,31 +75,32 @@ static void do_parse(char *line, struct utsname *uts, char *tty)
|
|||||||
s0 = line;
|
s0 = line;
|
||||||
for (s = line; *s != 0; s++) {
|
for (s = line; *s != 0; s++) {
|
||||||
if (*s == '\\') {
|
if (*s == '\\') {
|
||||||
(void)write(1, s0, s - s0);
|
if ((s - s0) > 0)
|
||||||
|
dprint(STDOUT_FILENO, s0, s - s0);
|
||||||
s0 = s + 2;
|
s0 = s + 2;
|
||||||
switch (*++s) {
|
switch (*++s) {
|
||||||
case 'l':
|
case 'l':
|
||||||
print(tty);
|
dprint(STDOUT_FILENO, tty, 0);
|
||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
print(uts->machine);
|
dprint(STDOUT_FILENO, uts->machine, 0);
|
||||||
break;
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
print(uts->nodename);
|
dprint(STDOUT_FILENO, uts->nodename, 0);
|
||||||
break;
|
break;
|
||||||
#ifdef _GNU_SOURCE
|
#ifdef _GNU_SOURCE
|
||||||
case 'o':
|
case 'o':
|
||||||
print(uts->domainname);
|
dprint(STDOUT_FILENO, uts->domainname, 0);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case 'r':
|
case 'r':
|
||||||
print(uts->release);
|
dprint(STDOUT_FILENO, uts->release, 0);
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
print(uts->sysname);
|
dprint(STDOUT_FILENO, uts->sysname, 0);
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
print(uts->version);
|
dprint(STDOUT_FILENO, uts->version, 0);
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
goto leave;
|
goto leave;
|
||||||
@@ -109,7 +111,8 @@ static void do_parse(char *line, struct utsname *uts, char *tty)
|
|||||||
}
|
}
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
(void)write(1, s0, s - s0);
|
if ((s - s0) > 0)
|
||||||
|
dprint(STDOUT_FILENO, s0, s - s0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -142,10 +145,10 @@ static void do_issue(char *tty)
|
|||||||
/*
|
/*
|
||||||
* Handle the process of a GETTY.
|
* Handle the process of a GETTY.
|
||||||
*/
|
*/
|
||||||
static void do_getty(char *tty, char *name, size_t len)
|
static int get_logname(char *tty, char *name, size_t len)
|
||||||
{
|
{
|
||||||
int ch;
|
|
||||||
char *np;
|
char *np;
|
||||||
|
int ch;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Display prompt.
|
* Display prompt.
|
||||||
@@ -156,14 +159,9 @@ static void do_getty(char *tty, char *name, size_t len)
|
|||||||
do_issue(tty);
|
do_issue(tty);
|
||||||
|
|
||||||
np = name;
|
np = name;
|
||||||
while ((ch = readch(tty)) != '\n') {
|
while ((ch = readch()) != '\n') {
|
||||||
if (ch == CTRL('U')) {
|
if (ch < 0)
|
||||||
while (np > name) {
|
return 1;
|
||||||
(void)write(1, "\b \b", 3);
|
|
||||||
np--;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (np < name + len)
|
if (np < name + len)
|
||||||
*np++ = ch;
|
*np++ = ch;
|
||||||
@@ -175,6 +173,7 @@ static void do_getty(char *tty, char *name, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
name[len - 1] = 0;
|
name[len - 1] = 0;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -186,26 +185,28 @@ static int do_login(char *name)
|
|||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
cgroup_user(name);
|
|
||||||
execl(_PATH_LOGIN, _PATH_LOGIN, name, NULL);
|
execl(_PATH_LOGIN, _PATH_LOGIN, name, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Failed to exec login, should be impossible. Try a starting a
|
* Failed to exec login, should not happen on normal systems.
|
||||||
* fallback shell instead.
|
* Try a starting a rescue shell instead.
|
||||||
*
|
|
||||||
* Note: Add /etc/securetty handling.
|
|
||||||
*/
|
*/
|
||||||
warnx("Failed exec %s, attempting fallback to %s ...", _PATH_LOGIN, _PATH_BSHELL);
|
if (fstat(0, &st) == 0 && S_ISCHR(st.st_mode)) {
|
||||||
if (fstat(0, &st) == 0 && S_ISCHR(st.st_mode))
|
warnx("Failed exec %s, attempting fallback to %s ...", _PATH_LOGIN, _PATH_SULOGIN);
|
||||||
|
execl(_PATH_SULOGIN, _PATH_SULOGIN, NULL);
|
||||||
|
|
||||||
|
warnx("Failed exec %s, attempting fallback to %s ...", _PATH_SULOGIN, _PATH_BSHELL);
|
||||||
execl(_PATH_BSHELL, _PATH_BSHELL, NULL);
|
execl(_PATH_BSHELL, _PATH_BSHELL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
return 1; /* We shouldn't get here ... */
|
return 1; /* We shouldn't get here ... */
|
||||||
}
|
}
|
||||||
|
|
||||||
int getty(char *tty, speed_t speed, char *term, char *user)
|
static int getty(char *tty, speed_t speed, char *term, char *user)
|
||||||
{
|
{
|
||||||
const char cln[] = "\r\e[2K\n";
|
const char cln[] = "\r\e[K\n";
|
||||||
char name[30];
|
char name[logname_len + 1]; /* +1 for NUL termination */
|
||||||
|
pid_t sid;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clean up tty name.
|
* Clean up tty name.
|
||||||
@@ -213,59 +214,70 @@ int getty(char *tty, speed_t speed, char *term, char *user)
|
|||||||
if (!strncmp(tty, _PATH_DEV, strlen(_PATH_DEV)))
|
if (!strncmp(tty, _PATH_DEV, strlen(_PATH_DEV)))
|
||||||
tty += 5;
|
tty += 5;
|
||||||
|
|
||||||
/* Set up TTY, re-enabling ISIG et al. */
|
|
||||||
stty(STDIN_FILENO, speed);
|
|
||||||
(void)write(STDERR_FILENO, cln, strlen(cln));
|
|
||||||
|
|
||||||
/* The getty process is responsible for the UTMP login record */
|
/* The getty process is responsible for the UTMP login record */
|
||||||
utmp_set_login(tty, NULL);
|
utmp_set_login(tty, NULL);
|
||||||
if (!user)
|
|
||||||
do_getty(tty, name, sizeof(name));
|
/* Replace "Please press enter ..." with login: */
|
||||||
else
|
dprint(STDERR_FILENO, cln, strlen(cln));
|
||||||
|
|
||||||
|
restart:
|
||||||
|
stty(STDIN_FILENO, speed);
|
||||||
|
if (!user) {
|
||||||
|
if (get_logname(tty, name, sizeof(name)))
|
||||||
|
goto restart;
|
||||||
|
} else
|
||||||
strlcpy(name, user, sizeof(name));
|
strlcpy(name, user, sizeof(name));
|
||||||
|
|
||||||
|
/* check current session associated with our tty */
|
||||||
|
sid = tcgetsid(0);
|
||||||
|
if (sid < 0 || getpid() != sid) {
|
||||||
|
if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) == -1)
|
||||||
|
err(1, "failed stealing controlling TTY");
|
||||||
|
}
|
||||||
|
|
||||||
if (term && term[0])
|
if (term && term[0])
|
||||||
setenv("TERM", term, 1);
|
setenv("TERM", term, 1);
|
||||||
|
|
||||||
return do_login(name);
|
return do_login(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sh(char *tty)
|
static int usage(int rc)
|
||||||
{
|
{
|
||||||
struct termios term;
|
warnx("usage: getty [-h?] tty [speed [term]]");
|
||||||
char *args[2] = {
|
return rc;
|
||||||
NULL,
|
}
|
||||||
NULL
|
|
||||||
};
|
|
||||||
char *arg0;
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
/* The getty process is usually responsible for the UTMP login record */
|
int main(int argc, char *argv[])
|
||||||
utmp_set_login(tty, NULL);
|
{
|
||||||
|
char *tty, *speed = "0", *term = NULL;
|
||||||
|
int c;
|
||||||
|
|
||||||
/* Set up TTY, re-enabling ISIG et al. */
|
while ((c = getopt(argc, argv, "h?")) != EOF) {
|
||||||
stty(STDIN_FILENO, B0);
|
switch(c) {
|
||||||
|
case 'h':
|
||||||
/* Start /bin/sh as a login shell, i.e. with a prefix '-' */
|
case '?':
|
||||||
len = strlen(_PATH_BSHELL) + 2;
|
return usage(0);
|
||||||
arg0 = malloc(len);
|
default:
|
||||||
if (!arg0)
|
return usage(1);
|
||||||
err(1, "Failed allocating memory");
|
}
|
||||||
snprintf(arg0, len, "-%s", _PATH_BSHELL);
|
|
||||||
args[0] = arg0;
|
|
||||||
|
|
||||||
/* Reenable Ctrl-D and Ctrl-C, and ... */
|
|
||||||
if (!tcgetattr(STDIN_FILENO, &term)) {
|
|
||||||
term.c_lflag |= ISIG;
|
|
||||||
term.c_cc[VEOF] = CEOF;
|
|
||||||
term.c_cc[VINTR] = CINTR;
|
|
||||||
tcsetattr(STDIN_FILENO, TCSAFLUSH, &term);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ... unblock signals in general */
|
if (optind >= argc)
|
||||||
sig_unblock();
|
return usage(1);
|
||||||
|
|
||||||
return execv(_PATH_BSHELL, args);
|
tty = argv[optind++];
|
||||||
|
if (optind < argc)
|
||||||
|
speed = argv[optind++];
|
||||||
|
if (optind < argc)
|
||||||
|
term = argv[optind++];
|
||||||
|
|
||||||
|
logname_len = sysconf(_SC_LOGIN_NAME_MAX);
|
||||||
|
if (logname_len == -1i)
|
||||||
|
logname_len = LOGIN_NAME_MAX;
|
||||||
|
if (logname_len < LOGIN_NAME_MIN)
|
||||||
|
logname_len = LOGIN_NAME_MIN;
|
||||||
|
|
||||||
|
return getty(tty, atoi(speed), term, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+122
-141
@@ -31,7 +31,11 @@
|
|||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
@@ -68,90 +72,14 @@ static const char *status2[] = STATUS_CLASS;
|
|||||||
#define CHOOSE(x,y,z) z
|
#define CHOOSE(x,y,z) z
|
||||||
static const char *color[] = STATUS_CLASS;
|
static const char *color[] = STATUS_CLASS;
|
||||||
|
|
||||||
/*
|
|
||||||
* System consoles, can be given multiple times on the kernel cmdline.
|
|
||||||
* We support only three currently. If none are given on the cmdline
|
|
||||||
* we probe /sys/class/tty/console/active and use the first (default).
|
|
||||||
*/
|
|
||||||
#define MAX_CONS 3
|
|
||||||
|
|
||||||
static char *consoles[MAX_CONS];
|
|
||||||
static int fds[MAX_CONS];
|
|
||||||
static int num_cons = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* System default console is always the first
|
|
||||||
*/
|
|
||||||
char *console(void)
|
char *console(void)
|
||||||
{
|
{
|
||||||
return consoles[0];
|
return _PATH_CONSOLE;
|
||||||
}
|
|
||||||
|
|
||||||
static void add_console(char *cons)
|
|
||||||
{
|
|
||||||
char path[80];
|
|
||||||
char *ptr;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (num_cons == NELEMS(fds)) {
|
|
||||||
_e("too many consoles, max %d supported", NELEMS(fds));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* drop any options */
|
|
||||||
ptr = strchr(cons, ',');
|
|
||||||
if (ptr)
|
|
||||||
*ptr = 0;
|
|
||||||
|
|
||||||
snprintf(path, sizeof(path), "/dev/%s", cons);
|
|
||||||
|
|
||||||
/* check for and skip duplicates */
|
|
||||||
for (i = 0; i < num_cons; i++) {
|
|
||||||
if (string_compare(path, consoles[i]))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* this requires we have /dev mounted && a device there */
|
|
||||||
fds[num_cons] = open(path, O_WRONLY);
|
|
||||||
if (fds[num_cons] < 0) {
|
|
||||||
_pe("Failed opening console %s", path);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
consoles[num_cons] = strdup(path);
|
|
||||||
num_cons++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void find_active_consoles(void)
|
|
||||||
{
|
|
||||||
char *cons, *ptr, *tok;
|
|
||||||
char buf[512];
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
fp = fopen("/sys/class/tty/console/active", "r");
|
|
||||||
if (!fp) {
|
|
||||||
fallback:
|
|
||||||
_d("Using fallback /dev/console");
|
|
||||||
add_console("/dev/console");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr = fgets(buf, sizeof(buf), fp);
|
|
||||||
fclose(fp);
|
|
||||||
if (!ptr)
|
|
||||||
goto fallback;
|
|
||||||
|
|
||||||
cons = chomp(ptr);
|
|
||||||
_d("Using these system consoles: %s", cons);
|
|
||||||
while ((tok = strtok(cons, " \t"))) {
|
|
||||||
cons = NULL;
|
|
||||||
add_console(tok);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void console_init(void)
|
void console_init(void)
|
||||||
{
|
{
|
||||||
find_active_consoles();
|
ttinit();
|
||||||
screen_init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t cprintf(const char *fmt, ...)
|
ssize_t cprintf(const char *fmt, ...)
|
||||||
@@ -160,14 +88,12 @@ ssize_t cprintf(const char *fmt, ...)
|
|||||||
char buf[len < 256 ? 256 : len];
|
char buf[len < 256 ? 256 : len];
|
||||||
size_t size;
|
size_t size;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
int i;
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
size = vsnprintf(buf, sizeof(buf), fmt, ap);
|
size = vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
for (i = 0; i < num_cons; i++)
|
dprint(STDERR_FILENO, buf, size);
|
||||||
(void)write(fds[i], buf, size);
|
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
@@ -202,6 +128,49 @@ void show_progress(pstyle_t style)
|
|||||||
progress_onoff = style;
|
progress_onoff = style;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find PRETTY_NAME in /etc/os-release to use as heading at boot
|
||||||
|
* and on runlevel changes. Fallback: "Finit vX.YY"
|
||||||
|
*/
|
||||||
|
char *release_heading(void)
|
||||||
|
{
|
||||||
|
char *name = NULL;
|
||||||
|
char buf[256];
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopen("/etc/os-release", "r");
|
||||||
|
if (fp) {
|
||||||
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
char *ptr = &buf[12];
|
||||||
|
|
||||||
|
if (strncmp(buf, "PRETTY_NAME=", 12))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (*ptr == '"' || *ptr == '\'') {
|
||||||
|
char *end = &ptr[strlen(ptr) - 1];
|
||||||
|
char q = *ptr;
|
||||||
|
|
||||||
|
while (end > ptr && isspace(*end))
|
||||||
|
*end-- = 0;
|
||||||
|
|
||||||
|
if (*end == q) {
|
||||||
|
*end = 0;
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
name = strdup(ptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
name = strdup(PACKAGE_NAME " v" PACKAGE_VERSION);
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return screen length of string, not counting escape chars, and
|
* Return screen length of string, not counting escape chars, and
|
||||||
* accounting for unicode characters as only one screen byte wide
|
* accounting for unicode characters as only one screen byte wide
|
||||||
@@ -252,20 +221,20 @@ static char *pad(char *buf, size_t len, char *ch, size_t width)
|
|||||||
|
|
||||||
void print_banner(const char *heading)
|
void print_banner(const char *heading)
|
||||||
{
|
{
|
||||||
char buf[4 * SCREEN_WIDTH];
|
char buf[4 * ttcols];
|
||||||
|
|
||||||
if (progress_style == PROGRESS_SILENT)
|
if (progress_style == PROGRESS_SILENT)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
memset(buf, 0, sizeof(buf));
|
buf[0] = 0;
|
||||||
strlcat(buf, "\r\e[2K", sizeof(buf));
|
strlcat(buf, "\r\e[K", sizeof(buf));
|
||||||
|
|
||||||
if (progress_style == PROGRESS_CLASSIC) {
|
if (progress_style == PROGRESS_CLASSIC) {
|
||||||
strlcat(buf, "\e[1m", sizeof(buf));
|
strlcat(buf, "\e[1m", sizeof(buf));
|
||||||
strlcat(buf, heading, sizeof(buf));
|
strlcat(buf, heading, sizeof(buf));
|
||||||
pad(buf, sizeof(buf), "=", SCREEN_WIDTH + 10);
|
pad(buf, sizeof(buf), "=", ttcols + 10);
|
||||||
} else {
|
} else {
|
||||||
size_t wmax = 80 <= SCREEN_WIDTH ? 80 : SCREEN_WIDTH;
|
size_t wmax = 80 <= ttcols ? 80 : ttcols;
|
||||||
|
|
||||||
/* • • • Foo System ═══════════════════════════════════════════════ */
|
/* • • • Foo System ═══════════════════════════════════════════════ */
|
||||||
/* ⬤ ⬤ ⬤ Foo System ═══════════════════════════════════════════════ */
|
/* ⬤ ⬤ ⬤ Foo System ═══════════════════════════════════════════════ */
|
||||||
@@ -328,7 +297,7 @@ static char *status(int rc)
|
|||||||
|
|
||||||
void printv(const char *fmt, va_list ap)
|
void printv(const char *fmt, va_list ap)
|
||||||
{
|
{
|
||||||
char buf[SCREEN_WIDTH];
|
char buf[ttcols];
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
if (!fmt || progress_style == PROGRESS_SILENT)
|
if (!fmt || progress_style == PROGRESS_SILENT)
|
||||||
@@ -336,14 +305,14 @@ void printv(const char *fmt, va_list ap)
|
|||||||
|
|
||||||
delline();
|
delline();
|
||||||
|
|
||||||
memset(buf, 0, sizeof(buf));
|
buf[0] = 0;
|
||||||
len = print_timestamp(buf, sizeof(buf));
|
len = print_timestamp(buf, sizeof(buf));
|
||||||
vsnprintf(&buf[len], sizeof(buf) - len, fmt, ap);
|
vsnprintf(&buf[len], sizeof(buf) - len, fmt, ap);
|
||||||
|
|
||||||
if (progress_style == PROGRESS_CLASSIC)
|
if (progress_style == PROGRESS_CLASSIC)
|
||||||
cprintf("\r%s ", pad(buf, sizeof(buf), ".", sizeof(buf)));
|
cprintf("\r%s ", pad(buf, sizeof(buf), ".", sizeof(buf)));
|
||||||
else
|
else
|
||||||
cprintf("\r\e[2K%s%s", status(3), buf);
|
cprintf("\r\e[K%s%s", status(3), buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void print(int rc, const char *fmt, ...)
|
void print(int rc, const char *fmt, ...)
|
||||||
@@ -410,6 +379,64 @@ int getgroup(char *group)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* get current user */
|
||||||
|
int getcuser(char *buf, size_t len)
|
||||||
|
{
|
||||||
|
char *ptr = "root";
|
||||||
|
|
||||||
|
#ifndef ENABLE_STATIC
|
||||||
|
struct passwd *pw = getpwuid(getuid());
|
||||||
|
|
||||||
|
if (pw)
|
||||||
|
ptr = pw->pw_name;
|
||||||
|
#endif
|
||||||
|
if (strlcpy(buf, ptr, len) > len)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get current group */
|
||||||
|
int getcgroup(char *buf, size_t len)
|
||||||
|
{
|
||||||
|
char *ptr = "root";
|
||||||
|
|
||||||
|
#ifndef ENABLE_STATIC
|
||||||
|
struct group *gr = getgrgid(getgid());
|
||||||
|
|
||||||
|
if (gr)
|
||||||
|
ptr = gr->gr_name;
|
||||||
|
#endif
|
||||||
|
if (strlcpy(buf, ptr, len) > len)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mksubsys(const char *dir, mode_t mode, char *user, char *group)
|
||||||
|
{
|
||||||
|
mode_t omask;
|
||||||
|
int uid, gid;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
omask = umask(0);
|
||||||
|
|
||||||
|
uid = getuser(user, NULL);
|
||||||
|
if (uid >= 0) {
|
||||||
|
gid = getgroup(group);
|
||||||
|
if (gid < 0)
|
||||||
|
gid = 0;
|
||||||
|
|
||||||
|
rc = makedir(dir, mode);
|
||||||
|
if (chown(dir, uid, gid))
|
||||||
|
_pe("Failed chown(%s, %d, %d)", dir, uid, gid);
|
||||||
|
}
|
||||||
|
|
||||||
|
umask(omask);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
void set_hostname(char **hostname)
|
void set_hostname(char **hostname)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
@@ -438,8 +465,10 @@ void set_hostname(char **hostname)
|
|||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (*hostname)
|
if (*hostname) {
|
||||||
(void)sethostname(*hostname, strlen(*hostname));
|
if (sethostname(*hostname, strlen(*hostname)))
|
||||||
|
_pe("Failed sethostnaem(%s)", *hostname);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -477,6 +506,7 @@ void networking(int updown)
|
|||||||
run("ifdown -a");
|
run("ifdown -a");
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
|
cgroup_service("network", pid, NULL);
|
||||||
|
|
||||||
print(pid > 0 ? 0 : 1, "%s networking", updown ? "Starting" : "Stopping");
|
print(pid > 0 ? 0 : 1, "%s networking", updown ? "Starting" : "Stopping");
|
||||||
}
|
}
|
||||||
@@ -534,55 +564,6 @@ void endfsent(void)
|
|||||||
}
|
}
|
||||||
#endif /* HAVE_GETFSENT */
|
#endif /* HAVE_GETFSENT */
|
||||||
|
|
||||||
static int hasopt(char *opts, char *opt)
|
|
||||||
{
|
|
||||||
char buf[strlen(opts) + 1];
|
|
||||||
char *ptr;
|
|
||||||
|
|
||||||
memcpy(buf, opts, sizeof(buf));
|
|
||||||
ptr = strtok(buf, ",");
|
|
||||||
while (ptr) {
|
|
||||||
if (!strcmp(ptr, opt))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
ptr = strtok(NULL, ",");
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ismnt(char *file, char *dir, char *mode)
|
|
||||||
{
|
|
||||||
struct mntent *mnt;
|
|
||||||
int found = 0;
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
fp = setmntent(file, "r");
|
|
||||||
if (!fp)
|
|
||||||
return 0; /* Dunno, maybe not */
|
|
||||||
|
|
||||||
while ((mnt = getmntent(fp))) {
|
|
||||||
if (!strcmp(mnt->mnt_dir, dir)) {
|
|
||||||
if (mode) {
|
|
||||||
if (hasopt(mnt->mnt_opts, mode))
|
|
||||||
found = 1;
|
|
||||||
} else
|
|
||||||
found = 1;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
endmntent(fp);
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Requires /proc to be mounted */
|
|
||||||
int fismnt(char *dir)
|
|
||||||
{
|
|
||||||
return ismnt("/proc/mounts", dir, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
|
|||||||
+32
-8
@@ -26,12 +26,17 @@
|
|||||||
#define FINIT_HELPERS_H_
|
#define FINIT_HELPERS_H_
|
||||||
|
|
||||||
#include <mntent.h>
|
#include <mntent.h>
|
||||||
|
#include <sched.h> /* sched_yield() */
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
|
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
#define PROGRESS_DEFAULT PROGRESS_MODERN
|
#define PROGRESS_DEFAULT PROGRESS_MODERN
|
||||||
@@ -67,11 +72,10 @@ char *strip_line (char *line);
|
|||||||
void enable_progress (int onoff);
|
void enable_progress (int onoff);
|
||||||
void show_progress (pstyle_t style);
|
void show_progress (pstyle_t style);
|
||||||
|
|
||||||
int getty (char *tty, speed_t speed, char *term, char *user);
|
char *release_heading (void);
|
||||||
int sh (char *tty);
|
|
||||||
|
|
||||||
int stty (int fd, speed_t speed);
|
|
||||||
speed_t stty_parse_speed(char *baud);
|
speed_t stty_parse_speed(char *baud);
|
||||||
|
void stty (int fd, speed_t speed);
|
||||||
|
|
||||||
void print_banner (const char *heading);
|
void print_banner (const char *heading);
|
||||||
void printv (const char *fmt, va_list ap);
|
void printv (const char *fmt, va_list ap);
|
||||||
@@ -81,6 +85,12 @@ int print_result (int fail);
|
|||||||
|
|
||||||
int getuser (char *username, char **home);
|
int getuser (char *username, char **home);
|
||||||
int getgroup (char *group);
|
int getgroup (char *group);
|
||||||
|
|
||||||
|
int getcuser (char *buf, size_t len);
|
||||||
|
int getcgroup (char *buf, size_t len);
|
||||||
|
|
||||||
|
int mksubsys (const char *dir, mode_t mode, char *user, char *group);
|
||||||
|
|
||||||
void set_hostname (char **hostname);
|
void set_hostname (char **hostname);
|
||||||
void networking (int updown);
|
void networking (int updown);
|
||||||
|
|
||||||
@@ -88,8 +98,7 @@ int complete (char *cmd, int pid);
|
|||||||
int run (char *cmd);
|
int run (char *cmd);
|
||||||
int run_interactive (char *cmd, char *fmt, ...);
|
int run_interactive (char *cmd, char *fmt, ...);
|
||||||
int exec_runtask (char *cmd, char *args[]);
|
int exec_runtask (char *cmd, char *args[]);
|
||||||
pid_t run_getty (char *tty, char *baud, char *term, int noclear, int nowait, struct rlimit rlimit[]);
|
pid_t run_getty (char *tty, char *cmd, char *args[], int noclear, int nowait, struct rlimit rlimit[]);
|
||||||
pid_t run_getty2 (char *tty, char *cmd, char *args[], int noclear, int nowait, struct rlimit rlimit[]);
|
|
||||||
pid_t run_sh (char *tty, int noclear, int nowait, struct rlimit rlimit[]);
|
pid_t run_sh (char *tty, int noclear, int nowait, struct rlimit rlimit[]);
|
||||||
int run_parts (char *dir, char *cmd);
|
int run_parts (char *dir, char *cmd);
|
||||||
|
|
||||||
@@ -103,8 +112,23 @@ static inline int create(char *path, mode_t mode, uid_t uid, gid_t gid)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ismnt (char *file, char *dir, char *mode);
|
static inline int dprint(int fd, const char *s, size_t len)
|
||||||
int fismnt (char *dir);
|
{
|
||||||
|
size_t loop = 3;
|
||||||
|
int rc = -1;
|
||||||
|
|
||||||
|
if (!len)
|
||||||
|
len = strlen(s);
|
||||||
|
|
||||||
|
while (loop--) {
|
||||||
|
rc = write(fd, s, len);
|
||||||
|
if (rc == -1 && errno == EINTR)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* FINIT_HELPERS_H_ */
|
#endif /* FINIT_HELPERS_H_ */
|
||||||
|
|
||||||
|
|||||||
+510
-297
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