mirror of
https://github.com/troglobit/finit.git
synced 2026-10-12 10:12:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f483a8aeaa | ||
|
|
e3e220ce8e | ||
|
|
fc653e4293 | ||
|
|
94d55cb7dd | ||
|
|
0e84ecf143 | ||
|
|
0e93dfd640 | ||
|
|
4dff8237f1 | ||
|
|
35400f2a8b | ||
|
|
9a76f0862c | ||
|
|
fb8a7caa99 | ||
|
|
f8bed5c7af | ||
|
|
da6fa482e7 | ||
|
|
fdf8e48c99 | ||
|
|
195155a7f5 | ||
|
|
6934ba4dbc | ||
|
|
fdbd25c1b5 | ||
|
|
467f1cca81 | ||
|
|
d6fdf4a806 | ||
|
|
4be9d97e61 | ||
|
|
021d011493 | ||
|
|
e988d38f71 | ||
|
|
8690fc732b | ||
|
|
ceb2945da9 | ||
|
|
1b8a0951f5 | ||
|
|
a27b8462d1 | ||
|
|
edc2d53923 | ||
|
|
4aae3403f5 | ||
|
|
73423699fd | ||
|
|
0cce69892a | ||
|
|
3ca6256f87 | ||
|
|
eca3098c0e | ||
|
|
7af3461e3c | ||
|
|
b62c975dc4 | ||
|
|
b368bd1420 | ||
|
|
060e97d64e | ||
|
|
9b17ce0b7c | ||
|
|
50f2cbf600 | ||
|
|
837bca3947 | ||
|
|
16180675db | ||
|
|
d3c6351ed8 | ||
|
|
7e37ac348e | ||
|
|
30e68658ae | ||
|
|
a179308819 | ||
|
|
4cdd5f8ccc | ||
|
|
7f19474d8d | ||
|
|
a5941165a0 | ||
|
|
181d9556a1 | ||
|
|
bf72e6b9c8 | ||
|
|
8db521d379 | ||
|
|
f46ac20fb0 | ||
|
|
d70d86e9fe | ||
|
|
38db52aa4e | ||
|
|
bf62bee440 | ||
|
|
e50fe3b060 | ||
|
|
d6c55282ef | ||
|
|
1015124530 | ||
|
|
38885aaa67 | ||
|
|
a685b698c2 | ||
|
|
9bce8f9584 | ||
|
|
d04b04d73a | ||
|
|
72125430e6 | ||
|
|
561387ce57 | ||
|
|
e2d1930e6c | ||
|
|
6f2a124240 | ||
|
|
10392e9639 | ||
|
|
605c489937 | ||
|
|
26409bc860 | ||
|
|
b01f9f38f2 | ||
|
|
2ddbb805ca | ||
|
|
ed999d9a80 | ||
|
|
82cc10be88 | ||
|
|
30fb9780d7 | ||
|
|
09f46f62b4 | ||
|
|
bc4e7a8d8d | ||
|
|
e2753d75f8 | ||
|
|
addb8c4019 | ||
|
|
0c4a9b62c2 | ||
|
|
57c97d8190 | ||
|
|
b0d0ca76cf | ||
|
|
5240c0cf19 | ||
|
|
a02f369a89 | ||
|
|
fa2a113cbf | ||
|
|
4c5ac38e2c | ||
|
|
f89ebb91a8 | ||
|
|
477bc064d5 | ||
|
|
96376126b3 | ||
|
|
1c150928cb | ||
|
|
7a8d4e2c6b | ||
|
|
fb956fd2f5 | ||
|
|
e6e4d814f3 | ||
|
|
544d44886a | ||
|
|
cec2d5a4db | ||
|
|
539d215d0e | ||
|
|
10ef0e7de6 | ||
|
|
05e6b3e752 | ||
|
|
3e4be9a122 | ||
|
|
5593372ffb | ||
|
|
05be281301 | ||
|
|
108bbf56dd | ||
|
|
a61aa73419 | ||
|
|
f39626f132 | ||
|
|
c0b6f3af08 | ||
|
|
5d8fcfdf13 | ||
|
|
e4830c5614 | ||
|
|
f33261af6b | ||
|
|
e7516f2b63 | ||
|
|
d18167fe1d | ||
|
|
7d3f95c0a9 | ||
|
|
86c5bbb03d | ||
|
|
7530bb74f6 | ||
|
|
54dd726d16 | ||
|
|
bd9bb92ca0 | ||
|
|
01cb088e51 | ||
|
|
3d91112e0d | ||
|
|
16aef80682 | ||
|
|
fd34914936 | ||
|
|
21a890a04e | ||
|
|
7f5f7e8ef6 | ||
|
|
ff937576ea | ||
|
|
7d831170ae | ||
|
|
6a21ac55ad | ||
|
|
a0820c7f20 | ||
|
|
6d58c9ed0b | ||
|
|
bc2ffbc767 | ||
|
|
4c1fc2410e | ||
|
|
70e1aa889a | ||
|
|
c8c5e4e88a | ||
|
|
86c1398778 | ||
|
|
b37fa2b417 | ||
|
|
a91e197553 | ||
|
|
5adb92ca1b | ||
|
|
cfc99c4e8b | ||
|
|
3e51ed1c55 | ||
|
|
b5df0a6274 | ||
|
|
cbe8d56042 | ||
|
|
a3ec792b44 | ||
|
|
c24855d4d5 | ||
|
|
014e457fda | ||
|
|
21d89c7e24 | ||
|
|
639fb76f5a | ||
|
|
30c189b116 | ||
|
|
e2a8803f7a | ||
|
|
209e140ddd | ||
|
|
2e3fa72924 | ||
|
|
1502838a0d | ||
|
|
377c8bce8c | ||
|
|
a39d958d25 | ||
|
|
7f8a96a73e | ||
|
|
5c2577214d | ||
|
|
f03206a694 | ||
|
|
f0e328edc9 | ||
|
|
13342f2bd9 | ||
|
|
c926160853 | ||
|
|
462d5b22b4 | ||
|
|
b1bfab08f3 | ||
|
|
aeb48ef04b | ||
|
|
b8b200ad75 | ||
|
|
c148d8d783 | ||
|
|
27ba3b27f5 | ||
|
|
b4af86255d | ||
|
|
01a007b388 | ||
|
|
0e28741dcb | ||
|
|
c993feeb44 | ||
|
|
ec17f0aa23 | ||
|
|
6baf2990e8 | ||
|
|
6416e2a1a4 | ||
|
|
7c42986800 | ||
|
|
6f802a7ff1 | ||
|
|
879721839e | ||
|
|
20290a4166 | ||
|
|
ba77e4f217 | ||
|
|
e7b18feca5 | ||
|
|
4a90a3e8ef | ||
|
|
6d14ff84d3 | ||
|
|
89cc6017df | ||
|
|
f6fafdbd23 | ||
|
|
3480e42687 | ||
|
|
053c1643a7 | ||
|
|
2018cac050 | ||
|
|
f9090f535d | ||
|
|
10577f3e48 | ||
|
|
07f7caef0d | ||
|
|
093b3ba467 | ||
|
|
c63279630b | ||
|
|
4755e5206b | ||
|
|
2002157032 | ||
|
|
094e00d405 | ||
|
|
e01836c506 | ||
|
|
685f332c6e | ||
|
|
ae09272bcc | ||
|
|
d16f7e0c88 | ||
|
|
063d645d95 | ||
|
|
f87e9d8880 | ||
|
|
e8099f1bfa | ||
|
|
7dc7f9a968 | ||
|
|
996ab8c6c6 | ||
|
|
16c2198304 | ||
|
|
ecca01dea0 | ||
|
|
bda3cdd3ad | ||
|
|
4811f76294 | ||
|
|
0aba704312 | ||
|
|
57329832d0 | ||
|
|
078a1d0c95 | ||
|
|
0e695aa0c7 | ||
|
|
f7a1514131 | ||
|
|
11bc87ecc3 | ||
|
|
e1c59a2515 | ||
|
|
2faefd44a2 | ||
|
|
6fa3aa41df | ||
|
|
ef9e9ec786 | ||
|
|
d77e3a6113 | ||
|
|
0b1258b44c | ||
|
|
62dad82ba8 | ||
|
|
5423b5b0a2 | ||
|
|
6b10174bcb | ||
|
|
ec94f4d321 | ||
|
|
69800537f2 | ||
|
|
61faedb0b5 | ||
|
|
61014431aa | ||
|
|
49bd63994c | ||
|
|
85b29d9407 | ||
|
|
b83fdea49b | ||
|
|
beec0ee590 | ||
|
|
4121113688 | ||
|
|
62da379472 | ||
|
|
3c9053b055 | ||
|
|
71b07ce2bd | ||
|
|
ebea3d273e | ||
|
|
f3a76b8a63 | ||
|
|
ba93791077 | ||
|
|
b994858907 | ||
|
|
74ad34a0c5 | ||
|
|
1b5b37c06b | ||
|
|
c8e1bd0e9a | ||
|
|
e9c8d3d740 | ||
|
|
f567b866a0 | ||
|
|
3471d3ee2d | ||
|
|
6e197f5751 | ||
|
|
b568c18346 | ||
|
|
1b29876ba8 | ||
|
|
4c6f3d2d69 | ||
|
|
8d3f7eded2 | ||
|
|
0222feeda1 | ||
|
|
f10cf1a9a0 | ||
|
|
85b2089fd3 | ||
|
|
885808c64c | ||
|
|
78069b42e7 | ||
|
|
3e0063e874 | ||
|
|
6ec1ab3d4f | ||
|
|
33b4540ad9 | ||
|
|
a434b51653 | ||
|
|
222d8d3575 | ||
|
|
8e2d006048 | ||
|
|
fd9f204b6d | ||
|
|
f0f358a138 | ||
|
|
cfffcd4513 | ||
|
|
e51587c66e | ||
|
|
f930953e6a | ||
|
|
ebdc10d1c5 | ||
|
|
d12370568f | ||
|
|
176125deca | ||
|
|
cb934ca39f | ||
|
|
4fd95fdcbe | ||
|
|
cb62349054 | ||
|
|
1b72119673 | ||
|
|
add474e825 | ||
|
|
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 |
@@ -0,0 +1,70 @@
|
||||
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-18.04
|
||||
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.5.2/libite-2.5.2.tar.gz
|
||||
tar xf libuev-2.3.2.tar.xz
|
||||
tar xf libite-2.5.2.tar.gz
|
||||
(cd libuev-2.3.2 && ./configure --prefix=/usr && make && sudo make install-strip)
|
||||
(cd libite-2.5.2 && ./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: |
|
||||
ver=$(/tmp/sbin/initctl -V | awk '/Finit.*/ {print $2;}')
|
||||
dir=finit-$ver/_build/sub
|
||||
make -j1 distcheck || (cat $dir/test/setup-root.log; cat $dir/test/test-suite.log; false)
|
||||
- name: Upload Test Results
|
||||
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/*
|
||||
@@ -45,3 +45,6 @@ GTAGS
|
||||
/.autoconf
|
||||
/.automake
|
||||
/.built
|
||||
|
||||
# VS Code user settings
|
||||
.vscode
|
||||
|
||||
-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= --disable-doc --disable-contrib --with-watchdog"
|
||||
build_command: "make"
|
||||
branch_pattern: dev
|
||||
|
||||
install:
|
||||
- wget https://github.com/troglobit/libuev/releases/download/v2.3.2/libuev-2.3.2.tar.xz
|
||||
- wget https://github.com/troglobit/libite/releases/download/v2.3.1/libite-2.3.1.tar.gz
|
||||
- tar xf libuev-2.3.2.tar.xz
|
||||
- tar xf libite-2.3.1.tar.gz
|
||||
- (cd libuev-2.3.2 && ./configure --prefix=/tmp && make && make install-strip)
|
||||
- (cd libite-2.3.1 && ./configure --prefix=/tmp && make && make install-strip)
|
||||
|
||||
# Custom build script for the time being, no "make test" yet
|
||||
script:
|
||||
- ./autogen.sh
|
||||
- ./configure --prefix= --enable-static
|
||||
- make clean
|
||||
- make V=1 -j5
|
||||
- ./configure --prefix= --enable-x11-common-plugin --with-watchdog --with-keventd
|
||||
- cat config.log
|
||||
- make clean
|
||||
- make V=1 -j5
|
||||
- make install-strip DESTDIR=/tmp/finit
|
||||
- tree /tmp/finit
|
||||
- ldd /tmp/finit/sbin/finit
|
||||
- size /tmp/finit/sbin/finit
|
||||
- size /tmp/finit/sbin/initctl
|
||||
- size /tmp/finit/sbin/reboot
|
||||
- LD_LIBRARY_PATH=/tmp/lib /tmp/finit/sbin/initctl -h
|
||||
- unshare -V
|
||||
- nsenter -V
|
||||
- chroot --version
|
||||
- 'LD_LIBRARY_PATH=/tmp/lib make distcheck || (cat finit-4.0-beta1/_build/sub/test/test-suite.log; exit 1)'
|
||||
+201
-11
@@ -4,8 +4,185 @@ Change Log
|
||||
All relevant changes are documented in this file.
|
||||
|
||||
|
||||
[4.1][UNRELEASED]
|
||||
-----------------
|
||||
[4.3][] - 2022-05-15
|
||||
--------------------
|
||||
|
||||
Critical bug fix release. If you run a 32-bit target with GLIBC 2.34
|
||||
you *need* to upgrade!
|
||||
|
||||
> **Note:** system verbosity on console at start and shutdown has been
|
||||
> increased. Now the output of all commands is logged to the
|
||||
> system logger, for early services `/dev/kmsg` is used.
|
||||
>
|
||||
> **Also:** please notice the updated support for enabling and disabling
|
||||
> kernel and Finit debug messages on the system console. Very
|
||||
> useful when debugging either of them, e.g., a kernel module.
|
||||
> For details, see [cmdline.md](doc/cmdline.md).
|
||||
|
||||
### Changes
|
||||
* Support for overriding default runlevel from kernel command line. Any
|
||||
runlevel `[1-9]` may be selected, except 6 (reboot). Issue #261
|
||||
* New command line option: `finit.fstab=/etc/fstab.custom`, with full
|
||||
support for mounting, mount helpers, fsck, and swapon/off, issue #224
|
||||
* Support for special device `/dev/root`, which may not exist in `/dev`.
|
||||
Finit now looks up the matching block device for `/` in `/sys/block/`
|
||||
* Loading `module`s no longer shows arguments in progress output
|
||||
* Warning messages in progress output now in yellow, not red, issue #214
|
||||
* `initctl`, new command line option `-V,--version` for ease of use
|
||||
* New condition `done` for run task, issue #207 by Ming Liu, Atlas Copco
|
||||
* Refactor parts of shutdown and reboot sequence for PREEMPT-RT kernels,
|
||||
by Robert Andersson, Mathias Thore, and Ming Liu, Atlas Copco
|
||||
* Conditions for run/task/sysv status, e.g. `run/foo/success` and
|
||||
`task/bar/failure`. Issue #232, by Ming Liu, Atlas Copco
|
||||
* Conditions for services, can be used to synchronize other stanzas:
|
||||
- `service/foo/running`
|
||||
- `service/foo/halted`
|
||||
- `service/foo/missing`
|
||||
- `service/foo/crashed`
|
||||
- `service/foo/stopped`
|
||||
- `service/foo/busy`
|
||||
- `service/foo/restart`
|
||||
* `initctl signal` support, by Jörgen Sigvardsson, issue #225
|
||||
* `initctl cond get` support to match `cond [set | clear]`, issue #255
|
||||
* `[WARN]` messages on console now printed in yellow, issue #214
|
||||
* Network services now also stopped when going to runlevel 6 (reboot),
|
||||
not just runlevel 0 (shutdown) or 1 (single-user)
|
||||
* When `ifup` is missing on the system, bring at least `lo` up at boot
|
||||
* Log output from `ifup -a` (and `ifdown -a`), to syslog
|
||||
* Avoid blocking PID 1 when starting SysV init scripts
|
||||
* Allow custom `pid:` for SysV init scripts
|
||||
* Document supported types of forking/non-forking services
|
||||
* Auto-detect running in some common forms of containers
|
||||
* Simplify shutdown/reboot when running in a container
|
||||
* Log to `stderr` when running in a container w/o syslog daemon
|
||||
* Add support for `type:forking` to services, already supported but
|
||||
with a very difficult `pid:` syntax, issue #223. Docs updated
|
||||
* Support for setting global environment variables in `finit.conf`,
|
||||
please note: this also affects Finit itself, be careful!
|
||||
* Extended environment variables for pre/post scripts, issue #189
|
||||
* Document secret service option `respawn`, which bypasses the crash
|
||||
semantics, allowing endless restarts
|
||||
* Document secret `HOOK_BANNER`, the first hook point before the banner
|
||||
* Document slightly confusing `initctl reload foo` command. It does
|
||||
*not* reload the service's `.conf` file! Issue #263
|
||||
* Log changes; all instances where previously the `basename cmd` of a
|
||||
service was used to identify the service, now the proper `name:id` is
|
||||
used instead. Meaning, a service without a custom `:ID` or `name:`
|
||||
will display the same as before, but with any of those customizations
|
||||
the name and name:id will now be shown. **Note:** this may affect any
|
||||
log scrapers out there!
|
||||
* New plugin: `hook-scripts`, allows [run-parts(8)][] style scripts to
|
||||
run on any hook point. Contributed by Tobias Waldekranz
|
||||
* `initctl` (`reboot`) falls back to `-f` when it detects it is in
|
||||
`sulogin` recovery mode, issue #247
|
||||
* The bundled `sulogin` is no longer enabled by default, in favor of
|
||||
distribution versions. Enable with `./configure --with-sulogin`
|
||||
* Support args to sysv-like scripts, e.g. `bridge-stp br0 start`
|
||||
* The `modules-load` plugin now skips all lines starting with `#` and
|
||||
`;`. Furthermore, files in `/etc/modules-load.d/*.conf` are now read
|
||||
in lexicographic order and UNIX backup files (`foo.conf~`) are skipped
|
||||
* The `name:id` tuple is now more consistently used in all log and debug
|
||||
messages instead of the basename of the command
|
||||
* Simplify error output of `initctl start/stop/restart/signal`, no more
|
||||
extra usage help, just a plain error message
|
||||
* Exit codes of `initctl` have changed to use LSB script standard and BSD
|
||||
sysexits.h exit codes. As before, a non-zero exit is error or missing
|
||||
* Add support for `initctl -q` to more commands: stop, start, restart,
|
||||
reload, signal, etc.
|
||||
|
||||
[run-parts(8)]: https://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
||||
|
||||
### Fixes
|
||||
* Fix nasty 32/64-bit alignment issue between finit and its plugins,
|
||||
applicable to 32-bit targets with GLIBC 2.34 and later. External
|
||||
plugins must make sure to use, at least: `-D_TIME_BITS=64`
|
||||
* Fix #215: disable cgroup support at runtime if kernel lacks support
|
||||
or does not have the required controllers (cpu)
|
||||
* Fix #217: iwatcher initialization issue, by Ming Liu, Atlas Copco
|
||||
* Fix #218: initctl matches too many services, by Ming Liu, Atlas Copco
|
||||
* Fix #219: not all filesystems unmounted at shutdown, by Ming Liu,
|
||||
Mathias Thore, and Robert Andersson, Atlas Copco
|
||||
* Fix #226: initctl shows wrong PID for crashing services
|
||||
* Fix #227: reboot stalls if process stopped with `[WARN]`
|
||||
* Fix #233: initctl shows wrong status for run/task, by Sergio Morlans
|
||||
and Ming Liu, Atlas Copco
|
||||
* Fix #248: source `env:file` also in `pre:` and `post` scripts
|
||||
* Fix #260: drop limit on device name in `Checking filesystem...` output
|
||||
* Fix start/stop and monitoring (restart) of SysV init scripts and
|
||||
forking services, see the updated documentation for details
|
||||
* Fix call to `swapoff` at shutdown, does not support `-e` flag
|
||||
* Fix suspend to RAM issue. Previously `reboot(RB_SW_SUSPEND)` was
|
||||
used, now the modern `/sys/power/state` API is used instead.
|
||||
* Fix nasty run/task/service matcher bug, triggered by stanzas using the
|
||||
same basename of a command but different `:ID`. Caused Finit to match
|
||||
with already registered but different run/task/service
|
||||
|
||||
|
||||
[4.2][] - 2022-01-16
|
||||
--------------------
|
||||
|
||||
### Changes
|
||||
* Support for non-root users to use `initctl`, e.g. group wheel
|
||||
* Support for new libite (-lite) header namespace
|
||||
* RTC plugin now reset an invalid RTC time to the kernel default
|
||||
time, 2000-01-01 00:00, prevents errors and is less crazy than
|
||||
some systems coming with with <= Jan 1, 1970
|
||||
* urandom plugin now use RNDADDENTROPY ioctl to seed kernel rng,
|
||||
incrementing entropy count. Also, 32 kiB instead of 512 bytes are
|
||||
now saved (and restored) on reboot. This should greatly improve
|
||||
reliability of systems with none or poor HWRNG
|
||||
* Kernel logging to console (loglevel >= 7, debug, when quiet mode is
|
||||
not used) is now honored by Finit, regardless of the finit.debug
|
||||
command line option
|
||||
* Reduced default log level from `LOG_NOTICE` to `LOG_INFO`
|
||||
* Wrapped all calls to mount(2) to add logging in case of failure
|
||||
* New configure options to control fastboot (no fsck) and fsck fix
|
||||
options, by Ming Liu, Atlas Copco
|
||||
* Support for overriding default `/etc/nologin` file with an external
|
||||
`#define`, by Ming Liu, Atlas Copco
|
||||
* Support for overriding default `/var/run/dbus/pid` file with an
|
||||
external `#define`, by Ming Liu, Atlas Copco
|
||||
* Support for more service options to control respawn behavior of
|
||||
crashing services, by Robert Andersson and Ming Liu, Atlas Copco
|
||||
* Support for `initctl ident [NAME]` which lists all instances of
|
||||
`NAME`, or all enabled system run/tasks and services
|
||||
* Show number of total restarts and current respawn count for a
|
||||
service in `initctl status foo`
|
||||
* Crashing services no longer have the crash/restart counter reset as
|
||||
soon as they have stabilized. Instead, a background timer will
|
||||
slowly (every 300 sec) age (decrement) the counter. This will still
|
||||
catch services that "rage quit", but also those that crash after a
|
||||
longer period of activity
|
||||
|
||||
### Fixes
|
||||
* Fix #180: user managed (`manual:yes`) services accidentally started
|
||||
by `initctl reload`, regression introduced in Finit v4.0
|
||||
* Fix #181: lots of typos all over the tree, by David Yang, Debian
|
||||
* Fix #187: fix typos, incl. small cleanup, in doc/bootstrap.md
|
||||
* Fix #188: support running on kernels that do not have cgroups v2.
|
||||
When this is detect, all functions related to cgroups support in
|
||||
Finit are disabled, *except* the .conf file parser. Hence, you
|
||||
may get parse error if you have invalid cgroup configuration in
|
||||
your Finit .conf files
|
||||
* Fix #197: `initctl status foo` now shows a focused overview of all
|
||||
matching instances; foo:1, foo:2 -- if only one instance matches the
|
||||
command line argument, or if onle one instance exists, the detailed
|
||||
view is shown, as before
|
||||
* Fix #198: a few typos found by Tim Gates
|
||||
* Fix #199: avoid using C++ reserved keywords
|
||||
* Fix #201: memory leak in usr condition plugin, by Ming Liu, Atlas Copco
|
||||
* Fix #203: ensure all filesystems listed in /proc/mounts are properly
|
||||
unumounted on shutdown/reboot, by Robert Andersson, Atlas Copco
|
||||
* Fix #210: resizing terminal (smaller) after boot causes empty lines
|
||||
to be inserted between boot progress
|
||||
* Fix #211: drop hard-coded 32 character limit in getty, now reads
|
||||
`_SC_LOGIN_NAME_MAX` from `sysconf(3)`
|
||||
* Fix #212: service PID file lost after inictl reload, visible from
|
||||
the output from `initctl status foo`
|
||||
|
||||
|
||||
[4.1][] - 2021-06-06
|
||||
--------------------
|
||||
|
||||
Bug fix release. Also disables handlers for `SIGINT` and `SIGPWR`, a
|
||||
new set of `sys` conditions are instead generated which can be used to
|
||||
@@ -36,6 +213,9 @@ trigger external programs.
|
||||
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
|
||||
@@ -45,6 +225,9 @@ trigger external programs.
|
||||
`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
|
||||
@@ -66,6 +249,11 @@ trigger external programs.
|
||||
* 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
|
||||
@@ -173,7 +361,7 @@ make sure to read the whole change log when upgrading.
|
||||
- As long as a stepped service changes state we queue another step all
|
||||
event, because services may depend on each other
|
||||
* Require new libuEv API: `uev_init1()` to reduce event cache so that
|
||||
the kernel can invalidate deleted events before enqueing to userspace
|
||||
the kernel can invalidate deleted events before enqueuing to userspace
|
||||
* Rename `hwclock.so` plugin to `rtc.so` since it now is stand-alone
|
||||
from the `hwclock` tool. Note: the kernel can also be set to load
|
||||
and store RTC to/from system clock at boot/halt as well, issue #110
|
||||
@@ -495,7 +683,7 @@ Bug fix release.
|
||||
|
||||
* Add support for status/show service by `name:id`
|
||||
* Enforce terse mode after boot, if verbose mode is disabled
|
||||
* Reenable verbose mode at reboot, if disabled at boot
|
||||
* Re-enable verbose mode at reboot, if disabled at boot
|
||||
* Update section mentioning BusyBox getty
|
||||
* Update debugging documentation
|
||||
* Allow debug to override terse mode
|
||||
@@ -550,7 +738,7 @@ handling and reconfiguration at runtime.
|
||||
* Clarify how to select different plugins with the configure script
|
||||
* Improve urandom plugin for embedded systems w/o random seed
|
||||
* Add `--debug` flag to `initctl`
|
||||
* The runlevels listed for services in `initctl show` now hightlight the
|
||||
* The runlevels listed for services in `initctl show` now highlight the
|
||||
active runlevel.
|
||||
* Clarify in the README and in `initctl help` that the GW event to
|
||||
listen for in service declarations is `GW:UP`
|
||||
@@ -582,7 +770,7 @@ handling and reconfiguration at runtime.
|
||||
* Do not use `-Os` use `-O2` as default optimization level. Many cross
|
||||
compiler toolchains are known to have problems with `-Os`
|
||||
* Do not allow build VERSION to be overloaded by an environment variable
|
||||
* Fix too small MAX arguments and too few argments in `svc_t` for
|
||||
* Fix too small MAX arguments and too few arguments in `svc_t` for
|
||||
reading currently running services with `initctl show`
|
||||
* Unblock blocked signals after forking off a child
|
||||
|
||||
@@ -682,7 +870,7 @@ The inetd release.
|
||||
### Changes
|
||||
* Add support for built-in inetd super server -- launch services on
|
||||
demand. Supports filtering per interface and custom Inet ports.
|
||||
* Upgrade to [libuEv] v1.1.0 to better handle error conditions.
|
||||
* Upgrade to [libuEv][] v1.1.0 to better handle error conditions.
|
||||
* Allow mixed case config directives in `finit.conf`
|
||||
* Add support for RFC 868 (rdate) time plugin, start as inetd service.
|
||||
* Load plugins before parsing `finit.conf`, this makes it possible to
|
||||
@@ -700,7 +888,7 @@ The inetd release.
|
||||
turned out to not work so well after all. For instance, launching
|
||||
TTYs in a background process completely blocked inetd services from
|
||||
even starting up listening sockets ... proper fork seems to work fine
|
||||
though. This is the casue for *yanking* the [1.11] release, below.
|
||||
though. This is the cause for *yanking* the [1.11] release, below.
|
||||
* Trap segfaults caused by external plugins/callbacks in a sub-process.
|
||||
This prevents a single programming mistake in by a 3rd party developer
|
||||
from taking down the entire system.
|
||||
@@ -713,7 +901,7 @@ The inetd release.
|
||||
[1.11][] - 2015-01-24 [YANKED]
|
||||
------------------------------
|
||||
|
||||
The [libuEv] release.
|
||||
The [libuEv][] release.
|
||||
|
||||
**Note:** This release has been *yanked* from distribution due to a
|
||||
regression in launching background processes and TTY's. Fixed in
|
||||
@@ -796,7 +984,7 @@ Major bug fix release.
|
||||
|
||||
### Changes
|
||||
* Show `__FILE__` in `_d()` debug messages, useful for plugins with
|
||||
similarily named callbacks. Also, only in debug mode anyway
|
||||
similarly named callbacks. Also, only in debug mode anyway
|
||||
* Make sure to cleanup recorded PID when a service is lost. Required by
|
||||
service plugins for their callbacks to work.
|
||||
* Only clear screen when in verbose mode. Maybe this should be removed
|
||||
@@ -964,7 +1152,9 @@ Major bug fix release.
|
||||
|
||||
* Initial release
|
||||
|
||||
[UNRELEASED]: https://github.com/troglobit/finit/compare/4.0...HEAD
|
||||
[UNRELEASED]: https://github.com/troglobit/finit/compare/4.2...HEAD
|
||||
[4.3]: https://github.com/troglobit/finit/compare/4.2...4.3
|
||||
[4.2]: https://github.com/troglobit/finit/compare/4.1...4.2
|
||||
[4.1]: https://github.com/troglobit/finit/compare/4.0...4.1
|
||||
[4.0]: https://github.com/troglobit/finit/compare/3.1...4.0
|
||||
[3.1]: https://github.com/troglobit/finit/compare/3.0...3.1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
Copyright (c) 2008-2022 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
|
||||
|
||||
+3
-1
@@ -1,5 +1,5 @@
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
SUBDIRS = plugins src test
|
||||
SUBDIRS = man plugins src test
|
||||
doc_DATA = README.md LICENSE contrib/finit.conf
|
||||
EXTRA_DIST = README.md LICENSE ChangeLog.md contrib/finit.conf
|
||||
|
||||
@@ -29,3 +29,5 @@ release: distcheck
|
||||
printf "$$file.md5\t"; cat ../$$file.md5 | cut -f1 -d' '; \
|
||||
printf "$$file.sha256\t"; cat ../$$file.sha256 | cut -f1 -d' '; \
|
||||
done
|
||||
|
||||
DISTCHECK_CONFIGURE_FLAGS = --with-fstab=/etc/fstab
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[![License Badge][]][License] [![Travis Status]][Travis] [![Coverity Status]][Coverity Scan]
|
||||
[![License Badge][]][License] [![GitHub Status][]][GitHub] [![Coverity Status][]][Coverity Scan]
|
||||
<img align="right" src="img/finit3.png" alt="Finit: Fast Init">
|
||||
|
||||
* [Introduction](#introduction)
|
||||
@@ -22,19 +22,19 @@
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Finit is a simple alternative to [SysV init][4] and [systemd][6]. It
|
||||
was reverse engineered from the [EeePC fastinit][] over ten years ago
|
||||
by [Claudio Matsuoka][] — "gaps filled with frog DNA …"
|
||||
Fast init for Linux systems. Reverse engineered from the [EeePC
|
||||
fastinit][] over ten years ago by [Claudio Matsuoka][] — "gaps filled
|
||||
with frog DNA …"
|
||||
|
||||

|
||||
*Figure 1: Screenshot showing Finit booting [Alpine Linux](https://www.alpinelinux.org/).*
|
||||
|
||||
Features include:
|
||||
|
||||
* Runlevels
|
||||
* One-shot tasks, daemons, or SysV init scripts
|
||||
* Runparts and rc.local
|
||||
* Process supervision
|
||||
* 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
|
||||
@@ -45,6 +45,10 @@ Features include:
|
||||
* Cgroups v2, both configuration and monitoring in `initctl top`
|
||||
* Plugin support for customization
|
||||
* Proper rescue mode with bundled `sulogin` for protected maintenance shell
|
||||
* Integration with [watchdogd][] for full system supervision
|
||||
* Logging to kernel ring buffer before `syslogd` has started, see the
|
||||
recommended [sysklogd][] project for complete logging integration
|
||||
and how to log to the kernel ring buffer from scripts using `logger`
|
||||
|
||||
Focus is on small and embedded systems, although Finit is fully usable
|
||||
on server and desktop systems as well. For working examples, see the
|
||||
@@ -52,7 +56,12 @@ on server and desktop systems as well. For working examples, see the
|
||||
|
||||
* [Void Linux](contrib/void/),
|
||||
* [Alpine Linux](contrib/alpine/), and
|
||||
* [Debian GNU/Linux](contrib/debian/)
|
||||
* [Debian GNU/Linux](contrib/debian/), also works on Ubuntu/Linux Mint
|
||||
|
||||
> **Note:** support for various Linux distributions does not mean Finit
|
||||
> installs easily on all architectures. The bundled install scripts are
|
||||
> examples for standard installations, tested on amd64 (x86_64) systems.
|
||||
> Custom setups, for embedded systems, can be found in [myLinux][].
|
||||
|
||||
|
||||
Example
|
||||
@@ -68,7 +77,11 @@ the [initctl](#commands--status) tool.
|
||||
host default
|
||||
|
||||
# Runlevel to start after bootstrap, 'S', default: 2
|
||||
runlevel 2
|
||||
#runlevel 2
|
||||
|
||||
# Support for setting global environment variables, using foo=bar syntax
|
||||
# be careful though with variables like PATH, SHELL, LOGNAME, etc.
|
||||
#PATH=/usr/bin:/bin:/usr/sbin:/sbin
|
||||
|
||||
# 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
|
||||
@@ -97,6 +110,11 @@ service :8080 [2345] merecat -n -p 8080 /var/www -- Old web server
|
||||
#sysv [S] /etc/init.d/acpid -- Starting ACPI Daemon
|
||||
#task [S] /etc/init.d/kbd -- Preparing console
|
||||
|
||||
# Hidden from boot progress, using empty `--` description
|
||||
#sysv [S] /etc/init.d/keyboard-setup --
|
||||
#sysv [S] /etc/init.d/acpid --
|
||||
#task [S] /etc/init.d/kbd --
|
||||
|
||||
# Run start scripts from this directory
|
||||
# runparts /etc/start.d
|
||||
|
||||
@@ -119,10 +137,10 @@ some of the most common components needed to start a UNIX daemon:
|
||||
|
||||
```
|
||||
service [LVLS] <COND> log env:[-]/etc/default/daemon daemon ARGS -- Daemon daemon
|
||||
^ ^ ^ ^ ^ ^ ^ ^
|
||||
| | | | | | | `-- Optional description
|
||||
| | | | | | `----------- Daemon arguments
|
||||
| | | | | `-------------------------- Path to daemon
|
||||
^ ^ ^ ^ ^ ^ ^ ^
|
||||
| | | | | | | `---------- Optional description
|
||||
| | | | | | `------------------ Daemon arguments
|
||||
| | | | | `------------------------- Path to daemon
|
||||
| | | | `---------------------------------------------------- Optional env. file
|
||||
| | | `-------------------------------------------------------- Redirect output to log
|
||||
| | `--------------------------------------------------------------- Optional conditions
|
||||
@@ -140,7 +158,7 @@ Dependencies are handled using [conditions](doc/conditions.md). One of
|
||||
the most common conditions is to wait for basic networking to become
|
||||
available:
|
||||
|
||||
service <net/route/default> nginx -- High performace HTTP server
|
||||
service <net/route/default> nginx -- High performance HTTP server
|
||||
|
||||
Here is another example where we instruct Finit to not start BusyBox
|
||||
`ntpd` until `syslogd` has started properly. Finit waits for `syslogd`
|
||||
@@ -263,8 +281,8 @@ unnecessary overhead, which can be removed at build-time using:
|
||||
|
||||
**Cgroups**
|
||||
|
||||
Finit supports cgroups v2 and comes with the following default groups
|
||||
in which services and user sessions are placed in:
|
||||
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
|
||||
@@ -300,6 +318,10 @@ The `initctl` tool has three commands to help debug and optimize the
|
||||
setup and monitoring of cgroups. See the `ps`, `top`, and `cgroup`
|
||||
commands for details.
|
||||
|
||||
> **Note:** systems that do not support cgroups, specifically version 2,
|
||||
> are automatically detected. On such systems the above functionality
|
||||
> is disabled early at boot.
|
||||
|
||||
|
||||
Runparts & /etc/rc.local
|
||||
------------------------
|
||||
@@ -409,24 +431,24 @@ services, called `initctl`. Unlike `telinit` the `initctl` tool does
|
||||
not return until the given command has fully completed.
|
||||
|
||||
```
|
||||
alpine:~# initctl help
|
||||
Usage: initctl [OPTIONS] [COMMAND]
|
||||
|
||||
Options:
|
||||
-b, --batch Batch mode, no screen size probing
|
||||
-c, --create Create missing paths (and files) as needed
|
||||
-f, --force Ignore missing files and arguments, never prompt
|
||||
-h, --help This help text
|
||||
-1, --once Only one lap in commands like 'top'
|
||||
-p, --plain Use plain table headings, no ctrl chars
|
||||
-q, --quiet Silent, only return status of command
|
||||
-t, --no-heading Skip table headings
|
||||
-v, --verbose Verbose output
|
||||
-h, --help This help text
|
||||
-V, --version Show program version
|
||||
|
||||
Commands:
|
||||
debug Toggle Finit (daemon) debug
|
||||
help This help text
|
||||
version Show Finit version
|
||||
version Show program version
|
||||
|
||||
ls | list List all .conf in /etc/finit.d
|
||||
create <CONF> Create .conf in /etc/finit.d/available
|
||||
@@ -439,6 +461,7 @@ Commands:
|
||||
reload Reload *.conf in /etc/finit.d (activate changes)
|
||||
|
||||
cond set <COND> Set (assert) user-defined condition +usr/COND
|
||||
cond get <COND> Get status of user-defined condition, see $? and -v
|
||||
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
|
||||
@@ -446,8 +469,12 @@ Commands:
|
||||
log [NAME] Show ten last Finit, or NAME, messages from syslog
|
||||
start <NAME>[:ID] Start service by name, with optional ID
|
||||
stop <NAME>[:ID] Stop/Pause a running service by name
|
||||
reload <NAME>[:ID] Reload service by name (SIGHUP or restart)
|
||||
reload <NAME>[:ID] Reload service as if .conf changed (SIGHUP or restart)
|
||||
This allows restart of run/tasks that have already run
|
||||
Note: Finit .conf file(s) are *not* reloaded!
|
||||
restart <NAME>[:ID] Restart (stop/start) service by name
|
||||
signal <NAME>[:ID] <S> Send signal S to service by name, with optional ID
|
||||
ident [NAME] Show matching identities for NAME, or all
|
||||
status <NAME>[:ID] Show service status, by name
|
||||
status Show status of services, default command
|
||||
|
||||
@@ -460,6 +487,8 @@ Commands:
|
||||
halt Halt system
|
||||
poweroff Halt and power off system
|
||||
suspend Suspend system
|
||||
|
||||
utmp show Raw dump of UTMP/WTMP db
|
||||
```
|
||||
|
||||
For services *not* supporting `SIGHUP` the `<!>` notation in the .conf
|
||||
@@ -571,36 +600,37 @@ This project is based on the [original finit][] by [Claudio Matsuoka][]
|
||||
which was reverse engineered from syscalls of the [EeePC fastinit][] —
|
||||
"gaps filled with frog DNA …"
|
||||
|
||||
Finit is developed and maintained by [Joachim Wiberg][] at [GitHub][].
|
||||
Finit is developed and maintained by [Joachim Wiberg][] at [GitHub][6].
|
||||
Please file bug reports, clone it, or send pull requests for bug fixes
|
||||
and proposed extensions.
|
||||
|
||||
|
||||
[1]: https://en.wikipedia.org/wiki/Process_supervision
|
||||
[2]: http://cr.yp.to/daemontools.html
|
||||
[3]: http://smarden.org/runit/
|
||||
[4]: http://en.wikipedia.org/wiki/Init
|
||||
[5]: http://en.wikipedia.org/wiki/Runlevel
|
||||
[6]: https://www.freedesktop.org/wiki/Software/systemd/
|
||||
[9]: https://github.com/troglobit/troglos
|
||||
[1]: https://en.wikipedia.org/wiki/Process_supervision
|
||||
[2]: https://cr.yp.to/daemontools.html
|
||||
[3]: https://smarden.org/runit/
|
||||
[4]: https://en.wikipedia.org/wiki/Init
|
||||
[5]: https://en.wikipedia.org/wiki/Runlevel
|
||||
[6]: https://github.com/troglobit/finit
|
||||
[RFC862]: https://tools.ietf.org/html/rfc862
|
||||
[RFC863]: https://tools.ietf.org/html/rfc863
|
||||
[RFC864]: https://tools.ietf.org/html/rfc864
|
||||
[RFC867]: https://tools.ietf.org/html/rfc867
|
||||
[RFC868]: https://tools.ietf.org/html/rfc868
|
||||
[init]: http://en.wikipedia.org/wiki/Init
|
||||
[upstart]: http://upstart.ubuntu.com/
|
||||
[systemd]: http://www.freedesktop.org/wiki/Software/systemd/
|
||||
[openrc]: http://www.gentoo.org/proj/en/base/openrc/
|
||||
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
||||
[init]: https://en.wikipedia.org/wiki/Init
|
||||
[upstart]: https://upstart.ubuntu.com/
|
||||
[systemd]: https://www.freedesktop.org/wiki/Software/systemd/
|
||||
[openrc]: https://www.gentoo.org/proj/en/base/openrc/
|
||||
[run-parts(8)]: https://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
||||
[original finit]: http://helllabs.org/finit/
|
||||
[EeePC fastinit]: https://web.archive.org/web/20071208212450/http://wiki.eeeuser.com/boot_process:the_boot_process
|
||||
[Claudio Matsuoka]: https://github.com/cmatsuoka
|
||||
[Joachim Wiberg]: http://troglobit.com
|
||||
[GitHub]: https://github.com/troglobit/finit
|
||||
[Joachim Wiberg]: https://troglobit.com
|
||||
[License]: https://en.wikipedia.org/wiki/MIT_License
|
||||
[License Badge]: https://img.shields.io/badge/License-MIT-teal.svg
|
||||
[Travis]: https://travis-ci.org/troglobit/finit
|
||||
[Travis Status]: https://travis-ci.org/troglobit/finit.svg?branch=master
|
||||
[myLinux]: https://github.com/troglobit/myLinux/
|
||||
[watchdogd]: https://github.com/troglobit/watchdogd/
|
||||
[sysklogd]: https://github.com/troglobit/sysklogd/
|
||||
[GitHub]: https://github.com/troglobit/finit/actions/workflows/build.yml/
|
||||
[GitHub Status]: https://github.com/troglobit/finit/actions/workflows/build.yml/badge.svg
|
||||
[Coverity Scan]: https://scan.coverity.com/projects/3545
|
||||
[Coverity Status]: https://scan.coverity.com/projects/3545/badge.svg
|
||||
|
||||
+70
-10
@@ -1,4 +1,4 @@
|
||||
AC_INIT(Finit, 4.1-rc2, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/finit.html)
|
||||
AC_INIT(Finit, 4.3, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/projects/finit/)
|
||||
AC_CONFIG_AUX_DIR(aux)
|
||||
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
|
||||
AM_SILENT_RULES([yes])
|
||||
@@ -11,10 +11,11 @@ AC_CONFIG_FILES([Makefile
|
||||
contrib/debian/Makefile contrib/debian/finit.d/Makefile contrib/debian/finit.d/available/Makefile
|
||||
contrib/void/Makefile contrib/void/finit.d/Makefile contrib/void/finit.d/available/Makefile
|
||||
doc/Makefile
|
||||
man/Makefile
|
||||
plugins/Makefile
|
||||
src/Makefile
|
||||
test/test.env
|
||||
test/Makefile])
|
||||
test/test.env test/Makefile
|
||||
test/tenv/Makefile test/common/Makefile])
|
||||
|
||||
# Older versions of autoconf (<2.58) do not have AC_CONFIG_MACRO_DIR()
|
||||
#m4_include([m4/plugin.m4])
|
||||
@@ -32,8 +33,8 @@ AC_PROG_MKDIR_P
|
||||
|
||||
# Configuration.
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS([fstaby.h termios.h sys/ioctl.h])
|
||||
AC_CHECK_FUNCS([strstr getopt getfsenty])
|
||||
AC_CHECK_HEADERS([termios.h sys/ioctl.h mntent.h sys/sysmacros.h])
|
||||
AC_CHECK_FUNCS([strstr getopt getmntent getmntent_r])
|
||||
|
||||
# Check for uint[8,16,32]_t
|
||||
AC_TYPE_UINT8_T
|
||||
@@ -56,6 +57,14 @@ AC_ARG_ENABLE(kernel_cmdline,
|
||||
AS_HELP_STRING([--enable-kernel-cmdline], [Parse init args from /proc/cmdline (don't use!)]),,[
|
||||
enable_kernel_cmdline=no])
|
||||
|
||||
AC_ARG_ENABLE(fastboot,
|
||||
AS_HELP_STRING([--enable-fastboot], [Skip fsck check on filesystems listed in /etc/fstab]),,[
|
||||
enable_fastboot=no])
|
||||
|
||||
AC_ARG_ENABLE(fsckfix,
|
||||
AS_HELP_STRING([--enable-fsckfix], [Run fsck fix mode (options: -yf) on filesystems listed in /etc/fstab]),,[
|
||||
enable_fsckfix=no])
|
||||
|
||||
AC_ARG_ENABLE(redirect,
|
||||
AS_HELP_STRING([--disable-redirect], [Disable redirection of service output to /dev/null]),,[
|
||||
enable_redirect=yes])
|
||||
@@ -77,16 +86,23 @@ enable_all_plugins=auto
|
||||
AC_PLUGIN([alsa-utils], [no], [Save and restore ALSA sound settings using alsactl])
|
||||
AC_PLUGIN([dbus], [no], [Setup and start system message bus, D-Bus])
|
||||
AC_PLUGIN([modules-load], [no], [Scans /etc/modules-load.d for modules to load])
|
||||
AC_PLUGIN([modprobe], [yes], [Coldplug modules using modalias magic])
|
||||
AC_PLUGIN([resolvconf], [no], [Setup necessary files for resolvconf])
|
||||
AC_PLUGIN([x11-common], [no], [Console setup (for X)])
|
||||
AC_PLUGIN([netlink], [yes], [Basic netlink plugin for IFUP/IFDN and GW events. Can be replaced with externally built plugin that links with libnl or similar.])
|
||||
AC_PLUGIN([hook-scripts], [no], [Trigger script execution from hook points])
|
||||
AC_PLUGIN([hotplug], [yes], [Setup and start udev or mdev hotplug daemon])
|
||||
AC_PLUGIN([rtc], [yes], [Save and restore RTC using hwclock])
|
||||
AC_PLUGIN([tty], [yes], [Automatically activate new TTYs, e.g. USB-to-serial])
|
||||
AC_PLUGIN([urandom], [yes], [Setup and save random seed at boot/shutdown])
|
||||
|
||||
# Check for extra arguments or packages
|
||||
AC_ARG_WITH(fstab,
|
||||
AS_HELP_STRING([--with-fstab=FILE], [System default fstab, default $sysconfdir/fstab]),
|
||||
[fstab=$withval], [fstab=yes])
|
||||
|
||||
AC_ARG_WITH(heading,
|
||||
AS_HELP_STRING([--with-heading=GREET], [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])
|
||||
|
||||
AC_ARG_WITH(config,
|
||||
@@ -105,12 +121,16 @@ AC_ARG_WITH(sysconfig,
|
||||
AS_HELP_STRING([--with-sysconfig=DIR], [System environment directory, sourced by .conf files, default /etc/default & /etc/conf.d]),
|
||||
[sysconfig=$withval], [sysconfig=default])
|
||||
|
||||
AC_ARG_WITH(group,
|
||||
AS_HELP_STRING([--with-group=NAME], [Group for /run/finit/socket (initctl), default: root]),
|
||||
[group=$withval], [group=root])
|
||||
|
||||
AC_ARG_WITH(hostname,
|
||||
AS_HELP_STRING([--with-hostname=NAME], [If /etc/hostname is missing, default: noname]),
|
||||
[hostname=$withval], [hostname=yes])
|
||||
|
||||
AC_ARG_WITH(runlevel,
|
||||
AS_HELP_STRING([--with-runlevel=N], [Runlevel to switch to after bootstrap, default: 2]),
|
||||
AS_HELP_STRING([--with-runlevel=N], [Runlevel to switch to after bootstrap [1-9], default: 2]),
|
||||
[runlevel=$withval], [runlevel=yes])
|
||||
|
||||
AC_ARG_WITH(random-seed,
|
||||
@@ -120,10 +140,18 @@ AC_ARG_WITH(random-seed,
|
||||
AC_ARG_WITH(keventd,
|
||||
AS_HELP_STRING([--with-keventd], [Enable built-in keventd, default: no]),, [with_keventd=no])
|
||||
|
||||
AC_ARG_WITH(sulogin,
|
||||
AS_HELP_STRING([--with-sulogin], [Enable built-in sulogin, default: no.]),, [with_sulogin=no])
|
||||
|
||||
AC_ARG_WITH(watchdog,
|
||||
AS_HELP_STRING([--with-watchdog=[DEV]], [Enable built-in watchdog, default: /dev/watchdog]),
|
||||
[watchdog=$withval], [with_watchdog=no watchdog=])
|
||||
|
||||
AC_ARG_WITH(hook-scripts-path,
|
||||
AS_HELP_STRING([--with-hook-scripts-path=DIR], [Base directory for hook scripts, default $libexecdir/finit/hook]),
|
||||
[hook_scripts_path=$withval], [hook_scripts_path=yes])
|
||||
|
||||
|
||||
### Enable features ###########################################################################
|
||||
|
||||
# Create config.h from selected features and fallback defaults
|
||||
@@ -133,6 +161,12 @@ AS_IF([test "x$enable_auto_reload" = "xyes"], [
|
||||
AS_IF([test "x$enable_kernel_cmdline" = "xyes"], [
|
||||
AC_DEFINE(KERNEL_CMDLINE, 1, [Dumpster diving after init args from /proc/cmdline])])
|
||||
|
||||
AS_IF([test "x$enable_fastboot" = "xyes"], [
|
||||
AC_DEFINE(FAST_BOOT, 1, [Skip fsck check on filesystems listed in /etc/fstab])])
|
||||
|
||||
AS_IF([test "x$enable_fsckfix" = "xyes"], [
|
||||
AC_DEFINE(FSCK_FIX, 1, [Run fsck fix mode (options: -yf) on filesystems listed in /etc/fstab])])
|
||||
|
||||
AS_IF([test "x$enable_redirect" = "xyes"], [
|
||||
AC_DEFINE(REDIRECT_OUTPUT, 1, [Enable redirection of service output to /dev/null])])
|
||||
|
||||
@@ -143,6 +177,12 @@ AS_IF([test "x$enable_logrotate" != "xno"], [
|
||||
AM_CONDITIONAL(LOGROTATE, [test "x$enable_logrotate" = "xyes"])
|
||||
|
||||
### With features ##############################################################################
|
||||
AS_IF([test "x$with_fstab" != "xno"], [
|
||||
AS_IF([test "x$fstab" = "xyes"], [fstab=$sysconfdir/fstab])
|
||||
AC_EXPAND_DIR(fstab_path, "$fstab")
|
||||
AC_DEFINE_UNQUOTED(FINIT_FSTAB, "$fstab_path", [Built-in default: /etc/fstab])],[
|
||||
AC_DEFINE_UNQUOTED(FINIT_FSTAB, NULL, [No built-in default fstab])])
|
||||
|
||||
AS_IF([test "x$with_config" != "xno"], [
|
||||
AS_IF([test "x$conf" = "xyes"], [
|
||||
conf=$sysconfdir/finit.conf])])
|
||||
@@ -170,9 +210,13 @@ AS_IF([test "x$with_sysconfig" != "xno"], [
|
||||
[System environment, default /etc/default & /etc/conf.d])])])
|
||||
|
||||
AS_IF([test "x$with_heading" != "xno"], [
|
||||
AS_IF([test "x$heading" = "xyes"], [
|
||||
heading="$PACKAGE_NAME v$PACKAGE_VERSION"])])
|
||||
AC_DEFINE_UNQUOTED(INIT_HEADING, "$heading", [Displayed by Finit at boot])
|
||||
AS_IF([test "x$heading" = "xyes"], [heading=""])
|
||||
AC_DEFINE_UNQUOTED(INIT_OSHEADING, "$heading", [Displayed by Finit at boot, defaults to /etc/os-release PRETTY_NAME])])
|
||||
|
||||
AS_IF([test "x$with_group" != "xno"], [
|
||||
AS_IF([test "x$group" = "xyes"], [
|
||||
group=root])])
|
||||
AC_DEFINE_UNQUOTED(DEFGROUP, "$group", [For /run/finit/socket])
|
||||
|
||||
AS_IF([test "x$with_hostname" != "xno"], [
|
||||
AS_IF([test "x$hostname" = "xyes"], [
|
||||
@@ -193,6 +237,8 @@ AS_IF([test "x$with_random_seed" != "xno"], [
|
||||
|
||||
AS_IF([test "x$with_keventd" != "xno"], [with_keventd=yes])
|
||||
|
||||
AS_IF([test "x$with_sulogin" != "xno"], [with_sulogin=yes])
|
||||
|
||||
AS_IF([test "x$with_watchdog" != "xno"], [
|
||||
AS_IF([test "x$watchdog" = "xyes"], [
|
||||
watchdog=/dev/watchdog])
|
||||
@@ -200,9 +246,15 @@ AS_IF([test "x$with_watchdog" != "xno"], [
|
||||
AC_DEFINE_UNQUOTED(WDT_DEVNODE, "$watchdog", [Built-in watchdog device node])], [
|
||||
watchdog=])
|
||||
|
||||
AS_IF([test "x$enable_hook_scripts_plugin" = "xyes" -a "x$with_hook_scripts_path" != "xno"], [
|
||||
AS_IF([test "x$hook_scripts_path" = "xyes"], [hook_scripts_path=$libexecdir/finit/hook])
|
||||
AC_EXPAND_DIR(hook_scripts_path, "$hook_scripts_path")
|
||||
AC_DEFINE_UNQUOTED(PLUGIN_HOOK_SCRIPTS_PATH, "$hook_scripts_path", [Built-in default: $libexecdir/finit])])
|
||||
|
||||
# Control build with automake flags
|
||||
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
||||
AM_CONDITIONAL(KEVENTD, [test "x$with_keventd" != "xno"])
|
||||
AM_CONDITIONAL(SULOGIN, [test "x$with_sulogin" != "xno"])
|
||||
AM_CONDITIONAL(WATCHDOGD, [test "x$with_watchdog" != "xno"])
|
||||
AM_CONDITIONAL(DOC, [test "x$enable_doc" = "xyes"])
|
||||
AM_CONDITIONAL(CONTRIB, [test "x$enable_contrib" = "xyes"])
|
||||
@@ -222,6 +274,9 @@ AC_DEFINE_UNQUOTED(RESCUE_CONF, "$rescue_conf", [Finit rescue mode .conf])
|
||||
AC_EXPAND_DIR(sample_conf, "$libdir/finit/sample.conf")
|
||||
AC_DEFINE_UNQUOTED(SAMPLE_CONF, "$sample_conf", [Finit sameple.conf for initctl create])
|
||||
|
||||
AS_IF([test "$heading" = ""], [heading="<DEFAULT>"])
|
||||
AS_IF([test "$heading" = "no"], [heading="<NONE>"])
|
||||
|
||||
# Generate all files
|
||||
AC_OUTPUT
|
||||
|
||||
@@ -233,6 +288,7 @@ cat <<EOF
|
||||
Exec prefix...........: $eprefix
|
||||
Sysconfdir............: `eval echo $sysconfdir`
|
||||
Localstatedir.........: `eval echo $localstatedir`
|
||||
Default fstab.........: `eval echo $fstab`
|
||||
Finit config file.....: $conf_path
|
||||
Finit config.d path...: $rcsd_path
|
||||
Finit plugin path.....: $plugin_path
|
||||
@@ -250,10 +306,14 @@ Optional features:
|
||||
Install doc/..........: $enable_doc
|
||||
Install contrib/......: $enable_contrib
|
||||
Built-in keventd......: $with_keventd
|
||||
Built-in sulogin......: $with_sulogin
|
||||
Built-in watchdogd....: $with_watchdog $watchdog
|
||||
Built-in logrotate....: $enable_logrotate
|
||||
Skip fsck check.......: $enable_fastboot
|
||||
Run fsck fix mode.....: $enable_fsckfix
|
||||
Redirect output.......: $enable_redirect
|
||||
Default hostname......: $hostname
|
||||
Default group.........: $group
|
||||
Default runlevel......: $runlevel
|
||||
|
||||
------------- Compiler version --------------
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
SUBDIRS = finit.d
|
||||
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)
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
3.6.2
|
||||
@@ -18,7 +18,7 @@ PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig ./configure \
|
||||
--sysconfdir=/etc --localstatedir=/var \
|
||||
--enable-dbus-plugin --enable-x11-common-plugin \
|
||||
--enable-alsa-utils-plugin --with-watchdog \
|
||||
--with-heading="Alpine Linux" --with-keventd
|
||||
--with-keventd
|
||||
|
||||
echo
|
||||
echo "*** Building ..."
|
||||
|
||||
@@ -8,7 +8,8 @@ if [ "x`id -u`" != "x0" ]; then
|
||||
fi
|
||||
|
||||
# Adjust base directory
|
||||
if [ -e alpine-release ]; then
|
||||
grep -q alpine Makefile 2>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
cd ../..
|
||||
elif [ ! -e configure.ac ]; then
|
||||
echo "*** Please run this script from the Finit base directory."
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
#
|
||||
# Each line is run in sequence.
|
||||
#
|
||||
# NOTE: Remeber to set the executable bit!
|
||||
# NOTE: Remember to set the executable bit!
|
||||
#
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
SUBDIRS = finit.d
|
||||
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)
|
||||
|
||||
@@ -47,12 +47,13 @@ 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
|
||||
and initialization like keyboard language etc.
|
||||
|
||||
If you want to use the X Window system, `sudo apt install elogind`
|
||||
(Bullseye and later). Followed by `initctl reload` (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.
|
||||
> **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!
|
||||
|
||||
@@ -26,8 +26,7 @@ echo
|
||||
--sysconfdir=/etc --localstatedir=/var \
|
||||
--enable-dbus-plugin --enable-x11-common-plugin \
|
||||
--enable-alsa-utils-plugin --with-keventd \
|
||||
--with-random-seed=/var/lib/urandom/random-seed \
|
||||
--with-heading="Debian GNU/Linux"
|
||||
--with-random-seed=/var/lib/urandom/random-seed
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
SUBDIRS = available
|
||||
docsdir := @docdir@/contrib/debian/finit.d
|
||||
d_LINKS = acpid.conf apparmor.conf avahi-demon.conf \
|
||||
d_LINKS = acpid.conf apparmor.conf avahi-daemon.conf \
|
||||
bluetooth.conf console-setup.conf elogind.conf \
|
||||
getty.conf keyboard-setup.conf modules.conf \
|
||||
rsyslogd.conf sshd.conf
|
||||
plymouth-quit.conf rsyslogd.conf sshd.conf
|
||||
|
||||
install-exec-hook:
|
||||
@$(MKDIR_P) $(DESTDIR)$(docsdir)/available
|
||||
|
||||
@@ -2,6 +2,7 @@ docsdir := @docdir@/contrib/debian/finit.d/available
|
||||
docs_DATA = acpid.conf apparmor.conf avahi-daemon.conf bluetooth.conf \
|
||||
console-setup.conf elogind.conf getty.conf \
|
||||
keyboard-setup.conf lightdm.conf modules.conf sntpd.conf \
|
||||
rsyslogd.conf sshd.conf syslogd.conf xdm.conf
|
||||
plymouth-quit.conf rsyslogd.conf sshd.conf syslogd.conf \
|
||||
xdm.conf
|
||||
EXTRA_DIST = $(docs_DATA)
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -8,7 +8,7 @@ if [ "x`id -u`" != "x0" ]; then
|
||||
fi
|
||||
|
||||
# Adjust base directory
|
||||
grep -q Debian os-release 2>/dev/null
|
||||
grep -q debian Makefile 2>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
cd ../..
|
||||
elif [ ! -e configure.ac ]; then
|
||||
|
||||
@@ -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/"
|
||||
@@ -0,0 +1,75 @@
|
||||
In Finit issue #196 we were reminded [1] of a missing inotify flag in
|
||||
Linux older kernels, IN_MASK_CREATE. Finit makes use of this internally
|
||||
for monitoring PID conditions, and more. This is a central mechanism to
|
||||
synchronize services at boot and reload at runtime.
|
||||
|
||||
The following patch for Linux 4.9.0, was provided by Andy Savage for
|
||||
other people that may want to run Finit on slightly older kernels.
|
||||
|
||||
[1]: https://github.com/troglobit/finit/issues/196
|
||||
|
||||
Index: fs/notify/inotify/inotify_user.c
|
||||
===================================================================
|
||||
--- fs.orig/notify/inotify/inotify_user.c
|
||||
+++ fs/notify/inotify/inotify_user.c
|
||||
@@ -522,6 +522,7 @@ static int inotify_update_existing_watch
|
||||
__u32 old_mask, new_mask;
|
||||
__u32 mask;
|
||||
int add = (arg & IN_MASK_ADD);
|
||||
+ int create = (arg & IN_MASK_CREATE);
|
||||
int ret;
|
||||
|
||||
mask = inotify_arg_to_mask(arg);
|
||||
@@ -529,6 +530,8 @@ static int inotify_update_existing_watch
|
||||
fsn_mark = fsnotify_find_inode_mark(group, inode);
|
||||
if (!fsn_mark)
|
||||
return -ENOENT;
|
||||
+ else if (create)
|
||||
+ return -EEXIST;
|
||||
|
||||
i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);
|
||||
|
||||
@@ -726,6 +729,10 @@ SYSCALL_DEFINE3(inotify_add_watch, int,
|
||||
if (unlikely(!f.file))
|
||||
return -EBADF;
|
||||
|
||||
+ /* IN_MASK_ADD and IN_MASK_CREATE don't make sense together */
|
||||
+ if (unlikely((mask & IN_MASK_ADD) && (mask & IN_MASK_CREATE)))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
/* verify that this is indeed an inotify instance */
|
||||
if (unlikely(f.file->f_op != &inotify_fops)) {
|
||||
ret = -EINVAL;
|
||||
@@ -814,7 +821,7 @@ static int __init inotify_user_setup(voi
|
||||
BUILD_BUG_ON(IN_ISDIR != FS_ISDIR);
|
||||
BUILD_BUG_ON(IN_ONESHOT != FS_IN_ONESHOT);
|
||||
|
||||
- BUG_ON(hweight32(ALL_INOTIFY_BITS) != 21);
|
||||
+ BUG_ON(hweight32(ALL_INOTIFY_BITS) != 22);
|
||||
|
||||
inotify_inode_mark_cachep = KMEM_CACHE(inotify_inode_mark, SLAB_PANIC);
|
||||
|
||||
Index: include/linux/inotify.h
|
||||
===================================================================
|
||||
--- include.orig/linux/inotify.h
|
||||
+++ include/linux/inotify.h
|
||||
@@ -17,6 +17,6 @@ extern struct ctl_table inotify_table[];
|
||||
IN_DELETE_SELF | IN_MOVE_SELF | IN_UNMOUNT | \
|
||||
IN_Q_OVERFLOW | IN_IGNORED | IN_ONLYDIR | \
|
||||
IN_DONT_FOLLOW | IN_EXCL_UNLINK | IN_MASK_ADD | \
|
||||
- IN_ISDIR | IN_ONESHOT)
|
||||
+ IN_MASK_CREATE | IN_ISDIR | IN_ONESHOT)
|
||||
|
||||
#endif /* _LINUX_INOTIFY_H */
|
||||
Index: include/uapi/linux/inotify.h
|
||||
===================================================================
|
||||
--- include.orig/uapi/linux/inotify.h
|
||||
+++ include/uapi/linux/inotify.h
|
||||
@@ -52,6 +52,7 @@ struct inotify_event {
|
||||
#define IN_ONLYDIR 0x01000000 /* only watch the path if it is a directory */
|
||||
#define IN_DONT_FOLLOW 0x02000000 /* don't follow a sym link */
|
||||
#define IN_EXCL_UNLINK 0x04000000 /* exclude events on unlinked objects */
|
||||
+#define IN_MASK_CREATE 0x10000000 /* only create watches */
|
||||
#define IN_MASK_ADD 0x20000000 /* add to the mask of an already existing watch */
|
||||
#define IN_ISDIR 0x40000000 /* event occurred against dir */
|
||||
#define IN_ONESHOT 0x80000000 /* only send event once */
|
||||
@@ -1,4 +1,4 @@
|
||||
SUBDIRS = finit.d
|
||||
docsdir := @docdir@/contrib/void
|
||||
docs_DATA = README.md finit.conf build.sh install.sh rc.local xbps
|
||||
docs_DATA = README.md finit.conf build.sh install.sh rc.local
|
||||
EXTRA_DIST = $(docs_DATA)
|
||||
|
||||
@@ -18,7 +18,7 @@ PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig ./configure \
|
||||
--sysconfdir=/etc --localstatedir=/var \
|
||||
--enable-dbus-plugin --enable-x11-common-plugin \
|
||||
--enable-alsa-utils-plugin --with-watchdog \
|
||||
--with-heading="Void Linux" --with-keventd
|
||||
--with-keventd
|
||||
|
||||
echo
|
||||
echo "*** Building ..."
|
||||
|
||||
@@ -8,7 +8,8 @@ if [ "x`id -u`" != "x0" ]; then
|
||||
fi
|
||||
|
||||
# Adjust base directory
|
||||
if [ -e xbps ]; then
|
||||
grep -q void Makefile 2>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
cd ../..
|
||||
elif [ ! -e configure.ac ]; then
|
||||
echo "*** Please run this script from the Finit base directory."
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
#
|
||||
# Each line is run in sequence.
|
||||
#
|
||||
# NOTE: Remeber to set the executable bit!
|
||||
# NOTE: Remember to set the executable bit!
|
||||
|
||||
+8
-2
@@ -21,11 +21,17 @@ Some of these are also registered in the issue tracker on GitHub.
|
||||
* Allow running as non-pid1 => read .conf and RCSD form cmdline
|
||||
* Add `finit.conf` support for UPS notification (SIGPWR) to start a task
|
||||
using, e.g. <sys/power/{ok,fail,low}> conditions. More info in sig.c
|
||||
|
||||
As of Finit v4.1 SIGPWR generates <sys/power/fail> condition and it
|
||||
is up to a task to check why and take appropriate action.
|
||||
* Add `finit.conf` support for ctrl-alt-delete (SIGINT) and kbrequest,
|
||||
i.e. KeyboardSignal, (SIGWINCH) behavior. Using conditions to a task,
|
||||
e.g, <sys/key/ctrlaltdel> and <sys/key/signal> like SIGPWR handling.
|
||||
* 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
|
||||
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
|
||||
|
||||
+11
-10
@@ -1,6 +1,8 @@
|
||||
Bootstrap
|
||||
=========
|
||||
|
||||
0. Get bearings, disable kernel logs, initialize TTY and print banner,
|
||||
unless `HOOK_BANNER` is defined, then call that instead
|
||||
1. Prepare emergency shell, if enabled
|
||||
2. Set up initial signal handlers
|
||||
3. Set up default $PATH early
|
||||
@@ -16,7 +18,9 @@ Bootstrap
|
||||
11. Load all `/etc/finit.d/*.conf` files and set hostname
|
||||
12. Remount `/` read-write if `/` is listed in `/etc/fstab` without `ro`
|
||||
13. Call 1st level hooks, `HOOK_ROOTFS_UP`
|
||||
14. Mount all file systems listed in `/etc/fstab` and swap, if available
|
||||
14. Mount all file systems listed in `/etc/fstab` and swap, if available.
|
||||
On mount error `HOOK_MOUNT_ERROR` is called. After mount, regardless
|
||||
of error, `HOOK_MOUNT_POST` is called
|
||||
15. Enable SysV init signals
|
||||
16. Call 2nd level hooks, `HOOK_BASEFS_UP`
|
||||
17. Cleanup stale files from `/tmp/*` et al, handled by `bootmisc` plugin
|
||||
@@ -38,16 +42,13 @@ Bootstrap
|
||||
26. Call 5th level (last) hooks, `HOOK_SYSTEM_UP`
|
||||
27. Start all configured TTYs
|
||||
|
||||
In (19) and (22) tasks and services defined in `/etc/finit.conf` and
|
||||
`/etc/sysctl.d/*.conf` are started. Remember, all `service` and `task`
|
||||
stanzas are started in parallel and `run` in sequence, and in the order
|
||||
listed. Hence, to emulate a SysV `/etc/init.d/rcS` one could write a
|
||||
long `finit.conf` with only `run` statements.
|
||||
In (19) and (23) tasks and services defined in `/etc/finit.conf` and
|
||||
`/etc/finit.d/*.conf` are started.
|
||||
|
||||
Notice the five hook points that are called at various point in the
|
||||
bootstrap process. This is where plugins can extend the boot in any way
|
||||
they please. There are other hook points, e.g. `HOOK_MOUNT_ERROR`, for
|
||||
more on this see [plugins.md](plugins.md).
|
||||
Notice the seven hook points that are called at various point in the
|
||||
bootstrap process. This is where plugins can extend the boot in any
|
||||
way they please. There are other hook points available, for more on
|
||||
this, see [plugins.md](plugins.md).
|
||||
|
||||
For instance, at `HOOK_BASEFS_UP` a plugin could read an XML file from a
|
||||
USB stick, convert/copy its contents to the system's `/etc/` directory,
|
||||
|
||||
+27
-12
@@ -27,10 +27,10 @@ optional plugins to enable. It depends on two external libraries:
|
||||
PKG_CONFIG_LIBDIR=/usr/local/lib/pkgconfig ./configure
|
||||
|
||||
The configure script checks for all dependencies, including the correct
|
||||
version of the above mentioned libraries. Currently requried versions:
|
||||
version of the above mentioned libraries. Currently required versions:
|
||||
|
||||
- libite v2.2.0
|
||||
- libuEv v2.2.0
|
||||
- libite v2.2.0, or later
|
||||
- libuEv v2.2.0, or later
|
||||
|
||||
|
||||
Configure
|
||||
@@ -54,7 +54,7 @@ Below are a few of the main switches to configure:
|
||||
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
|
||||
`/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.
|
||||
@@ -65,8 +65,19 @@ Below are a few of the main switches to configure:
|
||||
|
||||
* `--enable-x11-common-plugin`: Enable the optional X Window `x11-common.so` plugin.
|
||||
|
||||
* `--with-sulgin`: Enable bundled `sulogin` program. Default is to use the
|
||||
system `sulogin(8)`. The sulogin shipped with Finit *allows password-less*
|
||||
login if the `root` user is disabled or has no password at all.
|
||||
|
||||
For more configure flags, see <kbd>./configure --help</kbd>
|
||||
|
||||
> **Note:** the configure script is not available in the GIT sources. It is
|
||||
> however included in (officially supported) released tarballs. The
|
||||
> idea is that you should not need GNU autotools to build, only the
|
||||
> above mentioned dependencies, a POSIX shell, a C compiler and make.
|
||||
> Any contributing to Finit can generate it from `configure.ac` using
|
||||
> the `autogen.sh` script.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
@@ -74,8 +85,8 @@ Example
|
||||
First, unpack the archive:
|
||||
|
||||
```shell
|
||||
$ tar xf finit-4.1.tar.gz
|
||||
$ cd finit-4.1/
|
||||
$ tar xf finit-4.3.tar.gz
|
||||
$ cd finit-4.3/
|
||||
```
|
||||
|
||||
Then configure, build and install:
|
||||
@@ -83,8 +94,7 @@ Then configure, build and install:
|
||||
```shell
|
||||
$ ./configure --prefix=/usr --exec-prefix= \
|
||||
--sysconfdir=/etc --localstatedir=/var \
|
||||
--with-keventd --with-watchdog \
|
||||
--with-heading="Alpine Linux" --with-hostname=alpine
|
||||
--with-keventd --with-watchdog
|
||||
$ make
|
||||
.
|
||||
.
|
||||
@@ -92,7 +102,7 @@ $ make
|
||||
$ DESTDIR=/tmp/finit make install
|
||||
```
|
||||
|
||||
In this example the [finit-4.1.tar.gz][1] archive is unpacked to the
|
||||
In this example the [finit-4.3.tar.gz][1] archive is unpacked to the
|
||||
user's home directory, configured, built and installed to a temporary
|
||||
staging directory. The environment variable `DESTDIR` controls the
|
||||
destination directory when installing, very useful for building binary
|
||||
@@ -147,17 +157,22 @@ enabled. The default Finit rescue mode configuration is installed into
|
||||
|
||||
By default the a root shell, without login, is started.
|
||||
|
||||
> **Note:** in this mode `initctl` will not work. Use the `-f` flag to
|
||||
> force `reboot`, `shutdown`, or `poweroff`.
|
||||
|
||||
|
||||
Debugging
|
||||
---------
|
||||
|
||||
Edit, or append to, the kernel command line: remove `quiet` to enable
|
||||
kernel messages and add `debug` to enable Finit debug messages.
|
||||
kernel messages and add `finit.debug` to enable Finit debug messages.
|
||||
|
||||
```shell
|
||||
append="init=/sbin/finit debug"
|
||||
append="init=/sbin/finit -- finit.debug"
|
||||
```
|
||||
|
||||
Notice the `--` separator.
|
||||
|
||||
To debug startup issues, in particular issues with getty/login, add
|
||||
the following to your Finit .conf file:
|
||||
|
||||
@@ -176,6 +191,6 @@ it only for debugging start up issues when Finit crashes.
|
||||
systems since they can potentially give a user root access.
|
||||
|
||||
|
||||
[1]: ftp://troglobit.com/finit/finit-4.1.tar.gz
|
||||
[1]: ftp://troglobit.com/finit/finit-4.3.tar.gz
|
||||
[libuEv]: https://github.com/troglobit/libuev
|
||||
[libite]: https://github.com/troglobit/libite
|
||||
|
||||
+43
-8
@@ -10,13 +10,32 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
|
||||
> parameters to init. E.g., `init=/sbin/finit -- finit.debug rescue`
|
||||
|
||||
* `debug`: Enable kernel debug. Debug messages are printed to the
|
||||
console until Finit starts up.
|
||||
console until Finit starts up, unless `loglevel=7` (below) is used.
|
||||
|
||||
* `finit.debug[=bool]`: Enable finit debug. This is operated
|
||||
independently of the kernel debug setting. New as of Finit v4.
|
||||
independently of the kernel `debug` setting. New as of Finit v4.
|
||||
|
||||
* `finit.show_status[=bool]`: Control finit boot progress, including
|
||||
banner.
|
||||
* `finit.fstab=</path/to/etc/fstab.alternative>`: Tell Finit to use an
|
||||
alternate `fstab` to mount the file system from. Remember, this file
|
||||
must be on the `root=...` file system provided to Finit from the
|
||||
kernel. By default the built-in fstab is used, which itself defaults
|
||||
to `/etc/fstab`, but can be changed at build time with:
|
||||
|
||||
./configure --with-fstab=/path/to/fstab
|
||||
|
||||
It is even possible to disable a built-in default using:
|
||||
|
||||
./configure --without-fstab
|
||||
|
||||
Making `finit.fstab=/path/to/fstab` a *mandatory* command line option.
|
||||
Note, if the command line fstab is missing, Finit falls back to the
|
||||
built-in fstab, and if both are missing, the system treats this as a
|
||||
bad `fsck` and thus calls `sulogin`. If, in turn, `sulogin` is not
|
||||
available on the system, Finit calls reboot, which is also what will
|
||||
happen when a user exits from `sulogin`.
|
||||
|
||||
* `finit.status[=bool]`: Control finit boot progress, including banner.
|
||||
(Used to be `finit.show_status`, which works but is deprecated.)
|
||||
|
||||
* `finit.status_style=<classic,modern>`: Set Finit boot progress style,
|
||||
when enabled.
|
||||
@@ -26,25 +45,41 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
|
||||
signals and has no job control. Recommend using, and modifying,
|
||||
`rescue` mode instead.
|
||||
|
||||
* `loglevel=<0-7>`, sets the kernel's log level, which is more granular
|
||||
than `debug`. Also, when `loglevel=7`, Finit will *not disable*
|
||||
kernel logs to the console. This is very useful when debugging the
|
||||
kernel at system bring-up. Since `loglevel=7` is the same as `debug`
|
||||
this means you have to use `quiet` for a quiet boot, until sysklogd
|
||||
takes over logging of kernel events.
|
||||
|
||||
* `panic=SEC`: By default the kernel does not reboot after a kernel
|
||||
panic. This setting will cause a kernel reboot after SEC seconds.
|
||||
|
||||
* `quiet`: Suppress kernel logging to console, except for warnings and
|
||||
errors.
|
||||
errors. Also, see `loglevel` and `quiet` above.
|
||||
|
||||
* `rescue`: Start rescue/maintenance mode. If your system comes with
|
||||
the bundled `sulogin` program (Finit, or from util-linux/Busybox),
|
||||
you will be given a root login to a maintenance shell. However, if
|
||||
`sulogin` is missing, the file `/lib/finit/rescue.conf` is read and
|
||||
the system booted in a limited fallback mode. See [config.md][]
|
||||
for more information.
|
||||
for more information.
|
||||
|
||||
**Note:** in this mode `initctl` will not work. Correct the problem
|
||||
and use `reboot -f` to force reboot.
|
||||
|
||||
* `single`, or `S`: Single user mode, runlevel 1, in Finit. Useful to
|
||||
debug problems with the regular runlevel. All services and TTYs in
|
||||
`[1]` will be started, so a `tty [1] @console nologin` configuration
|
||||
presents you with a root console without login.
|
||||
|
||||
For more on kernel boot paramaters, see the man page [bootparam(7)][].
|
||||
* `1-9`, except `6`: override the configured `runlevel`. Like the `S`
|
||||
and `rescue`, giving a single number on the kernel command line tells
|
||||
Finit to ignore any `runlevel` in `/etc/finit.conf` as well as the
|
||||
configure fallback `--with-runlevel=N` setting. Remember, `6` is the
|
||||
reboot runlevel and is not permitted. Any other values are ignored.
|
||||
|
||||
[config.md][]: config.md#rescue-mode
|
||||
For more on kernel boot parameters, see the man page [bootparam(7)][].
|
||||
|
||||
[config.md]: config.md#rescue-mode
|
||||
[bootparam(7)]: https://www.man7.org/linux/man-pages/man7/bootparam.7.html
|
||||
|
||||
+2
-2
@@ -90,7 +90,7 @@ Built-in Conditions
|
||||
Finit comes with a set of plugins for conditions: `pidfile`, `netlink`,
|
||||
`sys`, and `usr`. The `pidfile` plugin (recursively) watches `/run/`
|
||||
(recursively) for PID files created by the monitored services, and sets
|
||||
a corresponding condition in the `pid/` namespace. Similarily, the
|
||||
a corresponding condition in the `pid/` namespace. Similarly, the
|
||||
`netlink` plugin provides basic conditions for when an interface is
|
||||
brought up/down and when a default route (gateway) is set, in the `net/`
|
||||
namespace. The `sys` and `usr` plugins monitor are passive condition
|
||||
@@ -180,7 +180,7 @@ PID IDENT STATUS CONDITION (+ ON, ~ FLUX, - OFF)
|
||||
|
||||
Here we can see that `netd` is allowed to run since both its conditions
|
||||
are in the `on` state, as indicated by the `+`-prefix. `udhcpc` however
|
||||
is not allowed to run since `net/vlan1/exist` condition is not satsifed.
|
||||
is not allowed to run since `net/vlan1/exist` condition is not satisfied.
|
||||
As indicated by the `-`-prefix.
|
||||
|
||||
To fake interface `vlan1` suddenly appearing, and test what happens to
|
||||
|
||||
+94
-21
@@ -43,13 +43,13 @@ Not all configuration directives are available in `/etc/finit.d/*.conf`
|
||||
and some directives are only available at [bootstrap][], runlevel `S`,
|
||||
see the section [Limitations](#limitations) below for details.
|
||||
|
||||
To add a new service, simply drop a `.conf` file in `/etc/finit.d` and
|
||||
run `initctl reload`. (It is also possible to `SIGHUP` to PID 1, or
|
||||
call `finit q`, but that has been deprecated with the `initctl` tool).
|
||||
Finit monitors all known active `.conf` files, so if you want to force
|
||||
a restart of any service you can simply touch its corresponding `.conf`
|
||||
file in `/etc/finit.d` and call `initctl reload`. Finit handle any
|
||||
and all conditions and dependencies between services automatically.
|
||||
To add a new service, drop a `.conf` file in `/etc/finit.d` and run
|
||||
`initctl reload`. (It is also possible to `SIGHUP` to PID 1, or call
|
||||
`finit q`, but that has been deprecated with the `initctl` tool). Finit
|
||||
monitors all known active `.conf` files, so if you want to force a
|
||||
restart of any service you can touch its corresponding `.conf` file in
|
||||
`/etc/finit.d` and call `initctl reload`. Finit handle any and all
|
||||
conditions and dependencies between services automatically.
|
||||
|
||||
It is also possible to drop `.conf` files in `/etc/finit.d/available/`
|
||||
and use `initctl enable` to enable a service `.conf` file. This may be
|
||||
@@ -59,7 +59,7 @@ files for a package and let the user decide when to enable a service.
|
||||
On `initctl reload` the following is checked for all services:
|
||||
|
||||
- If a service's `.conf` file has been removed, or its conditions are no
|
||||
longer satisifed, the service is stopped.
|
||||
longer satisfied, the service is stopped.
|
||||
- If the file is modified, or a service it depends on has been reloaded,
|
||||
the service is reloaded (stopped and started).
|
||||
- If a new service is added it is automatically started — respecting
|
||||
@@ -73,6 +73,36 @@ document [Finit Services](service.md).
|
||||
> examples in the `contrib/` directory, which can be used as a base.
|
||||
|
||||
|
||||
### Environment Variables
|
||||
|
||||
In Finit v4.3 support for setting environment variables in `finit.conf`,
|
||||
and any `*.conf`, was added. It is worth noting that these are global
|
||||
and *shared with all* services -- the only way to have service-local
|
||||
environment is detailed in the next section.
|
||||
|
||||
The syntax for global environment variables is straight forward:
|
||||
|
||||
foo=bar
|
||||
baz="qux"
|
||||
|
||||
On reload of .conf files, all tracked environment variables are cleared
|
||||
so if `foo=bar` is removed from `finit.conf`, or any `finit.d/*.conf`
|
||||
file, it will no longer be used by Finit or any new (!) started
|
||||
run/tasks or services. The environment of already started processes can
|
||||
not be changed.
|
||||
|
||||
The only variables reset to sane defaults on .conf reload are:
|
||||
|
||||
PATH=_PATH_STDPATH
|
||||
SHELL=_PATH_BSHELL
|
||||
LOGNAME=root
|
||||
USER=root
|
||||
|
||||
It is entirely possible to override these as well from the .conf files,
|
||||
but be careful. Changing SHELL changes the behavior of `system()` and a
|
||||
lot of other commands as well.
|
||||
|
||||
|
||||
Service Environment
|
||||
-------------------
|
||||
|
||||
@@ -154,7 +184,7 @@ Top-level group configuration.
|
||||
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
|
||||
the above three. We leave `init/` and `user/` as-is reducing weight of
|
||||
`system/` to 9700.
|
||||
|
||||
cgroup system cpu.weight:9700
|
||||
@@ -184,7 +214,7 @@ The latter form also allows per-stanza limits on the form:
|
||||
|
||||
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 not filtering,
|
||||
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.
|
||||
@@ -323,6 +353,10 @@ calls `init-script restart` on `initctl reload`. Similar to how
|
||||
|
||||
Forking services started with `sysv` scripts can be monitored by Finit
|
||||
by declaring the PID file to look for: `pid:!/path/to/pidfile.pid`.
|
||||
Notice the leading `!`, it signifies Finit should not try to create the
|
||||
file, but rather watch that file for the resulting forked-off PID. This
|
||||
syntax also works for forking daemons that do not have a command line
|
||||
option to run it in the foreground, more on this below in `service`.
|
||||
|
||||
> `<COND>` is described in the [Services](#services) section.
|
||||
|
||||
@@ -332,8 +366,13 @@ by declaring the PID file to look for: `pid:!/path/to/pidfile.pid`.
|
||||
**Syntax:** `service [LVLS] <COND> /path/to/daemon ARGS -- Optional description`
|
||||
|
||||
Service, or daemon, to be monitored and automatically restarted if it
|
||||
exits prematurely. Finit tries to restart services that die 10 times
|
||||
before giving up, then you have to `initctl restart NAME` it manually.
|
||||
exits prematurely. Finit tries to restart services that die, by
|
||||
default 10 times before giving up and marking them as *crashed*.
|
||||
After which they have to be manually restarted with `initctl restart
|
||||
NAME`. The limits controling this are configurable, see the options
|
||||
below.
|
||||
|
||||
> **Tip:** to allow endless restarts, see below option `respawn`
|
||||
|
||||
For daemons that support it, we recommend appending `--foreground`,
|
||||
`--no-background`, `-n`, `-F`, or similar command line argument to
|
||||
@@ -341,9 +380,19 @@ prevent them from forking off a sub-process in the background. This is
|
||||
the most reliable way to monitor a service.
|
||||
|
||||
However, not all daemons support running in the foreground, or they may
|
||||
start logging to the foreground as well, these are called forking
|
||||
services and are supported using the same syntax as forking `sysv`
|
||||
services, using the `pid:!/path/to/pidfile.pid` syntax.
|
||||
start logging to the foreground as well, these are forking daemons and
|
||||
are supported using the same syntax as forking `sysv` services, using
|
||||
the `pid:!/path/to/pidfile.pid` syntax. There is an alternative syntax
|
||||
that may be more intuitive, where Finit can also guess the PID file
|
||||
based on the daemon's command name:
|
||||
|
||||
service type:forking ntpd -- NTP daemon
|
||||
|
||||
This example lets BusyBox `ntpd` daemonize itself. Finit uses the
|
||||
basename of the binary to guess the PID file to watch for the PID:
|
||||
`/var/run/ntpd.pid`. If Finit guesses wrong, you have to submit the
|
||||
full `pid:!/path/to/file.pid`.
|
||||
|
||||
|
||||
**Example:**
|
||||
|
||||
@@ -390,6 +439,25 @@ optional `name` argument:
|
||||
|
||||
name:<service-name>
|
||||
|
||||
As mentioned previously, services are automatically restarted, this is
|
||||
configurable with the following options:
|
||||
|
||||
* `restart:NUM` -- number of times Finit tries to restart a crashing
|
||||
service, default: 10, max: 255. When this limit is reached the
|
||||
service is marked *crashed* and must be restarted manually with
|
||||
`initctl restart NAME`
|
||||
* `restart_sec:SEC` -- number of seconds before Finit tries to restart
|
||||
a crashing service, default: 2 seconds for the first five retries,
|
||||
then back-off to 5 seconds. The maximum of this configured value
|
||||
and the above (2 and 5) will be used
|
||||
* `norestart` -- dont restart on failures, same as `restart:0`
|
||||
* `respawn` -- bypasses the `restart` mechanism completely, allows
|
||||
endless restarts. Useful in many use-cases, but not what `service`
|
||||
was originally designed for so not the default behavior
|
||||
* `oncrash:reboot` -- when all retries have failed, and the service
|
||||
has *crashed*, if this option is set the system is rebooted.
|
||||
Note, future releases may include other `oncrash:` actions
|
||||
|
||||
When stopping a service (run/task/sysv/service), either manually or
|
||||
when moving to another runlevel, Finit starts by sending `SIGTERM`, to
|
||||
allow the process to shut down gracefully. If the process has not
|
||||
@@ -473,8 +541,9 @@ size limit is reached.
|
||||
`tty [LVLS] <COND> [notty] [rescue]`
|
||||
|
||||
The first variant of this option uses the built-in getty on the given
|
||||
TTY device DEV, in the given runlevels. The DEV may be the special
|
||||
keyword `@console`, or `console`, useful on embedded systems.
|
||||
TTY device DEV, in the given runlevels. DEV may be the special keyword
|
||||
`@console`, which is expanded from `/sys/class/tty/console/active`,
|
||||
useful on embedded systems.
|
||||
|
||||
The default baud rate is 0, i.e., keep kernel default.
|
||||
|
||||
@@ -555,8 +624,8 @@ One can also use the `service` stanza to start a stand-alone shell:
|
||||
### Non-privileged Services
|
||||
|
||||
Every `run`, `task`, or `service` can also list the privileges the
|
||||
`/path/to/cmd` should be executed with. Simply prefix the path with
|
||||
`[@USR[:GRP]]` like this:
|
||||
`/path/to/cmd` should be executed with. Prefix the command with
|
||||
`@USR[:GRP]`, group is optional, like this:
|
||||
|
||||
run [2345] @joe:users logger "Hello world"
|
||||
|
||||
@@ -606,6 +675,9 @@ activate it.
|
||||
|
||||
The rescue mode comes in two flavors; *traditional* and *fallback*.
|
||||
|
||||
> **Note:** in this mode `initctl` will not work. Use the `-f` flag to
|
||||
> force `reboot`, `shutdown`, or `poweroff`.
|
||||
|
||||
|
||||
### Traditional
|
||||
|
||||
@@ -654,8 +726,9 @@ Limitations
|
||||
-----------
|
||||
|
||||
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
|
||||
from `/etc/finit.conf`, since it is the first `.conf` file Finit reads.
|
||||
placed. Except for the system/global `rlimit` and `cgroup` top-level
|
||||
group declarations, which can only be set from `/etc/finit.conf`, since
|
||||
it is the first `.conf` file Finit reads.
|
||||
|
||||
Originally, `/etc/finit.conf` was the only way to set up a Finit system.
|
||||
Today it is mainly used for bootstrap settings like system hostname,
|
||||
|
||||
+34
-5
@@ -34,26 +34,50 @@ For your convenience a set of *optional* plugins are available:
|
||||
* *dbus.so*: Setup and start system message bus, D-Bus, at boot.
|
||||
_Optional plugin._
|
||||
|
||||
* *hook-scripts.so*: Trigger the execution of scripts from plugin hook
|
||||
points (see [Hooks](#hooks)). Scripts are located in
|
||||
`/libexec/finit/hook` by default, this can be build-time customized
|
||||
by using the `--with-hook-scripts-path=PATH` argument to
|
||||
`configure`. _Optional plugin._
|
||||
|
||||
* *hotplug.so*: Setup and start either udev or mdev hotplug daemon, if
|
||||
available.
|
||||
available. Enabled by default.
|
||||
|
||||
* *rtc.so*: Restore and save system clock from/to RTC on boot/halt.
|
||||
Enabled by default.
|
||||
|
||||
* *modules-load.so*: Scans /etc/modules-load.d for modules to modprobe.
|
||||
* *modules-load.so*: Scans `/etc/modules-load.d/*.conf` for modules to
|
||||
load using `modprobe`. Each file can contain multiple lines with the
|
||||
name of the module to load. Any line starting with the standard UNIX
|
||||
comment character, `#`, is skipped.
|
||||
|
||||
Modules are loaded when entering runlevel `[2345]` using the `task`
|
||||
stanza. Each module gets a unique `name:modprobe.foo`, and
|
||||
optional`:ID`. The `:ID` is a globally incremented index, which can
|
||||
be disabled per file (anywhere) using the following config line:
|
||||
|
||||
set noindex
|
||||
|
||||
**Note:** unlike the traditional .conf `module` directive, which load
|
||||
any listed module immediately, this plugin creates standard `taks`
|
||||
directives which load the module(s) in the background. As long as
|
||||
the `modprobe` program is found in the path, these tasks will always
|
||||
return `[ OK ]` at boot. Check the actual status using `initctl`.
|
||||
|
||||
* *netlink.so*: Listens to Linux kernel Netlink events for gateway and
|
||||
interfaces. These events are then sent to the Finit service monitor
|
||||
for services that may want to be SIGHUP'ed on new default route or
|
||||
interfaces going up/down.
|
||||
interfaces going up/down. Enabled by default.
|
||||
|
||||
* *resolvconf.so*: Setup necessary files for `resolvconf` at startup.
|
||||
_Optional plugin._
|
||||
|
||||
* *tty.so*: Watches `/dev`, using inotify, for new device nodes (TTY's)
|
||||
to start/stop getty consoles on them on demand. Useful when plugging
|
||||
in a usb2serial converter to login to your embedded device.
|
||||
in a usb2serial converter to login to your embedded device. Enabled
|
||||
by default.
|
||||
|
||||
* *urandom.so*: Setup random seed at startup.
|
||||
* *urandom.so*: Setup random seed at startup. Enabled by default.
|
||||
|
||||
* *x11-common.so*: Setup necessary files for X-Window. _Optional plugin._
|
||||
|
||||
@@ -69,6 +93,11 @@ Hooks
|
||||
|
||||
### Bootstrap Hooks
|
||||
|
||||
* `HOOK_BANNER`: The very first point at which a plugin can run.
|
||||
Intended to be used as a banner replacement. Essentially this runs
|
||||
just before entering runlevel S. Assume nothing is available, so
|
||||
be prepared to use absolute paths, etc.
|
||||
|
||||
* `HOOK_ROOTFS_UP`: When `finit.conf` has been read and `/` has is
|
||||
mounted — very early
|
||||
|
||||
|
||||
+55
-1
@@ -1,7 +1,59 @@
|
||||
Finit Services
|
||||
==============
|
||||
|
||||

|
||||
Starting & Monitoring
|
||||
---------------------
|
||||
|
||||
Finit can start and monitor the following types of daemons:
|
||||
|
||||
* Forks to background, creates a PID file
|
||||
* Runs in foreground:
|
||||
- creates a PID file
|
||||
- does not create a PID file -- Finit can create it for you (optional)
|
||||
|
||||
Finit can *not* start and monitor a daemon that:
|
||||
|
||||
* Forks to background and does *not* create a PID file
|
||||
|
||||
| | Forking | Creates PID File | Finit creates PID File |
|
||||
|---|---------|------------------|------------------------|
|
||||
| ✔ | Yes | Yes | No |
|
||||
| ✔ | No | Yes | No |
|
||||
| ✔ | No | No | Yes, optionally |
|
||||
| ✘ | Yes | No | No |
|
||||
|
||||
> **Note:** PID files is one mechanism used to assert conditions to
|
||||
> synchronize the start and stop of other, dependent, services.
|
||||
|
||||
### Forks to Background w/ PID File
|
||||
|
||||
There are two syntax variants, type 1 and type 2. The former is the
|
||||
traditional one used also for `sysv` start/stop scripts, and the latter
|
||||
is inspired by systemd, with a twist -- it lets Finit guess the pifdile
|
||||
to look for based on the standard path and the basename of the command.
|
||||
|
||||
service pid:!/run/serv.pid serv -- Forking service, type 1
|
||||
service type:forking serv -- Forking service, type 2
|
||||
|
||||
In this example the resulting files to watch for are `/run/serv.pid` and
|
||||
`/var/run/serv.pid`, respectively. On most modern Linux systems this is
|
||||
the same directory (`/var/run` is a symlink to `../run`).
|
||||
|
||||
### Runs in Foreground w/ PID File
|
||||
|
||||
service serv -n -p -- Foreground service w/ PID file
|
||||
|
||||
### Runs in Foreground w/o PID File
|
||||
|
||||
Same as previous, but we tell Finit to create the PID file, because we
|
||||
need it to synchronize start/stop of a dependent service.
|
||||
|
||||
service pid:/run/serv.pid serv -n -- Foreground service w/o PID file
|
||||
|
||||
### Runs in Foreground w/ Custom PID File
|
||||
|
||||
service pid:/run/servy.pid serv -n -p -P /run/servy.pid -- Foreground service w/ custom PID file
|
||||
|
||||
|
||||
State Machine
|
||||
-------------
|
||||
@@ -11,6 +63,8 @@ For `run`s and `task`s there is an additional end state called `DONE`,
|
||||
not shown in the diagram for brevity. Services start in the `HALTED`
|
||||
state.
|
||||
|
||||

|
||||
|
||||
The current state depends on the two following conditions:
|
||||
|
||||
* `E`: Service enabled. In order for `E` to be satisfied, the service
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
Makefile
|
||||
Makefile.in
|
||||
@@ -0,0 +1,2 @@
|
||||
dist_man8_MANS = finit.8 initctl.8
|
||||
dist_man5_MANS = finit.conf.5
|
||||
+261
@@ -0,0 +1,261 @@
|
||||
.\" 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 --
|
||||
.Op finit.debug
|
||||
.Op finit.fstab=/etc/fstab.alt
|
||||
.Op finit.status=<on,off>
|
||||
.Op finit.status_style=<classic,modern>
|
||||
.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 BOOTPARAM
|
||||
.Nm
|
||||
support the following command line parameters to alter the behavior
|
||||
at boot. Notice the
|
||||
.Cm --
|
||||
separator needed to tell the kernel which paramters should be given to
|
||||
PID 1. For more information on this, and available kernel command line
|
||||
options, see
|
||||
.Xr bootparam 7 .
|
||||
.Bl -tag -width pid -offset indent
|
||||
.It Cm finit.debug
|
||||
Enable Finit debug messages on system console and log. Sometimes useful
|
||||
when doing board bringup. Before the system log daemon has started,
|
||||
Finit use the kernel ring buffer,
|
||||
.Pa /dev/kmsg .
|
||||
.It Cm finit.fstab=/path/to/fstab.alt
|
||||
Tell
|
||||
.Nm
|
||||
to use an alternate
|
||||
.Cm fstab
|
||||
to mount the file system from. Remember, this file must be on the
|
||||
.Cm root=...
|
||||
file system provided to Finit from the kernel. If this file is missing,
|
||||
.Nm
|
||||
falls back to its built-in default, which can be changed at build time
|
||||
using the
|
||||
.Cm --with-fstab=/path/to/footab
|
||||
configure option. It is even possible to completely disable the
|
||||
built-in using
|
||||
.Cm --without-fstab ,
|
||||
meaning
|
||||
.Nm
|
||||
.Sy must
|
||||
be started with the
|
||||
.Cm finit.fstab
|
||||
option.
|
||||
.Pp
|
||||
Should
|
||||
.Nm
|
||||
discover that there is no fstab file available, including the fallback,
|
||||
it triggers the same failure mode as when
|
||||
.Cm fsck
|
||||
fails, starting
|
||||
.Xr sulogin 8 ,
|
||||
if that is availble. When
|
||||
.Cm sulogin
|
||||
is missing, or when the user exits from
|
||||
.Cm sulogin ,
|
||||
the system is rebooted.
|
||||
.Pp
|
||||
Default fstab, unless changed at build-time:
|
||||
.Pa /etc/fstab
|
||||
.It Cm finit.status=<on,off>
|
||||
Control finit boot progress, including banner. This used to be called
|
||||
.Cm finit.show_status ,
|
||||
which still works but is deprecated.
|
||||
.It Cm finit.status_style=<classic,modern>
|
||||
Set Finit boot progress style, when enabled.
|
||||
.It Cm rescue | recover
|
||||
Start rescue/maintenance mode. If your system comes with the bundled
|
||||
.Cm sulogin
|
||||
program (Finit, or from util-linux/Busybox), you will be given a root
|
||||
login to a maintenance shell. However, if
|
||||
.Cm sulogin
|
||||
is missing, the file
|
||||
.Pa /lib/finit/rescue.conf
|
||||
is read and the system booted in a limited fallback mode. See
|
||||
.Xr finit.conf 5
|
||||
for more information.
|
||||
.It Cm single | S
|
||||
Single user mode, runlevel 1, in Finit. Useful to debug problems with
|
||||
the regular runlevel. All services and TTYs in
|
||||
.Cm [1]
|
||||
will be started, e.g., a
|
||||
.Cm tty [1] @console nologin
|
||||
configuration presents you with a root console without login.
|
||||
.El
|
||||
.Sh BOOTING
|
||||
.Pp
|
||||
Before laucnhing services, the system needs to be bootstrapped. This
|
||||
involves mounting all filesystems (not already mounted by an initramfs)
|
||||
in
|
||||
.Pa /etc/fstab ,
|
||||
or any alternate
|
||||
.Pa fstab
|
||||
file provided on the Finit command line using
|
||||
.Cm finit.fstab ,
|
||||
ensuring that necessary filesystems like:
|
||||
.Pa /dev ,
|
||||
.Pa /proc ,
|
||||
.Pa /sys ,
|
||||
and
|
||||
.Pa /run
|
||||
are available and can provide the system with the services required.
|
||||
.Pp
|
||||
With that out of the way, a set of plugins take over:
|
||||
.Pp
|
||||
.Bl -tag -width bootmisc.so -offset indent
|
||||
.It Cm bootmisc.so
|
||||
Cleans up stale files from previous boots and default directories are
|
||||
created in tmpfs filesystems
|
||||
.It Cm modprobe.so
|
||||
Probes kernel modules required by the system
|
||||
.It Cm procps.so
|
||||
Set kernel variables from
|
||||
.Pa /etc/sysctl.conf
|
||||
et al
|
||||
.El
|
||||
.Pp
|
||||
When the plugins are done, finit reads
|
||||
.Pa /etc/finit.conf
|
||||
and all other enabled services in
|
||||
.Pa /etc/finit.d/* .
|
||||
First all services, run/tasks in runlevel S (bootStrap) are started,
|
||||
When all run/tasks have completed, Finit changes to the configured
|
||||
runlevel (default 2), Processes are started in parallel, in dependency
|
||||
order according to their conditions.
|
||||
.Pp
|
||||
When all services and run/tasks have been started, the console progress
|
||||
is disabled and all configured getty services are started.
|
||||
.Sh CONDITIONS
|
||||
The condition subysystem in Finit was initially created to track PID
|
||||
files of daemons. If service/task B requires service A to have started,
|
||||
Finit waits for the PID file of service A to be created/updated before
|
||||
it starts service B. Conversely, if service A is stopped and its PID
|
||||
file removed, service B is also stopped.
|
||||
.Pp
|
||||
The following condition families are available today:
|
||||
.Pp
|
||||
.Bl -tag -width 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,874 @@
|
||||
.\" 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
|
||||
.Bd -filled -offset indent
|
||||
.Sy Tip:
|
||||
to allow endless restarts, see below option
|
||||
.Cm respawn
|
||||
.Ed
|
||||
.Pp
|
||||
For daemons that support it, we recommend appending
|
||||
.Cm --foreground , --no-background , -n , -F ,
|
||||
or similar command line argument to prevent them from forking off a
|
||||
sub-process in the background. This is the most reliable way to monitor
|
||||
a service.
|
||||
.Pp
|
||||
However, not all daemons support running in the foreground, or they may
|
||||
start logging to the foreground as well, these are called forking
|
||||
services and are supported using the same syntax as forking
|
||||
.Cm sysv
|
||||
services, using the
|
||||
.Cm pid:!/path/to/pidfile.pid
|
||||
command modifier syntax. There is an alternative syntax that may be
|
||||
more intuitive, where Finit can also guess the PID file based on the
|
||||
daemon's command name:
|
||||
.Bd -unfilled -offset indent
|
||||
service type:forking ntpd -- NTP daemon
|
||||
.Ed
|
||||
.Pp
|
||||
Here we let BusyBox
|
||||
.Nm ntpd
|
||||
daemonize itself. Finit uses the basename of the binary to guess the
|
||||
PID file to watch for the PID:
|
||||
.Pa /var/run/ntpd.pid .
|
||||
If Finit guesses wrong, you have to submit the full
|
||||
.Cm pid:!/path/to/file.pid
|
||||
option to your service stanza.
|
||||
.Pp
|
||||
.Sy Example: in the case of
|
||||
.Cm ospfd
|
||||
(below), we omit the
|
||||
.Cm -d
|
||||
flag (daemonize) to prevent it from forking to the background:
|
||||
.Bd -unfilled -offset indent
|
||||
service [2345] <pid/zebra> /sbin/ospfd -- OSPF daemon
|
||||
.Ed
|
||||
.Pp
|
||||
.Cm [2345]
|
||||
denote the runlevels
|
||||
.Cm ospfd
|
||||
is allowed to run in, they are optional and default to runlevel 2-5 if
|
||||
omitted.
|
||||
.Pp
|
||||
.Cm <pid/zebra>
|
||||
is the condition for starting
|
||||
.Cm ospfd .
|
||||
In this example Finit waits for another service,
|
||||
.Cm zebra ,
|
||||
to have created its PID file in
|
||||
.Pa /var/run/quagga/zebra.pid
|
||||
before starting
|
||||
.Cm ospfd .
|
||||
Finit watches *all* files in
|
||||
.Pa /var/run ,
|
||||
for each file named
|
||||
.Cm *.pid ,
|
||||
.Cm */pid ,
|
||||
Finit opens it and find the matching
|
||||
.Cm NAME:ID
|
||||
using the PID.
|
||||
.Pp
|
||||
Some services do not maintain a PID file and rather than patching each
|
||||
application Finit provides a workaround. A
|
||||
.Cm pid
|
||||
modifier keyword can be set to have Finit automatically create (when
|
||||
starting) and later remove (when stopping) the PID file. The file is
|
||||
created in the
|
||||
.Pa /var/run
|
||||
directory using the
|
||||
.Xr basename 3
|
||||
of the service. The full syntax of the
|
||||
.Cm pid
|
||||
modifier is:
|
||||
.Bd -unfilled -offset indent
|
||||
pid[:[!][/path/to/]filename[.pid]]
|
||||
.Ed
|
||||
.Pp
|
||||
For example, by adding
|
||||
.Cm pid:/run/foo.pid
|
||||
to the service
|
||||
.Cm /sbin/bar ,
|
||||
that PID file will, not only be created and removed automatically, but
|
||||
also be used by the Finit condition subsystem. So a service/run/task
|
||||
can depend on the
|
||||
.Cm <pid/bar>
|
||||
condition.
|
||||
.Pp
|
||||
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 respawn
|
||||
bypasses the
|
||||
.Cm restart
|
||||
mechanism completely, allows endless restarts. Useful in many
|
||||
use-cases, but not what
|
||||
.Cm service
|
||||
was originally designed for so not the default behavior.
|
||||
.It Cm oncrash:reboot
|
||||
when all retries have failed, and the service
|
||||
has
|
||||
.Em crashed ,
|
||||
if this option is set the system is rebooted. 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.
|
||||
+236
@@ -0,0 +1,236 @@
|
||||
.\" 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 bcfhlpqtvV
|
||||
.Op COMMAND
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is the official tool for interacting with
|
||||
.Xr finit 8 .
|
||||
It comes with functions for showing status, querying health of services,
|
||||
as well as editing, enabling and disabling services.
|
||||
.Sh OPTIONS
|
||||
This program follows the usual UNIX command line syntax, with long
|
||||
options starting with two dashes (`-'). The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl b, -batch
|
||||
Batch mode, no screen size probing. Useful for scripting.
|
||||
.It Fl c, -create
|
||||
Create missing paths (and files) as needed. Useful with the
|
||||
.Cm edit
|
||||
command.
|
||||
.It Fl f, -force
|
||||
Ignore missing files and arguments, never prompt.
|
||||
.It Fl h, -help
|
||||
Show built-in help text.
|
||||
.It Fl 1, -once
|
||||
Only one lap in commands like top.
|
||||
.It Fl p, -plain
|
||||
Use plain table headings, no ANSI control characters.
|
||||
.It Fl q, -quiet
|
||||
Silent, only return status of command.
|
||||
.It Fl t, -no-heading
|
||||
Skip table headings.
|
||||
.It Fl v, -verbose
|
||||
Verbose output, where applicable.
|
||||
.It Fl V, -version
|
||||
Show program version.
|
||||
.El
|
||||
.Sh COMMANDS
|
||||
.Bl -tag -width Ds
|
||||
.It Nm Ar debug
|
||||
Toggle
|
||||
.Nm finit
|
||||
(daemon) debug to
|
||||
.Pa /dev/console
|
||||
.It Nm Ar help
|
||||
Show built-in help text
|
||||
.It Nm Ar version
|
||||
Show program version
|
||||
.It Nm Ar ls | list
|
||||
List all
|
||||
.Cm *.conf
|
||||
files in
|
||||
.Pa /etc/finit.d
|
||||
.It Nm Ar create Ar CONF
|
||||
Create
|
||||
.Cm .conf
|
||||
in
|
||||
.Pa /etc/finit.d/available .
|
||||
.Pp
|
||||
Piping the contents into
|
||||
.Nm
|
||||
works as one would expect:
|
||||
.Bd -literal -offset indent
|
||||
echo "task name:foo /tmp/foo.sh -- Foo logger" | initctl create foo
|
||||
initctl enable foo
|
||||
initctl reload
|
||||
.Ed
|
||||
.It Nm Ar delete Ar CONF
|
||||
Delete
|
||||
.Cm .conf
|
||||
in
|
||||
.Pa /etc/finit.d/available
|
||||
.It Nm Ar show Ar CONF
|
||||
Show
|
||||
.Cm .conf
|
||||
in
|
||||
.Pa /etc/finit.d/available
|
||||
.It Nm Ar edit Ar CONF
|
||||
Edit
|
||||
.Cm .conf
|
||||
in
|
||||
.Pa /etc/finit.d/available
|
||||
.It Nm Ar touch Ar CONF
|
||||
Change (mark as modified)
|
||||
.Cm .conf
|
||||
in
|
||||
.Pa /etc/finit.d/available ,
|
||||
like
|
||||
.Ar edit
|
||||
this tells
|
||||
.Nm finit
|
||||
that a configuration has been changed and is a candidate to be restarted
|
||||
(or SIGHUP'ed) on
|
||||
.Cm initctl reload
|
||||
.It Nm Ar enable Ar CONF
|
||||
Enable
|
||||
.Cm .conf
|
||||
in
|
||||
.Pa /etc/finit.d/available ,
|
||||
i.e., add symlink in
|
||||
.Pa /etc/finit.d/enabled
|
||||
.It Nm Ar disable Ar CONF
|
||||
Disable
|
||||
.Cm .conf
|
||||
in
|
||||
.Pa /etc/finit.d/enabled ,
|
||||
i.e., removes symlink
|
||||
.It Nm Ar reload
|
||||
Reload
|
||||
.Cm *.conf in
|
||||
.Pa /etc/finit.d ,
|
||||
i.e., activates changes
|
||||
.It Nm Ar cond set Ar COND
|
||||
Set (assert) user-defined condition,
|
||||
.Cm +usr/COND
|
||||
.It Nm Ar cond get Ar COND
|
||||
Get (quietly) the status of any condition. Defaults to user-defined
|
||||
condions, but if a slash is detected, e.g.,
|
||||
.Cm pid/foo
|
||||
or
|
||||
.Cm net/eth0/exist ,
|
||||
then any condition can be read.
|
||||
.Pp
|
||||
The command is geared for scripting, check the exit code to get the
|
||||
status of the condition, or give
|
||||
.Nm
|
||||
the
|
||||
.Fl v
|
||||
option for a more verbose output.
|
||||
.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 as if its configuration had changed. Internally,
|
||||
.Nm finit
|
||||
marks the named service as "dirty" and turns the state machine,
|
||||
resulting in a SIGHUP or restart of (at least) the named service.
|
||||
Any dependant services are also restarted.
|
||||
.Pp
|
||||
.Sy Note:
|
||||
no .conf file is reloaded with this variant of the command. Essentially
|
||||
it is the same as calling
|
||||
.Cm restart .
|
||||
Except for two things:
|
||||
.Bl -enum -offset indent -compact
|
||||
.It
|
||||
if the service supports HUP, it's signaled instead of stop-started, and
|
||||
.It
|
||||
it allows restarting run/task in the same runlevel -- which is otherwise
|
||||
restricted
|
||||
.El
|
||||
.It Nm Ar signal Cm NAME:[ID] S
|
||||
Send signal S to service, by name.
|
||||
.Cm S
|
||||
may be a complete signal name such as SIGHUP, or short name such as HUP, or the signal number such as 1 (SIGHUP).
|
||||
.It Nm Ar restart Cm NAME[:ID]
|
||||
Restart (stop/start) service by name
|
||||
.It Nm Ar status Cm NAME[:ID]
|
||||
Show service status, by name. If only
|
||||
.Cm NAME
|
||||
is given and multiple instances exits, a summary of all matching
|
||||
instances are shown. Only an exact match displays 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.
|
||||
+23
-3
@@ -3,11 +3,11 @@ AM_LDFLAGS = -module -avoid-version -shared
|
||||
AM_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/src -U_FORTIFY_SOURCE
|
||||
AM_CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
|
||||
AM_CPPFLAGS += $(lite_CFLAGS)
|
||||
AM_CPPFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
|
||||
|
||||
if STATIC
|
||||
noinst_LTLIBRARIES = libplug.la
|
||||
libplug_la_SOURCES = bootmisc.c modprobe.c pidfile.c procps.c sys.c tty.c usr.c
|
||||
libplug_la_SOURCES = bootmisc.c pidfile.c procps.c sys.c usr.c
|
||||
|
||||
if BUILD_ALSA_UTILS_PLUGIN
|
||||
libplug_la_SOURCES += alsa-utils.c
|
||||
@@ -25,6 +25,10 @@ if BUILD_MODULES_LOAD_PLUGIN
|
||||
libplug_la_SOURCES += modules-load.c
|
||||
endif
|
||||
|
||||
if BUILD_MODPROBE_PLUGIN
|
||||
libplug_la_SOURCES += modprobe.c
|
||||
endif
|
||||
|
||||
if BUILD_NETLINK_PLUGIN
|
||||
libplug_la_SOURCES += netlink.c
|
||||
endif
|
||||
@@ -37,6 +41,10 @@ if BUILD_RTC_PLUGIN
|
||||
libplug_la_SOURCES += rtc.c
|
||||
endif
|
||||
|
||||
if BUILD_TTY_PLUGIN
|
||||
libplug_la_SOURCES += tty.c
|
||||
endif
|
||||
|
||||
if BUILD_URANDOM_PLUGIN
|
||||
libplug_la_SOURCES += urandom.c
|
||||
endif
|
||||
@@ -46,7 +54,7 @@ libplug_la_SOURCES += x11-common.c
|
||||
endif
|
||||
|
||||
else
|
||||
pkglib_LTLIBRARIES = bootmisc.la modprobe.la pidfile.la procps.la sys.la tty.la usr.la
|
||||
pkglib_LTLIBRARIES = bootmisc.la pidfile.la procps.la sys.la usr.la
|
||||
|
||||
if BUILD_ALSA_UTILS_PLUGIN
|
||||
pkglib_LTLIBRARIES += alsa-utils.la
|
||||
@@ -56,6 +64,10 @@ if BUILD_DBUS_PLUGIN
|
||||
pkglib_LTLIBRARIES += dbus.la
|
||||
endif
|
||||
|
||||
if BUILD_HOOK_SCRIPTS_PLUGIN
|
||||
pkglib_LTLIBRARIES += hook-scripts.la
|
||||
endif
|
||||
|
||||
if BUILD_HOTPLUG_PLUGIN
|
||||
pkglib_LTLIBRARIES += hotplug.la
|
||||
endif
|
||||
@@ -64,6 +76,10 @@ if BUILD_MODULES_LOAD_PLUGIN
|
||||
pkglib_LTLIBRARIES += modules-load.la
|
||||
endif
|
||||
|
||||
if BUILD_MODPROBE_PLUGIN
|
||||
pkglib_LTLIBRARIES += modprobe.la
|
||||
endif
|
||||
|
||||
if BUILD_NETLINK_PLUGIN
|
||||
pkglib_LTLIBRARIES += netlink.la
|
||||
endif
|
||||
@@ -76,6 +92,10 @@ if BUILD_RTC_PLUGIN
|
||||
pkglib_LTLIBRARIES += rtc.la
|
||||
endif
|
||||
|
||||
if BUILD_TTY_PLUGIN
|
||||
pkglib_LTLIBRARIES += tty.la
|
||||
endif
|
||||
|
||||
if BUILD_URANDOM_PLUGIN
|
||||
pkglib_LTLIBRARIES += urandom.la
|
||||
endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Save and restore ALSA sound settings using alsactl
|
||||
*
|
||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -21,7 +21,12 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <lite/lite.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
|
||||
+25
-9
@@ -1,6 +1,6 @@
|
||||
/* Setup necessary system files for, e.g. UTMP (tracking logins)
|
||||
*
|
||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -21,10 +21,18 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h" /* Generated by configure script */
|
||||
|
||||
#include <ftw.h>
|
||||
#ifdef HAVE_MNTENT_H
|
||||
#include <mntent.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <lite/lite.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "finit.h"
|
||||
@@ -35,10 +43,12 @@
|
||||
|
||||
static int is_tmpfs(char *path)
|
||||
{
|
||||
struct mntent mount;
|
||||
struct mntent *mnt;
|
||||
char buf[256];
|
||||
int tmpfs = 0;
|
||||
FILE *fp;
|
||||
char *dir;
|
||||
struct mntent *mnt;
|
||||
|
||||
/* If path is a symlink, check what it resolves to */
|
||||
dir = realpath(path, NULL);
|
||||
@@ -51,7 +61,7 @@ static int is_tmpfs(char *path)
|
||||
return 0; /* Dunno, maybe not */
|
||||
}
|
||||
|
||||
while ((mnt = getmntent(fp))) {
|
||||
while ((mnt = getmntent_r(fp, &mount, buf, sizeof(buf)))) {
|
||||
if (!strcmp(dir, mnt->mnt_dir))
|
||||
break;
|
||||
}
|
||||
@@ -100,6 +110,12 @@ static void clean(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
static void ln(const char *target, const char *linkpath)
|
||||
{
|
||||
if (symlink(target, linkpath) && errno != EEXIST)
|
||||
_pe("Failed creating %s -> %s symlink", target, linkpath);
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup standard FHS 2.3 structure in /var, and write runlevel to UTMP
|
||||
*/
|
||||
@@ -121,11 +137,11 @@ static void setup(void *arg)
|
||||
_d("System with new /run tmpfs ...");
|
||||
if (!fisdir("/run/lock"))
|
||||
makedir("/run/lock", 1777);
|
||||
symlink("/run/lock", "/var/lock");
|
||||
symlink("/dev/shm", "/run/shm");
|
||||
ln("/run/lock", "/var/lock");
|
||||
ln("/dev/shm", "/run/shm");
|
||||
|
||||
/* compat only, should really be set up by OS/dist */
|
||||
symlink("/run", "/var/run");
|
||||
ln("/run", "/var/run");
|
||||
} else {
|
||||
makedir("/var/lock", 1777);
|
||||
makedir("/var/run", 0755);
|
||||
@@ -179,7 +195,7 @@ static void setup(void *arg)
|
||||
makedir("/var/run/sshd", 01755); /* OpenSSH */
|
||||
|
||||
if (!fexist("/etc/mtab"))
|
||||
symlink("../proc/self/mounts", "/etc/mtab");
|
||||
ln("../proc/self/mounts", "/etc/mtab");
|
||||
|
||||
/* Void Linux has a uuidd that runs as uuid:uuid and needs /run/uuid */
|
||||
mksubsys("/var/run/uuidd", 0755, "uuidd", "uuidd");
|
||||
@@ -188,7 +204,7 @@ static void setup(void *arg)
|
||||
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");
|
||||
run("restorecon /var/run/sudo /var/run/sudo/ts", "restorecon");
|
||||
|
||||
umask(prev);
|
||||
}
|
||||
|
||||
+15
-5
@@ -1,6 +1,6 @@
|
||||
/* Setup and start system message bus, D-Bus
|
||||
*
|
||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -22,7 +22,11 @@
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <lite/lite.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
#include "finit.h"
|
||||
#include "config.h"
|
||||
@@ -35,7 +39,13 @@
|
||||
#define ARGS "--nofork --system --syslog-only"
|
||||
#define DESC "D-Bus message bus daemon"
|
||||
|
||||
#ifndef DAEMONUSER
|
||||
#define DAEMONUSER "messagebus"
|
||||
#endif
|
||||
|
||||
#ifndef DAEMONPIDFILE
|
||||
#define DAEMONPIDFILE "/var/run/dbus/pid"
|
||||
#endif
|
||||
|
||||
static void setup(void *arg)
|
||||
{
|
||||
@@ -61,11 +71,11 @@ static void setup(void *arg)
|
||||
run_interactive("dbus-uuidgen --ensure", "Creating machine UUID for D-Bus");
|
||||
|
||||
/* Clean up from any previous pre-bootstrap run */
|
||||
remove("/var/run/dbus/pid");
|
||||
remove(DAEMONPIDFILE);
|
||||
|
||||
/* Register service with Finit */
|
||||
snprintf(line, sizeof(line), "[S12345789] cgroup.system @%s:%s %s %s -- %s",
|
||||
DAEMONUSER, DAEMONUSER, cmd, ARGS, DESC);
|
||||
snprintf(line, sizeof(line), "[S12345789] cgroup.system pid:!%s @%s:%s %s %s -- %s",
|
||||
DAEMONPIDFILE, DAEMONUSER, DAEMONUSER, cmd, ARGS, DESC);
|
||||
if (service_register(SVC_TYPE_SERVICE, line, global_rlimit, NULL))
|
||||
_pe("Failed registering %s", DAEMON);
|
||||
free(cmd);
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/* Trigger scripts to run from finit's hooks
|
||||
*
|
||||
* Copyright (c) 2022 Tobias Waldekranz <tobias@waldekranz.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
#include "config.h"
|
||||
|
||||
#define CHOOSE(x, y) y
|
||||
static const char *hscript_paths[] = HOOK_TYPES;
|
||||
#undef CHOOSE
|
||||
|
||||
static void hscript_run_parts(hook_point_t hook)
|
||||
{
|
||||
char path[CMD_SIZE] = "";
|
||||
|
||||
strlcat(path, PLUGIN_HOOK_SCRIPTS_PATH, sizeof(path));
|
||||
strlcat(path, hscript_paths[hook] + 4, sizeof(path));
|
||||
|
||||
run_parts(path, NULL);
|
||||
}
|
||||
|
||||
static void hscript_banner(void *arg)
|
||||
{
|
||||
hscript_run_parts(HOOK_BANNER);
|
||||
}
|
||||
|
||||
static void hscript_rootfs_up(void *arg)
|
||||
{
|
||||
hscript_run_parts(HOOK_ROOTFS_UP);
|
||||
}
|
||||
|
||||
static void hscript_mount_error(void *arg)
|
||||
{
|
||||
hscript_run_parts(HOOK_MOUNT_ERROR);
|
||||
}
|
||||
|
||||
static void hscript_mount_post(void *arg)
|
||||
{
|
||||
hscript_run_parts(HOOK_MOUNT_POST);
|
||||
}
|
||||
|
||||
static void hscript_basefs_up(void *arg)
|
||||
{
|
||||
hscript_run_parts(HOOK_BASEFS_UP);
|
||||
}
|
||||
|
||||
static void hscript_network_up(void *arg)
|
||||
{
|
||||
hscript_run_parts(HOOK_NETWORK_UP);
|
||||
}
|
||||
|
||||
static void hscript_svc_up(void *arg)
|
||||
{
|
||||
hscript_run_parts(HOOK_SVC_UP);
|
||||
}
|
||||
|
||||
static void hscript_system_up(void *arg)
|
||||
{
|
||||
hscript_run_parts(HOOK_SYSTEM_UP);
|
||||
}
|
||||
|
||||
static void hscript_shutdown(void *arg)
|
||||
{
|
||||
hscript_run_parts(HOOK_SHUTDOWN);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_BANNER] = { .cb = hscript_banner },
|
||||
.hook[HOOK_ROOTFS_UP] = { .cb = hscript_rootfs_up },
|
||||
.hook[HOOK_MOUNT_ERROR] = { .cb = hscript_mount_error },
|
||||
.hook[HOOK_MOUNT_POST] = { .cb = hscript_mount_post },
|
||||
.hook[HOOK_BASEFS_UP] = { .cb = hscript_basefs_up },
|
||||
.hook[HOOK_NETWORK_UP] = { .cb = hscript_network_up },
|
||||
.hook[HOOK_SVC_UP] = { .cb = hscript_svc_up },
|
||||
.hook[HOOK_SYSTEM_UP] = { .cb = hscript_system_up },
|
||||
.hook[HOOK_SHUTDOWN] = { .cb = hscript_shutdown },
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* Heuristically find and initialize a suitable hotplug daemon
|
||||
*
|
||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2022 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
|
||||
|
||||
+7
-3
@@ -1,6 +1,6 @@
|
||||
/* Coldplug modules using modalias magic
|
||||
*
|
||||
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2021-2022 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -40,11 +40,15 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h> /* gettimeofday() */
|
||||
#include <sys/types.h>
|
||||
#include <lite/lite.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "util.h"
|
||||
#include "plugin.h"
|
||||
|
||||
struct module {
|
||||
|
||||
+108
-38
@@ -21,10 +21,37 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <lite/lite.h>
|
||||
/*
|
||||
* This plugin scans files in /etc/modules-load.d/, for each line in the
|
||||
* file it assumes the name of a kernel module, with optional arguments.
|
||||
* Each module is loaded when entering runlevel 2, 3, 4, or 5, using the
|
||||
* modprobe tool.
|
||||
*
|
||||
* Loading is done by inserting a `task` stanza in Finit, ensuring all
|
||||
* modules are loaded in parallel, with other modules and programs.
|
||||
* Each `task` stanza is by default given the name:modprobe.module and
|
||||
* indexed with `:ID`, starting with 1.
|
||||
*
|
||||
* Indexing can be disabled per file in /etc/modules-load.d/, anywwhere
|
||||
* in a file, by putting the keyword `noindex` on a line of its own. A
|
||||
* noindex command can appear anywhere in the file, and up to the point
|
||||
* it is read, tasks will be indexed with an incrementing `:ID`. When
|
||||
* `noindex` is read indexing is disabled and all subseequent tasks will
|
||||
* not have any `:ID` at all.
|
||||
*
|
||||
* Please note, the :ID is there for your benefit, it ensures that tasks
|
||||
* in Finit are unique. If you have two tasks with the same name and ID
|
||||
* (or no ID), the last one read replaces any preceeding one!
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
@@ -36,51 +63,94 @@
|
||||
#define MODULES_LOAD_PATH "/etc/modules-load.d"
|
||||
#endif
|
||||
#define SERVICE_LINE \
|
||||
"cgroup.init :%d name:modprobe.%s [2345] /sbin/modprobe %s %s -- Kernel module: %s"
|
||||
"cgroup.init name:modprobe.%s :%d [2345] /sbin/modprobe %s %s -- Kernel module: %s"
|
||||
#define SERVICE_LINE_NOINDEX \
|
||||
"cgroup.init name:modprobe.%s [2345] /sbin/modprobe %s %s -- Kernel module: %s"
|
||||
|
||||
static int load_file(const char *file, int index)
|
||||
{
|
||||
char module_path[PATH_MAX];
|
||||
char line[256];
|
||||
int num = 0;
|
||||
FILE *fp;
|
||||
|
||||
strlcpy(module_path, MODULES_LOAD_PATH "/", sizeof(module_path));
|
||||
strlcat(module_path, file, sizeof(module_path));
|
||||
|
||||
fp = fopen(module_path, "r");
|
||||
if (!fp)
|
||||
return 0;
|
||||
|
||||
while (fgets(line, sizeof(line), fp)) {
|
||||
char cmd[CMD_SIZE], *mod, *args;
|
||||
|
||||
chomp(line);
|
||||
|
||||
mod = strip_line(line);
|
||||
if (!mod[0])
|
||||
continue;
|
||||
|
||||
if (mod[0] == '#' || mod[0] == ';')
|
||||
continue;
|
||||
|
||||
if (!strcmp(mod, "set noindex")) {
|
||||
index = 0;
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(mod, "set index", 9)) {
|
||||
mod += 9;
|
||||
args = strchr(mod, '=');
|
||||
if (args) /* optional */
|
||||
mod = args + 1;
|
||||
index = atoi(mod);
|
||||
continue;
|
||||
}
|
||||
|
||||
mod = strtok_r(mod, " ", &args);
|
||||
if (!mod)
|
||||
continue;
|
||||
|
||||
if (!index)
|
||||
snprintf(cmd, sizeof(cmd), SERVICE_LINE_NOINDEX, mod, mod, args, mod);
|
||||
else
|
||||
snprintf(cmd, sizeof(cmd), SERVICE_LINE, mod, index++, mod, args, mod);
|
||||
|
||||
service_register(SVC_TYPE_TASK, cmd, global_rlimit, NULL);
|
||||
num++;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
/* XXX: check here for .conf only? */
|
||||
static int module_filter(const struct dirent *d)
|
||||
{
|
||||
if (d->d_type == DT_DIR)
|
||||
return 0;
|
||||
if (d->d_name[0] == '.')
|
||||
return 0; /* skip dot files */
|
||||
if (d->d_name[strlen(d->d_name) - 1] == '~')
|
||||
return 0; /* skip backup files */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void load(void *arg)
|
||||
{
|
||||
FILE *fp;
|
||||
DIR *dirp;
|
||||
struct dirent *direntp;
|
||||
char line[256];
|
||||
struct dirent **dentry;
|
||||
int index = 1;
|
||||
int i, num;
|
||||
|
||||
_d("Scanning " MODULES_LOAD_PATH " for config files ...");
|
||||
|
||||
dirp = opendir(MODULES_LOAD_PATH);
|
||||
if (!dirp) return;
|
||||
|
||||
while ((direntp = readdir(dirp)))
|
||||
{
|
||||
char module_path[PATH_MAX];
|
||||
strlcpy(module_path, MODULES_LOAD_PATH "/", sizeof(module_path));
|
||||
strlcat(module_path, direntp->d_name, sizeof(module_path));
|
||||
|
||||
fp = fopen(module_path, "r");
|
||||
if (!fp) continue;
|
||||
|
||||
while (fgets(line, sizeof(line), fp)) {
|
||||
char cmd[CMD_SIZE], *mod, *args;
|
||||
|
||||
mod = strip_line(line);
|
||||
if (!*mod) continue;
|
||||
|
||||
mod = chomp(mod);
|
||||
if (!mod || !*mod) continue;
|
||||
|
||||
mod = strtok_r(mod, " ", &args);
|
||||
|
||||
snprintf(cmd, sizeof(cmd), SERVICE_LINE, index, mod, mod, args, mod);
|
||||
service_register(SVC_TYPE_TASK, cmd, global_rlimit, NULL);
|
||||
|
||||
index++;
|
||||
num = scandir(MODULES_LOAD_PATH, &dentry, module_filter, alphasort);
|
||||
if (num > 0) {
|
||||
for (i = 0; i < num; i++) {
|
||||
index += load_file(dentry[i]->d_name, index);
|
||||
free(dentry[i]);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
free(dentry);
|
||||
}
|
||||
|
||||
closedir(dirp);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
|
||||
+11
-9
@@ -1,7 +1,8 @@
|
||||
|
||||
/* Netlink plugin for IFUP/IFDN and GW events
|
||||
*
|
||||
* Copyright (C) 2009-2011 Mårten Wikström <marten.wikstrom@keystream.se>
|
||||
* Copyright (C) 2009-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (C) 2009-2022 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@@ -252,18 +253,18 @@ static int nl_parse(int sd)
|
||||
return -1;
|
||||
}
|
||||
|
||||
_d("recv %lld bytes", len);
|
||||
// _d("recv %zd bytes", len);
|
||||
l = (size_t)len;
|
||||
for (nh = (struct nlmsghdr *)nl_buf; NLMSG_OK(nh, l); nh = NLMSG_NEXT(nh, l)) {
|
||||
struct nlmsgerr *nle;
|
||||
|
||||
switch (nh->nlmsg_type) {
|
||||
case NLMSG_DONE:
|
||||
_d("Done with netlink messages.");
|
||||
// _d("Done with netlink messages.");
|
||||
return 0;
|
||||
|
||||
case NLMSG_ERROR:
|
||||
_d("Kernel netlink comm. error.");
|
||||
// _d("Kernel netlink comm. error.");
|
||||
nle = NLMSG_DATA(nh);
|
||||
if (nle) {
|
||||
errno = -nle->error;
|
||||
@@ -273,13 +274,13 @@ static int nl_parse(int sd)
|
||||
|
||||
case RTM_NEWROUTE:
|
||||
case RTM_DELROUTE:
|
||||
_d("Netlink route ...");
|
||||
// _d("Netlink route ...");
|
||||
nl_route(nh, len);
|
||||
break;
|
||||
|
||||
case RTM_NEWLINK:
|
||||
case RTM_DELLINK:
|
||||
_d("Netlink link ...");
|
||||
// _d("Netlink link ...");
|
||||
nl_link(nh, len);
|
||||
break;
|
||||
|
||||
@@ -303,14 +304,14 @@ static int nl_request(int sd, unsigned int seq, int type)
|
||||
|
||||
switch (type) {
|
||||
case RTM_GETROUTE:
|
||||
_d("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");
|
||||
// _d("RTM_GETLINK");
|
||||
nlr->ifi.ifi_family = AF_UNSPEC;
|
||||
nlr->ifi.ifi_change = 0xFFFFFFFF;
|
||||
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
||||
@@ -355,7 +356,7 @@ static void nl_resync(int all)
|
||||
|
||||
if (all) {
|
||||
_d("============================ RESYNC =================================");
|
||||
/* this doesn't update condtions, and thus does not stop services */
|
||||
/* this doesn't update conditions, and thus does not stop services */
|
||||
cond_deassert("net/");
|
||||
|
||||
nl_resync_ifaces(sd, seq++);
|
||||
@@ -449,6 +450,7 @@ PLUGIN_INIT(plugin_init)
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
close(plugin.io.fd);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+13
-5
@@ -1,7 +1,7 @@
|
||||
/* Simple pidfile event monitor for the Finit condition engine
|
||||
*
|
||||
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
|
||||
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2016-2022 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
|
||||
@@ -84,8 +84,10 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
|
||||
mkcond(svc, cond, sizeof(cond));
|
||||
if (mask & (IN_CLOSE_WRITE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) {
|
||||
svc_started(svc);
|
||||
if (!svc_has_pidfile(svc))
|
||||
if (!svc_has_pidfile(svc)) {
|
||||
_d("Setting %s PID file to %s", svc->name, fn);
|
||||
pid_file_set(svc, fn, 1);
|
||||
}
|
||||
|
||||
if (svc_is_forking(svc)) {
|
||||
pid_t pid;
|
||||
@@ -96,10 +98,16 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Service is not crashing, let's tell state machine! */
|
||||
service_forked(svc);
|
||||
|
||||
if (pid != svc->pid) {
|
||||
_d("Forking service %s changed PID from %d to %d",
|
||||
svc->cmd, svc->pid, pid);
|
||||
_d("Forking service %s (cmd %s) changed PID from %d to %d",
|
||||
svc_ident(svc, NULL, 0), svc->cmd, svc->pid, pid);
|
||||
svc->pid = pid;
|
||||
|
||||
/* Complement log in service.c for non-forking services */
|
||||
logit(LOG_CONSOLE | LOG_NOTICE, "Started %s[%d]", svc_ident(svc, NULL, 0), pid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,8 +311,8 @@ PLUGIN_INIT(plugin_init)
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
iwatch_exit(&iw_pidfile);
|
||||
plugin_unregister(&plugin);
|
||||
iwatch_exit(&iw_pidfile);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+12
-6
@@ -1,6 +1,6 @@
|
||||
/* Set kernel variables from /etc/sysctl.conf et al
|
||||
*
|
||||
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -22,7 +22,11 @@
|
||||
*/
|
||||
|
||||
#include <glob.h>
|
||||
#include <lite/lite.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
@@ -30,9 +34,7 @@
|
||||
|
||||
static void setup(void *arg)
|
||||
{
|
||||
size_t i;
|
||||
glob_t gl;
|
||||
char buf[160];
|
||||
|
||||
if (rescue) {
|
||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||
@@ -47,9 +49,13 @@ static void setup(void *arg)
|
||||
glob("/mnt/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||
glob("/etc/sysctl.conf", GLOB_APPEND, NULL, &gl);
|
||||
if (gl.gl_pathc > 0) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < gl.gl_pathc; i++) {
|
||||
snprintf(buf, sizeof(buf), "/sbin/sysctl -e -p %s >/dev/null", gl.gl_pathv[i]);
|
||||
run(buf);
|
||||
char cmd[160];
|
||||
|
||||
snprintf(cmd, sizeof(cmd), "/sbin/sysctl -e -p %s >/dev/null", gl.gl_pathv[i]);
|
||||
run(cmd, "sysctl");
|
||||
}
|
||||
globfree(&gl);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Setup necessary files for resolvconf
|
||||
*
|
||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -21,7 +21,11 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <lite/lite.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
|
||||
+17
-3
@@ -1,6 +1,6 @@
|
||||
/* Save and restore RTC using hwclock
|
||||
*
|
||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -24,7 +24,11 @@
|
||||
#include <time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <lite/lite.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
@@ -152,8 +156,18 @@ static void rtc_restore(void *arg)
|
||||
logit(LOG_ERR, "RTC has no previously saved (valid) time.");
|
||||
else
|
||||
logit(LOG_ERR, "RTC error code %d: %s", errno, strerror(errno));
|
||||
|
||||
/* Been here already? */
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
/* Attempt to set RTC to a sane value ... */
|
||||
tv.tv_sec = RTC_TIMESTAMP_BEGIN_2000;
|
||||
if (!gmtime_r(&tv.tv_sec, &tm))
|
||||
goto out;
|
||||
|
||||
logit(LOG_NOTICE, "Resetting RTC to kernel default, 2000-01-01 00:00.");
|
||||
rc = 2;
|
||||
goto out;
|
||||
}
|
||||
|
||||
print_desc(NULL, "Restoring system clock (UTC) from RTC");
|
||||
|
||||
+19
-5
@@ -1,6 +1,6 @@
|
||||
/* System condtion event monitor for the Finit condition engine
|
||||
/* System condition event monitor for the Finit condition engine
|
||||
*
|
||||
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2021-2022 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
|
||||
@@ -41,17 +41,31 @@ 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;
|
||||
|
||||
cond = strstr(name, COND_BASE);
|
||||
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);
|
||||
cond_update(cond);
|
||||
if (!cond_update(cond))
|
||||
unlink(path);
|
||||
}
|
||||
|
||||
/* synthesize events in case of new run dirs */
|
||||
@@ -183,8 +197,8 @@ PLUGIN_INIT(plugin_init)
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
iwatch_exit(&iw_sys);
|
||||
plugin_unregister(&plugin);
|
||||
iwatch_exit(&iw_sys);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+7
-4
@@ -1,7 +1,7 @@
|
||||
/* Optional TTY Watcher, used to catch new TTYs that are discovered, e.g., USB
|
||||
*
|
||||
* Copyright (c) 2013 Mattias Walström <lazzer@gmail.com>
|
||||
* Copyright (c) 2013-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2013-2022 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -27,7 +27,11 @@
|
||||
#include <unistd.h> /* read() */
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/stat.h>
|
||||
#include <lite/lite.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
@@ -112,10 +116,9 @@ PLUGIN_INIT(plugin_init)
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
if (plugin.io.fd)
|
||||
close(plugin.io.fd);
|
||||
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+71
-4
@@ -1,6 +1,6 @@
|
||||
/* Setup and save random seed at boot/shutdown
|
||||
*
|
||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -22,19 +22,34 @@
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h> /* gettimeofday() */
|
||||
#include <sys/types.h>
|
||||
#include <lite/lite.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
#include <linux/random.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
|
||||
#ifndef RANDOM_BYTES
|
||||
#define RANDOM_BYTES (32*1024)
|
||||
#endif
|
||||
|
||||
static void setup(void *arg)
|
||||
{
|
||||
#ifdef RANDOMSEED
|
||||
struct rand_pool_info *rpi;
|
||||
ssize_t len = 0;
|
||||
int rc = -1;
|
||||
int fd, err;
|
||||
|
||||
if (rescue) {
|
||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||
return;
|
||||
@@ -67,7 +82,59 @@ static void setup(void *arg)
|
||||
}
|
||||
|
||||
print_desc("Initializing random number generator", NULL);
|
||||
print_result(512 != copyfile(RANDOMSEED, "/dev/urandom", 0, 0));
|
||||
|
||||
/*
|
||||
* Simply copying our saved entropy to /dev/urandom doesn't
|
||||
* increment the kernel "entropy count", instead we must use
|
||||
* the ioctl below.
|
||||
*/
|
||||
fd = open(RANDOMSEED, O_RDONLY);
|
||||
if (fd < 0)
|
||||
goto fallback;
|
||||
|
||||
rpi = malloc(sizeof(*rpi) + RANDOM_BYTES);
|
||||
if (!rpi) {
|
||||
close(fd);
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
do {
|
||||
ssize_t num;
|
||||
|
||||
num = read(fd, &rpi->buf[len], RANDOM_BYTES - len);
|
||||
if (num <= 0) {
|
||||
if (num == -1 && errno == EINTR)
|
||||
continue;
|
||||
if (len > 0)
|
||||
break;
|
||||
|
||||
close(fd);
|
||||
free(rpi);
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
len += num;
|
||||
} while (len < RANDOM_BYTES);
|
||||
close(fd);
|
||||
|
||||
fd = open("/dev/urandom", O_WRONLY);
|
||||
if (fd < 0) {
|
||||
free(rpi);
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
rpi->buf_size = len;
|
||||
rpi->entropy_count = len * 8;
|
||||
rc = ioctl(fd, RNDADDENTROPY, rpi);
|
||||
err = errno;
|
||||
close(fd);
|
||||
free(rpi);
|
||||
if (rc < 0)
|
||||
logit(LOG_ERR, "Failed adding entropy to kernel random pool: %s", strerror(err));
|
||||
print_result(rc < 0);
|
||||
return;
|
||||
fallback:
|
||||
print_result(512 > copyfile(RANDOMSEED, "/dev/urandom", 0, 0));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -84,7 +151,7 @@ static void save(void *arg)
|
||||
prev = umask(077);
|
||||
|
||||
print_desc("Saving random seed", NULL);
|
||||
print_result(512 != copyfile("/dev/urandom", RANDOMSEED, 512, 0));
|
||||
print_result(RANDOM_BYTES != copyfile("/dev/urandom", RANDOMSEED, RANDOM_BYTES, 0));
|
||||
|
||||
umask(prev);
|
||||
#endif
|
||||
|
||||
+5
-3
@@ -1,6 +1,6 @@
|
||||
/* User-defined condtion event monitor for the Finit condition engine
|
||||
/* User-defined condition event monitor for the Finit condition engine
|
||||
*
|
||||
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2021-2022 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
|
||||
@@ -97,6 +97,8 @@ static void usr_init(void *arg)
|
||||
|
||||
if (iwatch_add(&iw_usr, path, IN_ONLYDIR))
|
||||
iwatch_exit(&iw_usr);
|
||||
|
||||
free(path);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
@@ -121,8 +123,8 @@ PLUGIN_INIT(plugin_init)
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
iwatch_exit(&iw_usr);
|
||||
plugin_unregister(&plugin);
|
||||
iwatch_exit(&iw_usr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Console setup (for X)
|
||||
*
|
||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -24,7 +24,11 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <lite/lite.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
@@ -54,7 +58,7 @@ static void setup(void *arg)
|
||||
if ((fd = open("/var/run/console/console.lock", O_CREAT|O_WRONLY|O_TRUNC, 0644)) >= 0) {
|
||||
write(fd, username, strlen(username));
|
||||
close(fd);
|
||||
run("pam_console_apply");
|
||||
run("pam_console_apply", "pam-console");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -62,7 +66,7 @@ static void setup(void *arg)
|
||||
makedir("/tmp/.ICE-unix", 01777);
|
||||
|
||||
if (whichp("restorecon"))
|
||||
run("restorecon /tmp/.ICE-unix /tmp/.X11-unix");
|
||||
run("restorecon /tmp/.ICE-unix /tmp/.X11-unix", "restorecon");
|
||||
|
||||
umask(prev);
|
||||
}
|
||||
|
||||
+4
-1
@@ -8,7 +8,10 @@ AM_LDFLAGS = -export-dynamic
|
||||
endif
|
||||
|
||||
sbin_PROGRAMS = finit initctl
|
||||
pkglibexec_PROGRAMS = getty logit sulogin
|
||||
pkglibexec_PROGRAMS = getty logit
|
||||
if SULOGIN
|
||||
pkglibexec_PROGRAMS += sulogin
|
||||
endif
|
||||
if KEVENTD
|
||||
pkglibexec_PROGRAMS += keventd
|
||||
endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* External client API, using UNIX domain socket.
|
||||
*
|
||||
* Copyright (c) 2015-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2015-2022 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -21,6 +21,8 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h" /* Generated by configure script */
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
@@ -29,10 +31,13 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <lite/lite.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
#include <uev/uev.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "finit.h"
|
||||
#include "cond.h"
|
||||
#include "conf.h"
|
||||
@@ -47,12 +52,12 @@
|
||||
extern svc_t *wdog;
|
||||
static uev_t api_watcher;
|
||||
|
||||
static int call(int (*action)(svc_t *), char *buf, size_t len)
|
||||
static int call(int (*action)(svc_t *, void *), char *buf, size_t len)
|
||||
{
|
||||
return svc_parse_jobstr(buf, len, action, NULL);
|
||||
return svc_parse_jobstr(buf, len, NULL, action, NULL);
|
||||
}
|
||||
|
||||
static int stop(svc_t *svc)
|
||||
static int stop(svc_t *svc, void *user_data)
|
||||
{
|
||||
if (!svc)
|
||||
return 1;
|
||||
@@ -63,7 +68,7 @@ static int stop(svc_t *svc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int start(svc_t *svc)
|
||||
static int start(svc_t *svc, void *user_data)
|
||||
{
|
||||
if (!svc)
|
||||
return 1;
|
||||
@@ -79,7 +84,7 @@ static int start(svc_t *svc)
|
||||
* 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, void *user_data)
|
||||
{
|
||||
if (!svc)
|
||||
return 1;
|
||||
@@ -91,7 +96,7 @@ static int restart(svc_t *svc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reload(svc_t *svc)
|
||||
static int reload(svc_t *svc, void *user_data)
|
||||
{
|
||||
if (!svc)
|
||||
return 1;
|
||||
@@ -110,8 +115,28 @@ 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_reload (char *buf, size_t len) { return call(reload, buf, len); }
|
||||
|
||||
static int do_signal_svc(svc_t *svc, void *user_data)
|
||||
{
|
||||
int signo;
|
||||
|
||||
if (!svc || !user_data || !svc_is_running(svc))
|
||||
return 1;
|
||||
|
||||
signo = *(int *)user_data;
|
||||
return !!kill(svc->pid, signo);
|
||||
}
|
||||
|
||||
static int do_signal(char *buf, size_t len, int sig)
|
||||
{
|
||||
/* Sanity check: do we know this signal? */
|
||||
if (!*sig2str(sig))
|
||||
return 1;
|
||||
|
||||
return svc_parse_jobstr(buf, len, &sig, do_signal_svc, NULL);
|
||||
}
|
||||
|
||||
static char query_buf[368];
|
||||
static int missing(char *job, char *id)
|
||||
static int missing(char *job, char *id, void *user_data)
|
||||
{
|
||||
char buf[20];
|
||||
|
||||
@@ -129,7 +154,7 @@ static int missing(char *job, char *id)
|
||||
static int do_query(char *buf, size_t len)
|
||||
{
|
||||
query_buf[0] = 0;
|
||||
if (svc_parse_jobstr(buf, len, NULL, missing)) {
|
||||
if (svc_parse_jobstr(buf, len, NULL, NULL, missing)) {
|
||||
memcpy(buf, query_buf, len);
|
||||
return 1;
|
||||
}
|
||||
@@ -173,7 +198,7 @@ static svc_t *do_find(char *buf, size_t len)
|
||||
if (!id)
|
||||
return svc_named_iterator(&iter, 1, input);
|
||||
|
||||
return svc_find_by_nameid(input, id);
|
||||
return svc_find(input, id);
|
||||
}
|
||||
|
||||
static svc_t *do_find_byc(char *buf, size_t len)
|
||||
@@ -226,10 +251,10 @@ static int do_reboot(int cmd, char *buf, size_t len)
|
||||
case INIT_CMD_SUSPEND:
|
||||
_d("suspend");
|
||||
sync();
|
||||
rc = reboot(RB_SW_SUSPEND);
|
||||
rc = suspend();
|
||||
if (rc) {
|
||||
if (errno == EINVAL)
|
||||
snprintf(buf, len, "Kernel does not support suspend.");
|
||||
snprintf(buf, len, "Kernel does not support suspend to RAM.");
|
||||
else
|
||||
snprintf(buf, len, "Failed: %s", strerror(errno));
|
||||
}
|
||||
@@ -387,7 +412,7 @@ static void api_cb(uev_t *w, void *arg, int events)
|
||||
break;
|
||||
}
|
||||
|
||||
_e("Request to hand-over wdog ... to PID %d", rq.runlevel);
|
||||
_d("Request to hand-over wdog ... to PID %d", rq.runlevel);
|
||||
svc = svc_find_by_pid(rq.runlevel);
|
||||
if (!svc) {
|
||||
logit(LOG_ERR, "Cannot find PID %d, not registered.", rq.runlevel);
|
||||
@@ -403,7 +428,7 @@ static void api_cb(uev_t *w, void *arg, int events)
|
||||
|
||||
if (wdog->protect) {
|
||||
logit(LOG_NOTICE, "Stopping and deleting built-in watchdog.");
|
||||
stop(wdog);
|
||||
stop(wdog, NULL);
|
||||
svc_del(wdog);
|
||||
}
|
||||
}
|
||||
@@ -413,7 +438,7 @@ static void api_cb(uev_t *w, void *arg, int events)
|
||||
case INIT_CMD_SVC_ITER:
|
||||
// _d("svc iter, first: %d", rq.runlevel);
|
||||
/*
|
||||
* XXX: This severly limits the number of
|
||||
* XXX: This severely limits the number of
|
||||
* simultaneous client connections, but will
|
||||
* have to do for now.
|
||||
*/
|
||||
@@ -439,6 +464,13 @@ static void api_cb(uev_t *w, void *arg, int events)
|
||||
send_svc(sd, do_find_byc(rq.data, sizeof(rq.data)));
|
||||
goto leave;
|
||||
|
||||
case INIT_CMD_SIGNAL:
|
||||
/* runlevel is reused for signal */
|
||||
_d("svc signal %d: %s", rq.runlevel, rq.data);
|
||||
strterm(rq.data, sizeof(rq.data));
|
||||
result = do_signal(rq.data, sizeof(rq.data), rq.runlevel);
|
||||
break;
|
||||
|
||||
default:
|
||||
_d("Unsupported cmd: %d", rq.cmd);
|
||||
break;
|
||||
@@ -466,12 +498,13 @@ error:
|
||||
|
||||
int api_init(uev_ctx_t *ctx)
|
||||
{
|
||||
int sd;
|
||||
mode_t oldmask;
|
||||
struct sockaddr_un sun = {
|
||||
.sun_family = AF_UNIX,
|
||||
.sun_path = INIT_SOCKET,
|
||||
};
|
||||
mode_t oldmask;
|
||||
int uid, gid;
|
||||
int sd;
|
||||
|
||||
_d("Setting up external API socket ...");
|
||||
sd = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
|
||||
@@ -480,20 +513,26 @@ int api_init(uev_ctx_t *ctx)
|
||||
return 1;
|
||||
}
|
||||
|
||||
uid = geteuid();
|
||||
gid = getgroup(DEFGROUP);
|
||||
|
||||
erase(INIT_SOCKET);
|
||||
oldmask = umask(0077);
|
||||
oldmask = umask(0117);
|
||||
if (-1 == bind(sd, (struct sockaddr*)&sun, sizeof(sun)))
|
||||
goto error;
|
||||
|
||||
if (-1 == listen(sd, 10))
|
||||
goto error;
|
||||
|
||||
if (chown(INIT_SOCKET, uid, gid))
|
||||
_pe("Failed setting group %s on %s", DEFGROUP, INIT_SOCKET);
|
||||
|
||||
umask(oldmask);
|
||||
if (!uev_io_init(ctx, &api_watcher, api_cb, NULL, sd, UEV_READ))
|
||||
return 0;
|
||||
|
||||
error:
|
||||
_pe("Failed intializing API socket");
|
||||
_pe("Failed initializing API socket");
|
||||
umask(oldmask);
|
||||
close(sd);
|
||||
return 1;
|
||||
|
||||
+68
-16
@@ -1,6 +1,6 @@
|
||||
/* Finit control group support functions
|
||||
*
|
||||
* Copyright (c) 2019-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2019-2022 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -24,8 +24,13 @@
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <lite/lite.h>
|
||||
#include <lite/queue.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
# include <libite/queue.h> /* BSD sys/queue.h API */
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
# include <lite/queue.h> /* BSD sys/queue.h API */
|
||||
#endif
|
||||
#include <sys/mount.h>
|
||||
#include <sys/sysinfo.h> /* get_nprocs_conf() */
|
||||
|
||||
@@ -42,7 +47,7 @@ struct cg {
|
||||
char *cfg; /* kernel settings */
|
||||
|
||||
int active; /* for mark & sweep */
|
||||
int protected; /* for init/, user/, & system/ */
|
||||
int is_protected; /* for init/, user/, & system/ */
|
||||
};
|
||||
|
||||
static TAILQ_HEAD(, cg) cgroups = TAILQ_HEAD_INITIALIZER(cgroups);
|
||||
@@ -51,6 +56,7 @@ static char controllers[256];
|
||||
|
||||
static struct iwatch iw_cgroup;
|
||||
static uev_t cgw;
|
||||
static int avail;
|
||||
|
||||
|
||||
static void cgset(const char *path, char *ctrl, char *prop)
|
||||
@@ -159,6 +165,9 @@ static int cgroup_leaf_init(char *group, char *name, int pid, const char *cfg)
|
||||
|
||||
int cgroup_user(char *name, int pid)
|
||||
{
|
||||
if (!avail)
|
||||
return 0;
|
||||
|
||||
return cgroup_leaf_init("user", name, pid, NULL);
|
||||
}
|
||||
|
||||
@@ -166,6 +175,9 @@ int cgroup_service(char *name, int pid, struct cgroup *cg)
|
||||
{
|
||||
char *group = "system";
|
||||
|
||||
if (!avail)
|
||||
return 0;
|
||||
|
||||
if (cg && cg->name[0]) {
|
||||
char path[256];
|
||||
|
||||
@@ -302,8 +314,11 @@ void cgroup_mark_all(void)
|
||||
{
|
||||
struct cg *cg;
|
||||
|
||||
if (!avail)
|
||||
return;
|
||||
|
||||
TAILQ_FOREACH(cg, &cgroups, link) {
|
||||
if (cg->protected)
|
||||
if (cg->is_protected)
|
||||
continue;
|
||||
|
||||
cg->active = 0;
|
||||
@@ -318,6 +333,9 @@ void cgroup_cleanup(void)
|
||||
struct cg *cg, *tmp;
|
||||
char path[256];
|
||||
|
||||
if (!avail)
|
||||
return;
|
||||
|
||||
TAILQ_FOREACH_SAFE(cg, &cgroups, link, tmp) {
|
||||
if (cg->active)
|
||||
continue;
|
||||
@@ -330,10 +348,13 @@ void cgroup_cleanup(void)
|
||||
/*
|
||||
* Add, or update, settings for top-level cgroup
|
||||
*/
|
||||
int cgroup_add(char *name, char *cfg, int protected)
|
||||
int cgroup_add(char *name, char *cfg, int is_protected)
|
||||
{
|
||||
struct cg *cg;
|
||||
|
||||
if (!avail)
|
||||
return 0;
|
||||
|
||||
if (!name)
|
||||
return -1;
|
||||
if (!cfg)
|
||||
@@ -364,7 +385,7 @@ int cgroup_add(char *name, char *cfg, int protected)
|
||||
free(cg);
|
||||
return -1;
|
||||
}
|
||||
cg->protected = protected;
|
||||
cg->is_protected = is_protected;
|
||||
cg->active = 1;
|
||||
|
||||
return 0;
|
||||
@@ -378,6 +399,9 @@ int cgroup_del(char *dir)
|
||||
struct cg *cg;
|
||||
char path[256];
|
||||
|
||||
if (!avail)
|
||||
return 0;
|
||||
|
||||
TAILQ_FOREACH(cg, &cgroups, link) {
|
||||
snprintf(path, sizeof(path), FINIT_CGPATH "/%s", cg->name);
|
||||
if (strcmp(path, dir))
|
||||
@@ -409,6 +433,9 @@ void cgroup_config(void)
|
||||
{
|
||||
struct cg *cg;
|
||||
|
||||
if (!avail)
|
||||
return;
|
||||
|
||||
TAILQ_FOREACH(cg, &cgroups, link) {
|
||||
char path[256];
|
||||
int leaf = 0;
|
||||
@@ -437,14 +464,24 @@ void cgroup_init(uev_ctx_t *ctx)
|
||||
int fd;
|
||||
|
||||
if (mount("none", FINIT_CGPATH, "cgroup2", opts, NULL)) {
|
||||
_pe("Failed mounting cgroup v2");
|
||||
if (errno == ENOENT)
|
||||
logit(LOG_INFO, "Kernel does not support cgroups v2, disabling.");
|
||||
else if (errno == EPERM) /* Probably inside an unpriviliged container */
|
||||
logit(LOG_INFO, "Not allowed to mount cgroups v2, disabling.");
|
||||
else
|
||||
_pe("Failed mounting cgroup v2");
|
||||
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");
|
||||
abort:
|
||||
umount(FINIT_CGPATH);
|
||||
avail = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -460,9 +497,26 @@ void cgroup_init(uev_ctx_t *ctx)
|
||||
|
||||
fclose(fp);
|
||||
|
||||
/* Check for cpu controller, abort if missing */
|
||||
if (!strstr(controllers, "+cpu")) {
|
||||
logit(LOG_NOTICE, "Missing CPU controller, disabling cgroup support.");
|
||||
goto abort;
|
||||
}
|
||||
|
||||
/* Enable all controllers */
|
||||
if (fnwrite(controllers, FINIT_CGPATH "/cgroup.subtree_control"))
|
||||
if (fnwrite(controllers, FINIT_CGPATH "/cgroup.subtree_control")) {
|
||||
_pe("Failed enabling %s for %s", controllers, FINIT_CGPATH "/cgroup.subtree_control");
|
||||
goto abort;
|
||||
}
|
||||
|
||||
/* 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");
|
||||
iwatch_exit(&iw_cgroup);
|
||||
close(fd);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
/* Default (protected) groups, PID 1, services, and user/login processes */
|
||||
cgroup_add("init", "cpu.weight:100", 1);
|
||||
@@ -471,14 +525,12 @@ void cgroup_init(uev_ctx_t *ctx)
|
||||
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");
|
||||
if (fnwrite("1", FINIT_CGPATH "/init/cgroup.procs")) {
|
||||
_pe("Failed moving PID 1 to cgroup %s", FINIT_CGPATH "/init");
|
||||
uev_io_stop(&cgw);
|
||||
iwatch_exit(&iw_cgroup);
|
||||
close(fd);
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
/* Finit control group support functions
|
||||
*
|
||||
* Copyright (c) 2019-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2019-2022 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
|
||||
@@ -34,7 +34,7 @@ struct cgroup {
|
||||
void cgroup_mark_all(void);
|
||||
void cgroup_cleanup (void);
|
||||
|
||||
int cgroup_add (char *name, char *cfg, int protected);
|
||||
int cgroup_add (char *name, char *cfg, int is_protected);
|
||||
int cgroup_del (char *dir);
|
||||
void cgroup_config (void);
|
||||
|
||||
|
||||
+19
-10
@@ -1,6 +1,6 @@
|
||||
/* New client tool, replaces old /dev/initctl API and telinit tool
|
||||
*
|
||||
* Copyright (c) 2019-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2019-2022 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
|
||||
@@ -23,14 +23,17 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <err.h>
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <search.h>
|
||||
#include <inttypes.h>
|
||||
#include <lite/lite.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
#include <sys/sysinfo.h> /* sysinfo() */
|
||||
|
||||
#include "cgutil.h"
|
||||
@@ -49,6 +52,10 @@ uint64_t total_ram; /* From sysinfo() */
|
||||
struct cg dummy; /* empty result "NULL" */
|
||||
struct cg *list;
|
||||
|
||||
int cgroup_avail(void)
|
||||
{
|
||||
return fismnt(FINIT_CGPATH);
|
||||
}
|
||||
|
||||
char *pid_cmdline(int pid, char *buf, size_t len)
|
||||
{
|
||||
@@ -236,7 +243,7 @@ static float cgroup_cpuload(struct cg *cg)
|
||||
snprintf(fn, sizeof(fn), "%s/cpu.stat", cg->cg_path);
|
||||
fp = fopen(fn, "r");
|
||||
if (!fp)
|
||||
err(1, "Cannot open %s", fn);
|
||||
ERR(72, "Cannot open %s", fn);
|
||||
|
||||
while (fgets(buf, sizeof(buf), fp)) {
|
||||
uint64_t curr;
|
||||
@@ -272,13 +279,13 @@ static struct cg *append(char *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);
|
||||
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");
|
||||
ERR(71, "failed allocating struct cg");
|
||||
|
||||
cg->cg_path = strdup(path);
|
||||
if (list)
|
||||
@@ -288,7 +295,7 @@ static struct cg *append(char *path)
|
||||
item.key = cg->cg_path;
|
||||
item.data = cg;
|
||||
if (!hsearch(item, ENTER))
|
||||
err(1, "failed adding to hash table");
|
||||
ERR(70, "failed adding to hash table");
|
||||
|
||||
return cg;
|
||||
}
|
||||
@@ -426,7 +433,6 @@ int cgroup_tree(char *path, char *pfx, int mode, int pos)
|
||||
pid_comm(pid, comm, sizeof(comm));
|
||||
if (pid_cmdline(pid, buf, sizeof(buf))) {
|
||||
char proc[ttcols];
|
||||
int len;
|
||||
|
||||
switch (mode) {
|
||||
case 1:
|
||||
@@ -448,6 +454,8 @@ int cgroup_tree(char *path, char *pfx, int mode, int pos)
|
||||
if (plain) {
|
||||
strlcat(row, proc, rplen);
|
||||
} else {
|
||||
int len;
|
||||
|
||||
strlcat(row, CDIM, rlen);
|
||||
strlcat(row, proc, rlen);
|
||||
|
||||
@@ -592,7 +600,6 @@ int show_cgtop(char *arg)
|
||||
uev_t timer, input, sigint, sigterm, sigquit;
|
||||
char path[512];
|
||||
uev_ctx_t ctx;
|
||||
int flags;
|
||||
|
||||
if (!arg)
|
||||
arg = FINIT_CGPATH;
|
||||
@@ -602,7 +609,7 @@ int show_cgtop(char *arg)
|
||||
}
|
||||
|
||||
if (!hcreate(ttrows + 25))
|
||||
err(1, "failed creating hash table");
|
||||
ERR(70, "failed creating hash table");
|
||||
|
||||
sysinfo(&si);
|
||||
total_ram = si.totalram * si.mem_unit;
|
||||
@@ -611,6 +618,8 @@ int show_cgtop(char *arg)
|
||||
uev_timer_init(&ctx, &timer, cgtop, arg, 1, ionce ? 0 : 1000);
|
||||
|
||||
if (!ionce && !plain) {
|
||||
int flags;
|
||||
|
||||
atexit(cleanup);
|
||||
ttraw();
|
||||
hidecursor();
|
||||
|
||||
+3
-1
@@ -1,6 +1,6 @@
|
||||
/* Cgroup utility functions for initctl
|
||||
*
|
||||
* Copyright (c) 2019-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2019-2022 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -52,6 +52,8 @@ struct cg {
|
||||
} cg_cpu;
|
||||
};
|
||||
|
||||
int cgroup_avail(void);
|
||||
|
||||
char *pid_cmdline (int pid, char *buf, size_t len);
|
||||
char *pid_comm (int pid, char *buf, size_t len);
|
||||
char *pid_cgroup (int pid, char *buf, size_t len);
|
||||
|
||||
+28
-25
@@ -1,6 +1,6 @@
|
||||
/* External client API, using UNIX domain socket.
|
||||
*
|
||||
* Copyright (c) 2015-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2015-2022 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -21,13 +21,13 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include "client.h"
|
||||
#include "initctl.h"
|
||||
|
||||
static int sd = -1;
|
||||
|
||||
@@ -39,11 +39,17 @@ int client_connect(void)
|
||||
};
|
||||
|
||||
sd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
|
||||
if (-1 == sd)
|
||||
err(1, "Failed creating UNIX domain socket");
|
||||
if (-1 == sd) {
|
||||
WARN("Failed creating UNIX domain socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (connect(sd, (struct sockaddr*)&sun, sizeof(sun)) == -1)
|
||||
err(1, "Failed connecting to finit");
|
||||
if (connect(sd, (struct sockaddr*)&sun, sizeof(sun)) == -1) {
|
||||
if (errno != ENOENT)
|
||||
WARNX("Failed connecting to finit");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sd;
|
||||
}
|
||||
@@ -66,37 +72,38 @@ int client_disconnect(void)
|
||||
int client_send(struct init_request *rq, ssize_t len)
|
||||
{
|
||||
struct pollfd pfd = { 0 };
|
||||
int sd, result = 255;
|
||||
int result = 255;
|
||||
int rc;
|
||||
|
||||
sd = client_connect();
|
||||
if (-1 == sd)
|
||||
if (client_connect() == -1)
|
||||
return -1;
|
||||
|
||||
pfd.fd = sd;
|
||||
pfd.events = POLLOUT;
|
||||
if (poll(&pfd, 1, 2000) <= 0) {
|
||||
warn("Timed out waiting for Finit, errno %d", errno);
|
||||
WARN("Timed out waiting for Finit, errno %d", errno);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (write(sd, rq, len) != len) {
|
||||
warn("Failed communicating with Finit, errno %d", errno);
|
||||
WARN("Failed communicating with Finit, errno %d", errno);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
pfd.fd = sd;
|
||||
pfd.events = POLLIN;
|
||||
pfd.events = POLLIN | POLLERR | POLLHUP;
|
||||
if ((rc = poll(&pfd, 1, 2000)) <= 0) {
|
||||
if (rc)
|
||||
warn("poll(), errno %d", errno);
|
||||
else
|
||||
warnx("Timed out waiting for reply from Finit.");
|
||||
if (rc) {
|
||||
if (errno == EINTR) /* shutdown/reboot */
|
||||
goto exit;
|
||||
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);
|
||||
WARN("Failed reading reply from Finit, errno %d", errno);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@@ -112,15 +119,13 @@ exit:
|
||||
|
||||
svc_t *client_svc_iterator(int first)
|
||||
{
|
||||
int sd = -1;
|
||||
struct init_request rq = {
|
||||
.magic = INIT_MAGIC,
|
||||
.cmd = INIT_CMD_SVC_ITER,
|
||||
};
|
||||
static svc_t svc;
|
||||
|
||||
sd = client_connect();
|
||||
if (sd == -1)
|
||||
if (client_connect() == -1)
|
||||
return NULL;
|
||||
|
||||
if (first)
|
||||
@@ -139,7 +144,7 @@ svc_t *client_svc_iterator(int first)
|
||||
|
||||
return &svc;
|
||||
error:
|
||||
perror("Failed communicating with finit");
|
||||
WARN("Failed communicating with finit, error %d", errno);
|
||||
client_disconnect();
|
||||
sd = -1;
|
||||
|
||||
@@ -153,10 +158,8 @@ svc_t *do_cmd(int cmd, const char *arg)
|
||||
.cmd = cmd,
|
||||
};
|
||||
static svc_t svc;
|
||||
int sd = -1;
|
||||
|
||||
sd = client_connect();
|
||||
if (sd == -1)
|
||||
if (client_connect() == -1)
|
||||
return NULL;
|
||||
|
||||
strlcpy(rq.data, arg, sizeof(rq.data));
|
||||
@@ -172,7 +175,7 @@ svc_t *do_cmd(int cmd, const char *arg)
|
||||
return &svc;
|
||||
error:
|
||||
client_disconnect();
|
||||
perror("Failed communicating with finit");
|
||||
WARN("Failed communicating with finit, error %d", errno);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* External client API, using UNIX domain socket.
|
||||
*
|
||||
* Copyright (c) 2015-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2015-2022 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
|
||||
|
||||
+43
-5
@@ -21,10 +21,15 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <dirent.h>
|
||||
#include <ftw.h>
|
||||
#include <libgen.h>
|
||||
#include <lite/lite.h>
|
||||
#include <stdio.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
#include "finit.h"
|
||||
#include "cond.h"
|
||||
@@ -128,6 +133,25 @@ static int cond_checkpath(const char *path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Intended for 'service/foo/`, nothing else */
|
||||
static void cond_delpath(const char *path)
|
||||
{
|
||||
char fn[PATH_MAX];
|
||||
struct dirent *d;
|
||||
DIR *dir;
|
||||
|
||||
dir = opendir(path);
|
||||
if (!dir)
|
||||
return;
|
||||
|
||||
while ((d = readdir(dir))) {
|
||||
paste(fn, sizeof(fn), path, d->d_name);
|
||||
remove(fn);
|
||||
}
|
||||
closedir(dir);
|
||||
unlink(path);
|
||||
}
|
||||
|
||||
int cond_set_path(const char *path, enum cond_state next)
|
||||
{
|
||||
enum cond_state prev;
|
||||
@@ -151,8 +175,18 @@ int cond_set_path(const char *path, enum cond_state next)
|
||||
break;
|
||||
|
||||
case COND_OFF:
|
||||
if (unlink(path) && errno != ENOENT)
|
||||
_pe("Failed removing condition '%s'", path);
|
||||
if (unlink(path)) {
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
break;
|
||||
case EISDIR:
|
||||
cond_delpath(path);
|
||||
break;
|
||||
default:
|
||||
_pe("Failed removing condition '%s'", path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -164,18 +198,22 @@ int cond_set_path(const char *path, enum cond_state next)
|
||||
}
|
||||
|
||||
/* Should only be used by cond_set*(), cond_clear(), and usr/sys plugins! */
|
||||
void cond_update(const char *name)
|
||||
int cond_update(const char *name)
|
||||
{
|
||||
svc_t *svc, *iter = NULL;
|
||||
int affects = 0;
|
||||
|
||||
_d("%s", name);
|
||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||
if (!svc_has_cond(svc) || !cond_affects(name, svc->cond))
|
||||
continue;
|
||||
|
||||
affects++;
|
||||
_d("%s: match <%s> %s(%s)", name ?: "nil", svc->cond, svc->desc, svc->cmd);
|
||||
service_step(svc);
|
||||
}
|
||||
|
||||
return affects;
|
||||
}
|
||||
|
||||
int cond_set_noupdate(const char *name)
|
||||
@@ -269,7 +307,7 @@ static int do_assert(const char *fpath, const struct stat *sb, int tflg, struct
|
||||
|
||||
nm = strstr((char *)fpath, COND_BASE);
|
||||
if (!nm) {
|
||||
_e("Incorrect condtion path %s, cannot %sassert", fpath, set ? "re" : "de");
|
||||
_e("Incorrect condition path %s, cannot %sassert", fpath, set ? "re" : "de");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
+5
-1
@@ -21,8 +21,12 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <lite/lite.h>
|
||||
#include <stdio.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
#include "finit.h"
|
||||
#include "cond.h"
|
||||
|
||||
+3
-2
@@ -2,7 +2,8 @@
|
||||
#define FINIT_COND_H_
|
||||
|
||||
#include <paths.h>
|
||||
#include <svc.h>
|
||||
|
||||
#include "svc.h"
|
||||
|
||||
#define COND_BASE "finit/cond"
|
||||
#define COND_PID "pid/"
|
||||
@@ -30,7 +31,7 @@ enum cond_state cond_get (const char *name);
|
||||
enum cond_state cond_get_agg (const char *names);
|
||||
int cond_affects (const char *name, const char *names);
|
||||
|
||||
void cond_update (const char *name);
|
||||
int cond_update (const char *name);
|
||||
int cond_set_path (const char *path, enum cond_state new);
|
||||
void cond_set (const char *name);
|
||||
void cond_set_oneshot (const char *name);
|
||||
|
||||
+248
-62
@@ -1,6 +1,6 @@
|
||||
/* Parser for /etc/finit.conf and /etc/finit.d/<SVC>.conf
|
||||
*
|
||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2022 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
|
||||
@@ -28,14 +28,20 @@
|
||||
#include <string.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/resource.h>
|
||||
#include <lite/lite.h>
|
||||
#include <lite/queue.h> /* BSD sys/queue.h API */
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
# include <libite/queue.h> /* BSD sys/queue.h API */
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
# include <lite/queue.h> /* BSD sys/queue.h API */
|
||||
#endif
|
||||
#include <time.h>
|
||||
#include <glob.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "cond.h"
|
||||
#include "iwatch.h"
|
||||
#include "private.h"
|
||||
#include "service.h"
|
||||
#include "tty.h"
|
||||
#include "helpers.h"
|
||||
@@ -48,6 +54,12 @@
|
||||
int logfile_size_max = 200000; /* 200 kB */
|
||||
int logfile_count_max = 5;
|
||||
|
||||
struct env_entry {
|
||||
TAILQ_ENTRY(env_entry) link;
|
||||
char *name;
|
||||
};
|
||||
static TAILQ_HEAD(, env_entry) env_list = TAILQ_HEAD_INITIALIZER(env_list);
|
||||
|
||||
struct rlimit initial_rlimit[RLIMIT_NLIMITS];
|
||||
struct rlimit global_rlimit[RLIMIT_NLIMITS];
|
||||
|
||||
@@ -61,7 +73,7 @@ struct conf_change {
|
||||
static struct iwatch iw_conf;
|
||||
static uev_t etcw;
|
||||
|
||||
static TAILQ_HEAD(head, conf_change) conf_change_list = TAILQ_HEAD_INITIALIZER(conf_change_list);
|
||||
static TAILQ_HEAD(, conf_change) conf_change_list = TAILQ_HEAD_INITIALIZER(conf_change_list);
|
||||
|
||||
static int parse_conf(char *file, int is_rcsd);
|
||||
static void drop_changes(void);
|
||||
@@ -80,8 +92,10 @@ fallback:
|
||||
}
|
||||
|
||||
/*
|
||||
* finit.debug = [on,off]
|
||||
* finit.show_status = [on,off]
|
||||
* finit.debug = [on,off]
|
||||
* finit.fstab = /path/to/etc/fstab.aternative
|
||||
* finit.status = [on,off] (compat finit.show_status)
|
||||
* finit.status_style = [old,classic,modern]
|
||||
*/
|
||||
static void parse_finit_opts(char *opt)
|
||||
{
|
||||
@@ -96,6 +110,11 @@ static void parse_finit_opts(char *opt)
|
||||
return;
|
||||
}
|
||||
|
||||
if (string_compare(opt, "fstab")) {
|
||||
fstab = arg;
|
||||
return;
|
||||
}
|
||||
|
||||
if (string_compare(opt, "status_style")) {
|
||||
if (!arg) {
|
||||
_e("status_style option requires an argument, skipping.");
|
||||
@@ -109,12 +128,39 @@ static void parse_finit_opts(char *opt)
|
||||
return;
|
||||
}
|
||||
|
||||
if (string_compare(opt, "show_status")) {
|
||||
if (string_compare(opt, "status") || string_compare(opt, "show_status")) {
|
||||
show_progress(get_bool(arg, 1) ? PROGRESS_DEFAULT : PROGRESS_SILENT);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* When runlevel (single integer) is given on the command line,
|
||||
* it overrides the runlevel in finit.conf and the built-in
|
||||
* default (from configure). It do however have to pass the
|
||||
* same sanity checks.
|
||||
*/
|
||||
static int parse_runlevel(char *arg)
|
||||
{
|
||||
const char *err = NULL;
|
||||
char *ptr = arg;
|
||||
long long num;
|
||||
|
||||
/* Sanity check the token is just digit(s) */
|
||||
while (*ptr) {
|
||||
if (!isdigit(*ptr++))
|
||||
return 0;
|
||||
}
|
||||
|
||||
num = strtonum(arg, 1, 9, &err);
|
||||
if (err || num == 6) {
|
||||
_d("Not a valid runlevel (%s), valid levels are [1-9], excluding 6, skipping.", arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int)num;
|
||||
}
|
||||
|
||||
static void parse_arg(char *arg)
|
||||
{
|
||||
if (!strncmp(arg, "finit.", 6)) {
|
||||
@@ -122,11 +168,19 @@ static void parse_arg(char *arg)
|
||||
return;
|
||||
}
|
||||
|
||||
if (string_compare(arg, "rescue") || string_compare(arg, "recover"))
|
||||
if (string_compare(arg, "rescue") || string_compare(arg, "recover")) {
|
||||
rescue = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (string_compare(arg, "single") || string_compare(arg, "S"))
|
||||
if (string_compare(arg, "single") || string_compare(arg, "S")) {
|
||||
single = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Put any new command line options before this line. */
|
||||
|
||||
cmdlevel = parse_runlevel(arg);
|
||||
}
|
||||
|
||||
#ifdef KERNEL_CMDLINE
|
||||
@@ -165,39 +219,147 @@ static void parse_kernel_cmdline(void)
|
||||
#define parse_kernel_cmdline()
|
||||
#endif
|
||||
|
||||
static void parse_kernel_loglevel(void)
|
||||
{
|
||||
char line[LINE_SIZE], *ptr;
|
||||
FILE *fp;
|
||||
int val;
|
||||
|
||||
fp = fopen("/proc/sys/kernel/printk", "r");
|
||||
if (!fp)
|
||||
return;
|
||||
|
||||
if (!fgets(line, sizeof(line), fp)) {
|
||||
fclose(fp);
|
||||
return;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
ptr = chomp(line);
|
||||
_d("%s", ptr);
|
||||
val = atoi(ptr);
|
||||
if (val >= 7)
|
||||
kerndebug = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Kernel gives us all non-kernel options on our cmdline
|
||||
*/
|
||||
void conf_parse_cmdline(int argc, char *argv[])
|
||||
{
|
||||
int dbg = 0;
|
||||
|
||||
for (int i = 1; i < argc; i++)
|
||||
parse_arg(argv[i]);
|
||||
|
||||
parse_kernel_cmdline();
|
||||
parse_kernel_loglevel();
|
||||
}
|
||||
|
||||
log_init(dbg);
|
||||
/*
|
||||
* Clear all environment variables read in parse_env(), they may be
|
||||
* removed now so let the next call to parse_env() restore them.
|
||||
*/
|
||||
void conf_reset_env(void)
|
||||
{
|
||||
struct env_entry *node, *tmp;
|
||||
|
||||
TAILQ_FOREACH_SAFE(node, &env_list, link, tmp) {
|
||||
TAILQ_REMOVE(&env_list, node, link);
|
||||
if (node->name) {
|
||||
unsetenv(node->name);
|
||||
free(node->name);
|
||||
}
|
||||
free(node);
|
||||
}
|
||||
|
||||
setenv("PATH", _PATH_STDPATH, 1);
|
||||
setenv("SHELL", _PATH_BSHELL, 1);
|
||||
setenv("LOGNAME", "root", 1);
|
||||
setenv("USER", "root", 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets, and makes a note of, all KEY=VALUE lines in a given .conf line
|
||||
* from finit.conf, or other .conf file. Note, PATH is always reset in
|
||||
* the conf_reset_env() function.
|
||||
*/
|
||||
static void parse_env(char *line)
|
||||
{
|
||||
struct env_entry *node;
|
||||
char *key, *val, *end;
|
||||
|
||||
/* skip any leading whitespace */
|
||||
key = line;
|
||||
while (isspace(*key))
|
||||
key++;
|
||||
|
||||
/* find end of line */
|
||||
end = key;
|
||||
while (*end)
|
||||
end++;
|
||||
|
||||
/* strip trailing whitespace */
|
||||
if (end > key) {
|
||||
end--;
|
||||
while (isspace(*end))
|
||||
*end-- = 0;
|
||||
}
|
||||
|
||||
val = strchr(key, '=');
|
||||
if (!val)
|
||||
return;
|
||||
*val++ = 0;
|
||||
|
||||
/* strip leading whitespace from value */
|
||||
while (isspace(*val))
|
||||
val++;
|
||||
|
||||
/* unquote value, if quoted */
|
||||
if (val[0] == '"' || val[0] == '\'') {
|
||||
char q = val[0];
|
||||
|
||||
if (*end == q) {
|
||||
val = &val[1];
|
||||
*end = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* find end of key */
|
||||
end = key;
|
||||
while (*end)
|
||||
end++;
|
||||
|
||||
/* strip trailing whitespace */
|
||||
if (end > key) {
|
||||
end--;
|
||||
while (isspace(*end))
|
||||
*end-- = 0;
|
||||
}
|
||||
|
||||
setenv(key, val, 1);
|
||||
|
||||
node = malloc(sizeof(*node));
|
||||
if (!node) {
|
||||
_pe("Out of memory cannot track env vars");
|
||||
return;
|
||||
}
|
||||
node->name = strdup(key);
|
||||
TAILQ_INSERT_HEAD(&env_list, node, link);
|
||||
}
|
||||
|
||||
static int kmod_exists(char *mod)
|
||||
{
|
||||
char buf[256];
|
||||
int found = 0;
|
||||
FILE *fp;
|
||||
char buf[256];
|
||||
size_t len;
|
||||
|
||||
for (len = 0; mod[len]; len++) {
|
||||
if (mod[len] == ' ' || mod[len] == '\t')
|
||||
break;
|
||||
}
|
||||
|
||||
fp = fopen("/proc/modules", "r");
|
||||
if (!fp)
|
||||
return 0;
|
||||
|
||||
while (!found && (fgets(buf, sizeof(buf), fp))) {
|
||||
if (!strncmp(buf, mod, len))
|
||||
while (!found && fgets(buf, sizeof(buf), fp)) {
|
||||
char *kmod = strtok(buf, " \t");
|
||||
|
||||
if (kmod && !strcmp(kmod, mod))
|
||||
found = 1;
|
||||
}
|
||||
fclose(fp);
|
||||
@@ -205,22 +367,26 @@ static int kmod_exists(char *mod)
|
||||
return found;
|
||||
}
|
||||
|
||||
static void kmod_load(char *line)
|
||||
static void kmod_load(char *mod)
|
||||
{
|
||||
char *mod;
|
||||
char module[64] = { 0 };
|
||||
char cmd[CMD_SIZE];
|
||||
|
||||
if (runlevel != 0)
|
||||
return;
|
||||
|
||||
mod = strip_line(line);
|
||||
if (kmod_exists(mod))
|
||||
/* Strip args for progress below and kmod_exists() */
|
||||
strlcpy(module, mod, sizeof(module));
|
||||
if (!strtok(module, " \t"))
|
||||
return;
|
||||
|
||||
if (kmod_exists(module))
|
||||
return;
|
||||
|
||||
strcpy(cmd, "modprobe ");
|
||||
strlcat(cmd, mod, sizeof(cmd));
|
||||
|
||||
run_interactive(cmd, "Loading kernel module %s", mod);
|
||||
run_interactive(cmd, "Loading kernel module %s", module);
|
||||
}
|
||||
|
||||
/* Convert optional "[!123456789S]" string into a bitmask */
|
||||
@@ -288,12 +454,12 @@ void conf_parse_cond(svc_t *svc, char *cond)
|
||||
ptr[i] = 0;
|
||||
|
||||
if (i >= sizeof(svc->cond)) {
|
||||
logit(LOG_WARNING, "Too long event list in declaration of %s: %s", svc->cmd, ptr);
|
||||
logit(LOG_WARNING, "Too long event list in declaration of %s: %s", svc_ident(svc, NULL, 0), ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strncmp(ptr, "svc/", 4)) {
|
||||
logit(LOG_ERR, "Unsupported cond syntax for %s: <%s", svc->cmd, ptr);
|
||||
logit(LOG_ERR, "Unsupported cond syntax for %s: <%s", svc_ident(svc, NULL, 0), ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -451,7 +617,7 @@ static void conf_parse_cgroup(char *line)
|
||||
cgroup_add(name, config, 0);
|
||||
}
|
||||
|
||||
static void parse_static(char *line, int is_rcsd)
|
||||
static int parse_static(char *line, int is_rcsd)
|
||||
{
|
||||
char cmd[CMD_SIZE];
|
||||
char *x;
|
||||
@@ -459,7 +625,7 @@ static void parse_static(char *line, int is_rcsd)
|
||||
if (BOOTSTRAP && (MATCH_CMD(line, "host ", x) || MATCH_CMD(line, "hostname ", x))) {
|
||||
if (hostname) free(hostname);
|
||||
hostname = strdup(strip_line(x));
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (BOOTSTRAP && MATCH_CMD(line, "mknod ", x)) {
|
||||
@@ -468,25 +634,25 @@ static void parse_static(char *line, int is_rcsd)
|
||||
strcpy(cmd, "mknod ");
|
||||
strlcat(cmd, dev, sizeof(cmd));
|
||||
run_interactive(cmd, "Creating device node %s", dev);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Kernel module to load */
|
||||
if (BOOTSTRAP && MATCH_CMD(line, "module ", x)) {
|
||||
kmod_load(x);
|
||||
return;
|
||||
kmod_load(strip_line(x));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (BOOTSTRAP && MATCH_CMD(line, "network ", x)) {
|
||||
if (network) free(network);
|
||||
network = strdup(strip_line(x));
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (BOOTSTRAP && MATCH_CMD(line, "runparts ", x)) {
|
||||
if (runparts) free(runparts);
|
||||
runparts = strdup(strip_line(x));
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (MATCH_CMD(line, "include ", x)) {
|
||||
@@ -495,11 +661,10 @@ static void parse_static(char *line, int is_rcsd)
|
||||
strlcpy(cmd, file, sizeof(cmd));
|
||||
if (!fexist(cmd)) {
|
||||
_e("Cannot find include file %s, absolute path required!", x);
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
|
||||
parse_conf(cmd, is_rcsd);
|
||||
return;
|
||||
return parse_conf(cmd, is_rcsd);
|
||||
}
|
||||
|
||||
if (MATCH_CMD(line, "log ", x)) {
|
||||
@@ -520,12 +685,14 @@ static void parse_static(char *line, int is_rcsd)
|
||||
logfile_size_max = size;
|
||||
if (count >= 0)
|
||||
logfile_count_max = count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (MATCH_CMD(line, "shutdown ", x)) {
|
||||
if (sdown) free(sdown);
|
||||
sdown = strdup(strip_line(x));
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -542,72 +709,85 @@ static void parse_static(char *line, int is_rcsd)
|
||||
cfglevel = RUNLEVEL;
|
||||
if (cfglevel < 1 || cfglevel > 9 || cfglevel == 6)
|
||||
cfglevel = 2; /* Fallback */
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void parse_dynamic(char *line, struct rlimit rlimit[], char *file)
|
||||
static int parse_dynamic(char *line, struct rlimit rlimit[], char *file)
|
||||
{
|
||||
char *x;
|
||||
|
||||
/* Monitored daemon, will be respawned on exit */
|
||||
if (MATCH_CMD(line, "service ", x)) {
|
||||
service_register(SVC_TYPE_SERVICE, x, rlimit, file);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* One-shot task, will not be respawned */
|
||||
if (MATCH_CMD(line, "task ", x)) {
|
||||
service_register(SVC_TYPE_TASK, x, rlimit, file);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Like task but waits for completion, useful w/ [S] */
|
||||
if (MATCH_CMD(line, "run ", x)) {
|
||||
service_register(SVC_TYPE_RUN, x, rlimit, file);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Similar to task but is treated like a SysV init script */
|
||||
if (MATCH_CMD(line, "sysv ", x)) {
|
||||
service_register(SVC_TYPE_SYSV, x, rlimit, file);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read resource limits */
|
||||
if (MATCH_CMD(line, "rlimit ", x)) {
|
||||
conf_parse_rlimit(x, rlimit);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read contrl group limits */
|
||||
/* Read control group limits */
|
||||
if (MATCH_CMD(line, "cgroup ", x)) {
|
||||
conf_parse_cgroup(x);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set current cgroup for the following services/run/tasks */
|
||||
if (MATCH_CMD(line, "cgroup.", x)) {
|
||||
strlcpy(cgroup_current, x, sizeof(cgroup_current));
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Regular or serial TTYs to run getty */
|
||||
if (MATCH_CMD(line, "tty ", x)) {
|
||||
service_register(SVC_TYPE_TTY, strip_line(x), rlimit, file);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void tabstospaces(char *line)
|
||||
{
|
||||
if (!line)
|
||||
return;
|
||||
|
||||
for (int i = 0; line[i]; i++) {
|
||||
if (line[i] == '\t')
|
||||
line[i] = ' ';
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int parse_conf(char *file, int is_rcsd)
|
||||
@@ -641,8 +821,13 @@ static int parse_conf(char *file, int is_rcsd)
|
||||
if (MATCH_CMD(line, "#", x))
|
||||
continue;
|
||||
|
||||
parse_static(line, is_rcsd);
|
||||
parse_dynamic(line, is_rcsd ? rlimit : global_rlimit, file);
|
||||
if (!parse_static(line, is_rcsd))
|
||||
continue;
|
||||
if (!parse_dynamic(line, is_rcsd ? rlimit : global_rlimit, file))
|
||||
continue;
|
||||
|
||||
/* Not static or dynamic conf, check if it is a global env. */
|
||||
parse_env(line);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
@@ -666,6 +851,7 @@ int conf_reload(void)
|
||||
/* Mark and sweep */
|
||||
cgroup_mark_all();
|
||||
svc_mark_dynamic();
|
||||
conf_reset_env();
|
||||
|
||||
/*
|
||||
* Reset global rlimit to bootstrap values from conf_init().
|
||||
|
||||
+2
-1
@@ -1,6 +1,6 @@
|
||||
/* Parser for /etc/finit.conf and /etc/finit.d/<SVC>.conf
|
||||
*
|
||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2022 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
|
||||
@@ -42,6 +42,7 @@ int conf_any_change (void);
|
||||
int conf_changed (char *file);
|
||||
int conf_monitor (void);
|
||||
|
||||
void conf_reset_env (void);
|
||||
void conf_parse_cmdline (int argc, char *argv[]);
|
||||
int conf_parse_runlevels (char *runlevels);
|
||||
void conf_parse_cond (svc_t *svc, char *cond);
|
||||
|
||||
+112
-76
@@ -1,7 +1,7 @@
|
||||
/* Functions for exec'ing processes
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2022 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
|
||||
@@ -28,12 +28,17 @@
|
||||
#include <dirent.h>
|
||||
#include <err.h>
|
||||
#include <stdarg.h>
|
||||
#include <sysexits.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
|
||||
#include <termios.h>
|
||||
#include <lite/lite.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
#include <linux/vt.h>
|
||||
|
||||
#include "finit.h"
|
||||
@@ -66,89 +71,128 @@ int complete(char *cmd, int pid)
|
||||
return status;
|
||||
}
|
||||
|
||||
int run(char *cmd)
|
||||
static int do_redirect(void)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen("/dev/null", "w");
|
||||
if (fp) {
|
||||
int fd = fileno(fp);
|
||||
|
||||
dup2(fd, STDIN_FILENO);
|
||||
dup2(fd, STDOUT_FILENO);
|
||||
dup2(fd, STDERR_FILENO);
|
||||
|
||||
return fclose(fp);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run 'cmd' and wait for completion. If 'log' is not NULL any output
|
||||
* from the command is logged with the given string as prefix, use "" to
|
||||
* skip. If 'log' is NULL all output is redirected to /dev/null, which
|
||||
* is what this function originally did.
|
||||
*/
|
||||
int run(char *cmd, char *log)
|
||||
{
|
||||
char *args[NUM_ARGS + 1] = { 0 };
|
||||
int status, result, i = 0;
|
||||
char *args[NUM_ARGS + 1], *arg, *backup;
|
||||
char *backup = NULL;
|
||||
pid_t pid;
|
||||
|
||||
/* We must create a copy that is possible to modify. */
|
||||
backup = arg = strdup(cmd);
|
||||
if (!arg)
|
||||
return 1; /* Failed allocating a string to be modified. */
|
||||
if (!log) {
|
||||
char *arg;
|
||||
|
||||
/* Split command line into tokens of an argv[] array. */
|
||||
args[i++] = strsep(&arg, "\t ");
|
||||
while (arg && i < NUM_ARGS) {
|
||||
/* Handle run("su -c \"dbus-daemon --system\" messagebus");
|
||||
* => "su", "-c", "\"dbus-daemon --system\"", "messagebus" */
|
||||
if (*arg == '\'' || *arg == '"') {
|
||||
char *p, delim[2] = " ";
|
||||
/* We must create a copy that is possible to modify. */
|
||||
backup = arg = strdup(cmd);
|
||||
if (!arg)
|
||||
return 1;
|
||||
|
||||
delim[0] = arg[0];
|
||||
args[i++] = arg++;
|
||||
strsep(&arg, delim);
|
||||
p = arg - 1;
|
||||
*p = *delim;
|
||||
*arg++ = 0;
|
||||
} else {
|
||||
args[i++] = strsep(&arg, "\t ");
|
||||
/* Split command line into tokens of an argv[] array. */
|
||||
args[i++] = strsep(&arg, "\t ");
|
||||
while (arg && i < NUM_ARGS) {
|
||||
/* Handle run("su -c \"dbus-daemon --system\" messagebus");
|
||||
* => "su", "-c", "\"dbus-daemon --system\"", "messagebus" */
|
||||
if (*arg == '\'' || *arg == '"') {
|
||||
char *p, delim[2] = " ";
|
||||
|
||||
delim[0] = arg[0];
|
||||
args[i++] = arg++;
|
||||
strsep(&arg, delim);
|
||||
p = arg - 1;
|
||||
*p = *delim;
|
||||
*arg++ = 0;
|
||||
} else {
|
||||
args[i++] = strsep(&arg, "\t ");
|
||||
}
|
||||
}
|
||||
}
|
||||
args[i] = NULL;
|
||||
args[i] = NULL;
|
||||
|
||||
if (i == NUM_ARGS && arg) {
|
||||
_e("Command too long: %s", cmd);
|
||||
free(backup);
|
||||
errno = EOVERFLOW;
|
||||
return 1;
|
||||
if (i == NUM_ARGS && arg) {
|
||||
_e("Command too long: %s", cmd);
|
||||
free(backup);
|
||||
errno = EOVERFLOW;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (0 == pid) {
|
||||
FILE *fp;
|
||||
int rc = EX_OSERR;
|
||||
|
||||
setsid();
|
||||
sig_unblock();
|
||||
if (!log) {
|
||||
do_redirect();
|
||||
execvp(args[0], args);
|
||||
} else {
|
||||
char *pfx = *log ? ": " : "";
|
||||
FILE *pp;
|
||||
|
||||
/* Always redirect stdio for run() */
|
||||
fp = fopen("/dev/null", "w");
|
||||
if (fp) {
|
||||
int fd = fileno(fp);
|
||||
pp = popen(cmd, "r");
|
||||
if (pp) {
|
||||
char buf[256];
|
||||
|
||||
dup2(fd, STDIN_FILENO);
|
||||
dup2(fd, STDOUT_FILENO);
|
||||
dup2(fd, STDERR_FILENO);
|
||||
while (fgets(buf, sizeof(buf), pp)) {
|
||||
chomp(buf);
|
||||
logit(LOG_NOTICE, "%s%s%s", log, pfx, buf);
|
||||
}
|
||||
|
||||
rc = pclose(pp);
|
||||
}
|
||||
}
|
||||
|
||||
sig_unblock();
|
||||
execvp(args[0], args);
|
||||
|
||||
_exit(1); /* Only if execv() fails. */
|
||||
_exit(rc);
|
||||
} else if (-1 == pid) {
|
||||
_pe("%s", args[0]);
|
||||
free(backup);
|
||||
_pe("%s", !log ? args[0] : cmd);
|
||||
if (backup)
|
||||
free(backup);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = complete(args[0], pid);
|
||||
if (-1 == status) {
|
||||
free(backup);
|
||||
if (backup)
|
||||
free(backup);
|
||||
return 1;
|
||||
}
|
||||
|
||||
result = WEXITSTATUS(status);
|
||||
if (WIFEXITED(status)) {
|
||||
_d("Started %s and ended OK: %d", args[0], result);
|
||||
_d("Started '%s' and exit without signal, status: %d", cmd, result);
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
_d("Process %s terminated by signal %d", args[0], WTERMSIG(status));
|
||||
_d("Process '%s' terminated by signal %d", cmd, WTERMSIG(status));
|
||||
if (!result)
|
||||
result = 1; /* Must alert callee that the command did complete successfully.
|
||||
* This is necessary since not all programs trap signals and
|
||||
* change their return code accordingly. --Jocke */
|
||||
}
|
||||
|
||||
free(backup);
|
||||
if (backup)
|
||||
free(backup);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -182,7 +226,7 @@ int run_interactive(char *cmd, char *fmt, ...)
|
||||
}
|
||||
|
||||
/* Run cmd ... */
|
||||
status = run(cmd);
|
||||
status = run(cmd, "");
|
||||
|
||||
/* Restore stderr/stdout */
|
||||
if (fp && !debug) {
|
||||
@@ -218,7 +262,6 @@ int run_interactive(char *cmd, char *fmt, ...)
|
||||
|
||||
int exec_runtask(char *cmd, char *args[])
|
||||
{
|
||||
size_t i;
|
||||
char buf[1024] = "";
|
||||
char *argv[4] = {
|
||||
"sh",
|
||||
@@ -226,6 +269,7 @@ int exec_runtask(char *cmd, char *args[])
|
||||
buf,
|
||||
NULL
|
||||
};
|
||||
size_t i;
|
||||
|
||||
strlcat(buf, cmd, sizeof(buf));
|
||||
for (i = 1; args[i]; i++) {
|
||||
@@ -281,8 +325,12 @@ static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit
|
||||
|
||||
static int activate_console(int noclear, int nowait)
|
||||
{
|
||||
static const char msg[] = "\nPlease press Enter to activate this console.";
|
||||
static const char clr[] = "\r\e[K";
|
||||
static const char cup[] = "\e[A";
|
||||
struct termios orig;
|
||||
int ret = 0;
|
||||
char c;
|
||||
int rc;
|
||||
|
||||
if (nowait || rescue)
|
||||
return 1;
|
||||
@@ -301,36 +349,24 @@ static int activate_console(int noclear, int nowait)
|
||||
tcsetattr(STDIN_FILENO, TCSAFLUSH, &c);
|
||||
}
|
||||
|
||||
while (!fexist(SYNC_SHUTDOWN)) {
|
||||
char c;
|
||||
static const char clr[] = "\r\e[2K";
|
||||
static const char cup[] = "\e[A";
|
||||
static const char msg[] = "\nPlease press Enter to activate this console.";
|
||||
dprint(STDERR_FILENO, clr, strlen(clr));
|
||||
dprint(STDERR_FILENO, msg, strlen(msg));
|
||||
while ((rc = read(STDIN_FILENO, &c, 1)) > 0 && c != '\r' && c != '\n')
|
||||
continue;
|
||||
|
||||
if (fexist(SYNC_STOPPED)) {
|
||||
sleep(5);
|
||||
continue;
|
||||
}
|
||||
/* On any error (likely EINTR), we avoid starting getty */
|
||||
if (rc == -1)
|
||||
rc = 0;
|
||||
|
||||
dprint(STDERR_FILENO, clr, strlen(clr));
|
||||
dprint(STDERR_FILENO, msg, strlen(msg));
|
||||
while (read(STDIN_FILENO, &c, 1) == 1 && c != '\r')
|
||||
continue;
|
||||
|
||||
if (fexist(SYNC_STOPPED))
|
||||
continue;
|
||||
|
||||
dprint(STDERR_FILENO, clr, strlen(clr));
|
||||
dprint(STDERR_FILENO, cup, strlen(cup));
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
/* Clear msg and move cursor up for next message/login: */
|
||||
dprint(STDERR_FILENO, clr, strlen(clr));
|
||||
dprint(STDERR_FILENO, cup, strlen(cup));
|
||||
|
||||
/* Restore TTY */
|
||||
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig) == -1)
|
||||
ret = 0;
|
||||
rc = 0; /* TTY in bad shape, restart */
|
||||
|
||||
return ret;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -359,7 +395,7 @@ pid_t run_getty(char *tty, char *cmd, char *args[], int noclear, int nowait, str
|
||||
/* Dunno speed, tell stty() to not mess with it */
|
||||
prepare_tty(tty, B0, "getty", rlimit);
|
||||
if (activate_console(noclear, nowait)) {
|
||||
logit(LOG_INFO, "Starting external getty on %s", tty);
|
||||
logit(LOG_INFO, "Starting getty on %s", tty);
|
||||
rc = execv(cmd, args);
|
||||
}
|
||||
|
||||
|
||||
+289
-101
@@ -1,7 +1,7 @@
|
||||
/* Finit - Fast /sbin/init replacement w/ I/O, hook & service plugins
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2022 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
|
||||
@@ -26,17 +26,23 @@
|
||||
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#ifdef HAVE_FSTAB_H
|
||||
#include <fstab.h>
|
||||
#endif
|
||||
#include <getopt.h>
|
||||
#ifdef HAVE_MNTENT_H
|
||||
#include <mntent.h>
|
||||
#endif
|
||||
#include <time.h> /* tzet() */
|
||||
#include <sys/klog.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h> /* umask(), mkdir() */
|
||||
#include <sys/wait.h>
|
||||
#include <lite/lite.h>
|
||||
#ifdef HAVE_SYS_SYSMACROS_H
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
#include "finit.h"
|
||||
#include "cgroup.h"
|
||||
@@ -56,16 +62,20 @@
|
||||
|
||||
int runlevel = 0; /* Bootstrap 'S' */
|
||||
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
|
||||
int cmdlevel = 0; /* runlevel override from cmdline */
|
||||
int prevlevel = -1;
|
||||
int debug = 0; /* debug mode from kernel cmdline */
|
||||
int rescue = 0; /* rescue mode from kernel cmdline */
|
||||
int single = 0; /* single user mode from kernel cmdline */
|
||||
int bootstrap = 1; /* set while bootrapping (for TTYs) */
|
||||
int kerndebug = 0; /* set if /proc/sys/kernel/printk > 7 */
|
||||
char *fstab = FINIT_FSTAB;
|
||||
char *sdown = NULL;
|
||||
char *network = NULL;
|
||||
char *hostname = NULL;
|
||||
char *rcsd = FINIT_RCSD;
|
||||
char *runparts = NULL;
|
||||
char *osheading = NULL;
|
||||
|
||||
uev_ctx_t *ctx = NULL; /* Main loop context */
|
||||
svc_t *wdog = NULL; /* No watchdog by default */
|
||||
@@ -81,7 +91,7 @@ static void banner(void)
|
||||
* similar enabled to start emptying /dev/kmsg, but for
|
||||
* our progress we want to own the console.
|
||||
*/
|
||||
if (!debug)
|
||||
if (!debug && !kerndebug)
|
||||
klogctl(6, NULL, 0);
|
||||
|
||||
/*
|
||||
@@ -90,7 +100,91 @@ static void banner(void)
|
||||
*/
|
||||
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
|
||||
}
|
||||
|
||||
static int sulogin(int do_reboot)
|
||||
{
|
||||
int rc = EX_OSFILE;
|
||||
char *cmd[] = {
|
||||
_PATH_SULOGIN,
|
||||
"sulogin",
|
||||
};
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < NELEMS(cmd); i++) {
|
||||
char *path = which(cmd[i]);
|
||||
|
||||
if (access(path, X_OK)) {
|
||||
free(path);
|
||||
continue;
|
||||
}
|
||||
|
||||
rc = systemf("%s", path);
|
||||
free(path);
|
||||
break;
|
||||
}
|
||||
|
||||
if (do_reboot) {
|
||||
do_shutdown(SHUT_REBOOT);
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
char *fs_root_dev(char *real, size_t len)
|
||||
{
|
||||
struct dirent *d;
|
||||
struct stat st;
|
||||
int found = 0;
|
||||
dev_t dev;
|
||||
DIR *dir;
|
||||
|
||||
if (stat("/", &st))
|
||||
return NULL;
|
||||
|
||||
if (S_ISBLK(st.st_mode))
|
||||
dev = st.st_rdev;
|
||||
else
|
||||
dev = st.st_dev;
|
||||
|
||||
dir = opendir("/sys/block");
|
||||
if (!dir)
|
||||
return NULL;
|
||||
|
||||
while ((d = readdir(dir))) {
|
||||
char buf[10];
|
||||
char *ptr;
|
||||
|
||||
if (fnread(buf, sizeof(buf), "/sys/block/%s/dev", d->d_name) == -1)
|
||||
continue;
|
||||
|
||||
ptr = strchr(buf, ':');
|
||||
if (!ptr)
|
||||
continue;
|
||||
*ptr++ = 0;
|
||||
|
||||
if (atoi(buf) == (int)major(dev) && atoi(ptr) == (int)minor(dev)) {
|
||||
/* Guess name, assume no renaming */
|
||||
snprintf(real, len, "/dev/%s", d->d_name);
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
if (!found)
|
||||
return NULL;
|
||||
|
||||
return real;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -98,89 +192,133 @@ static void banner(void)
|
||||
*/
|
||||
static int fsck(int pass)
|
||||
{
|
||||
struct fstab *fs;
|
||||
struct mntent mount;
|
||||
struct mntent *mnt;
|
||||
char real[192];
|
||||
char buf[256];
|
||||
int rc = 0;
|
||||
FILE *fp;
|
||||
|
||||
if (!setfsent()) {
|
||||
_pe("Failed opening fstab");
|
||||
return 1;
|
||||
fp = setmntent(fstab, "r");
|
||||
if (!fp) {
|
||||
_pe("Failed opening fstab: %s", fstab);
|
||||
sulogin(1);
|
||||
}
|
||||
|
||||
while ((fs = getfsent())) {
|
||||
char cmd[80];
|
||||
_d("Opened %s, pass %d", fstab, pass);
|
||||
while ((mnt = getmntent_r(fp, &mount, buf, sizeof(buf)))) {
|
||||
int fsck_rc = 0;
|
||||
struct stat st;
|
||||
char cmd[256];
|
||||
char *dev;
|
||||
|
||||
if (fs->fs_passno != pass)
|
||||
_d("got: fsname '%s' dir '%s' type '%s' opts '%s' freq '%d' passno '%d'",
|
||||
mnt->mnt_fsname, mnt->mnt_dir, mnt->mnt_type, mnt->mnt_opts,
|
||||
mnt->mnt_freq, mnt->mnt_passno);
|
||||
|
||||
if (mnt->mnt_passno == 0 || mnt->mnt_passno != pass)
|
||||
continue;
|
||||
|
||||
/* Device to maybe fsck, */
|
||||
dev = mnt->mnt_fsname;
|
||||
|
||||
errno = 0;
|
||||
if (stat(fs->fs_spec, &st) || !S_ISBLK(st.st_mode)) {
|
||||
if (!string_match(fs->fs_spec, "UUID=") && !string_match(fs->fs_spec, "LABEL=")) {
|
||||
_d("Cannot fsck %s, not a block device: %s", fs->fs_spec, strerror(errno));
|
||||
if (stat(dev, &st) || !S_ISBLK(st.st_mode)) {
|
||||
int skip = 1;
|
||||
|
||||
if (string_match(dev, "UUID=") || string_match(dev, "LABEL="))
|
||||
skip = 0;
|
||||
|
||||
/*
|
||||
* Kernel short form for root= device, figure out
|
||||
* actual device since we cannot rely on symlinks
|
||||
* https://bugs.busybox.net/show_bug.cgi?id=8891
|
||||
*/
|
||||
else if (string_compare(dev, "/dev/root")) {
|
||||
if (fs_root_dev(real, sizeof(real))) {
|
||||
dev = real;
|
||||
skip = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (skip) {
|
||||
_d("Cannot fsck %s, not a block device: %s", dev, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (ismnt("/proc/mounts", fs->fs_file, "rw")) {
|
||||
_d("Skipping fsck of %s, already mounted rw on %s.", fs->fs_spec, fs->fs_file);
|
||||
if (ismnt("/proc/mounts", mnt->mnt_dir, "rw")) {
|
||||
_d("Skipping fsck of %s, already mounted rw on %s.", dev, mnt->mnt_dir);
|
||||
continue;
|
||||
}
|
||||
|
||||
snprintf(cmd, sizeof(cmd), "fsck -a %s", fs->fs_spec);
|
||||
rc += run_interactive(cmd, "Checking filesystem %.13s", fs->fs_spec);
|
||||
#ifdef FSCK_FIX
|
||||
snprintf(cmd, sizeof(cmd), "fsck -yf %s", dev);
|
||||
#else
|
||||
snprintf(cmd, sizeof(cmd), "fsck -a %s", dev);
|
||||
#endif
|
||||
_d("Running pass %d fsck command %s", pass, cmd);
|
||||
fsck_rc = run_interactive(cmd, "Checking filesystem %s", dev);
|
||||
/*
|
||||
* "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) {
|
||||
logit(LOG_CONSOLE | LOG_ALERT, "Failed fsck %s, attempting sulogin ...", dev);
|
||||
sulogin(1);
|
||||
}
|
||||
rc += fsck_rc;
|
||||
}
|
||||
|
||||
endfsent();
|
||||
endmntent(fp);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int fsck_all(void)
|
||||
{
|
||||
int pass, rc = 0;
|
||||
int rc = 0;
|
||||
#ifndef FAST_BOOT
|
||||
int pass;
|
||||
|
||||
for (pass = 1; pass < 10; pass++) {
|
||||
rc = fsck(pass);
|
||||
if (rc)
|
||||
break;
|
||||
}
|
||||
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifndef SYSROOT
|
||||
/* If / is not listed in fstab, or listed as 'ro', leave it alone */
|
||||
static int fs_readonly_root(struct fstab *fs)
|
||||
/* 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)
|
||||
{
|
||||
char *tok, *str;
|
||||
const char *msg = !fstype ? "MS_MOVE" : "mounting";
|
||||
int rc;
|
||||
|
||||
if (!fs)
|
||||
return 1;
|
||||
|
||||
str = fs->fs_mntops;
|
||||
while ((tok = strtok(str, ","))) {
|
||||
if (!strcmp(tok, "ro"))
|
||||
return 1;
|
||||
|
||||
str = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
rc = mount(src, tgt, fstype, flags, data);
|
||||
if (rc && errno != EBUSY)
|
||||
_pe("Failed %s %s on %s", msg, src, tgt);
|
||||
}
|
||||
|
||||
#ifndef SYSROOT
|
||||
static void fs_remount_root(int fsckerr)
|
||||
{
|
||||
struct fstab *fs;
|
||||
struct mntent *mnt;
|
||||
FILE *fp;
|
||||
|
||||
if (!setfsent())
|
||||
fp = setmntent(fstab, "r");
|
||||
if (!fp)
|
||||
return;
|
||||
|
||||
while ((fs = getfsent())) {
|
||||
if (!strcmp(fs->fs_file, "/"))
|
||||
while ((mnt = getmntent(fp))) {
|
||||
if (!strcmp(mnt->mnt_dir, "/"))
|
||||
break;
|
||||
}
|
||||
|
||||
if (fs_readonly_root(fs))
|
||||
/* If / is not listed in fstab, or listed as 'ro', leave it alone */
|
||||
if (!mnt || hasmntopt(mnt, "ro"))
|
||||
goto out;
|
||||
|
||||
if (fsckerr)
|
||||
@@ -190,7 +328,7 @@ static void fs_remount_root(int fsckerr)
|
||||
"Remounting / as read-write");
|
||||
|
||||
out:
|
||||
endfsent();
|
||||
endmntent(fp);
|
||||
}
|
||||
#else
|
||||
static void fs_remount_root(int fsckerr)
|
||||
@@ -199,8 +337,7 @@ static void fs_remount_root(int fsckerr)
|
||||
* XXX: Untested, in the initramfs age we should
|
||||
* probably use switch_root instead.
|
||||
*/
|
||||
if (mount(SYSROOT, "/", NULL, MS_MOVE, NULL))
|
||||
_pe("Failed %s / MS_MOVE");
|
||||
fs_mount(SYSROOT, "/", NULL, MS_MOVE, NULL);
|
||||
}
|
||||
#endif /* SYSROOT */
|
||||
|
||||
@@ -224,7 +361,7 @@ static void fs_finalize(void)
|
||||
*/
|
||||
if (!fismnt("/dev/shm")) {
|
||||
makedir("/dev/shm", 0777);
|
||||
mount("shm", "/dev/shm", "tmpfs", 0, "mode=0777");
|
||||
fs_mount("shm", "/dev/shm", "tmpfs", 0, "mode=0777");
|
||||
}
|
||||
|
||||
/* Modern systems use /dev/pts */
|
||||
@@ -242,7 +379,7 @@ static void fs_finalize(void)
|
||||
snprintf(opts, sizeof(opts), "gid=%d,mode=%d,ptmxmode=0666", gid, mode);
|
||||
|
||||
makedir("/dev/pts", 0755);
|
||||
mount("devpts", "/dev/pts", "devpts", MS_NOSUID | MS_NOEXEC, opts);
|
||||
fs_mount("devpts", "/dev/pts", "devpts", MS_NOSUID | MS_NOEXEC, opts);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -255,33 +392,81 @@ static void fs_finalize(void)
|
||||
* for /run (and optionally /run/lock).
|
||||
*/
|
||||
if (fisdir("/run") && !fismnt("/run")) {
|
||||
mount("tmpfs", "/run", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME, "mode=0755,size=10%");
|
||||
fs_mount("tmpfs", "/run", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME, "mode=0755,size=10%");
|
||||
|
||||
/* This prevents user DoS of /run by filling /run/lock at the expense of another tmpfs, max 5MiB */
|
||||
makedir("/run/lock", 1777);
|
||||
mount("tmpfs", "/run/lock", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME, "mode=0777,size=5252880");
|
||||
fs_mount("tmpfs", "/run/lock", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME, "mode=0777,size=5252880");
|
||||
}
|
||||
|
||||
/* Modern systems use tmpfs for /tmp */
|
||||
if (!fismnt("/tmp"))
|
||||
mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_NODEV, "mode=1777");
|
||||
fs_mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_NODEV, "mode=1777");
|
||||
}
|
||||
|
||||
static void fs_mount(void)
|
||||
static void fs_swapon(char *cmd, size_t len)
|
||||
{
|
||||
struct mntent *mnt;
|
||||
FILE *fp;
|
||||
|
||||
if (!whichp("swapon"))
|
||||
return;
|
||||
|
||||
fp = setmntent(fstab, "r");
|
||||
if (!fp)
|
||||
return;
|
||||
|
||||
while ((mnt = getmntent(fp))) {
|
||||
if (strcmp(mnt->mnt_type, MNTTYPE_SWAP))
|
||||
continue;
|
||||
|
||||
snprintf(cmd, len, "swapon %s", mnt->mnt_fsname);
|
||||
run_interactive(cmd, "Enabling swap %s", mnt->mnt_fsname);
|
||||
}
|
||||
|
||||
endmntent(fp);
|
||||
}
|
||||
|
||||
static void fs_mount_all(void)
|
||||
{
|
||||
char cmd[256] = "mount -na";
|
||||
|
||||
if (!fstab || !fexist(fstab)) {
|
||||
logit(LOG_CONSOLE | LOG_NOTICE, "%s system fstab %s, trying fallback ...",
|
||||
!fstab ? "Missing" : "Cannot find", fstab ?: "\b");
|
||||
fstab = FINIT_FSTAB;
|
||||
}
|
||||
if (!fstab || !fexist(fstab)) {
|
||||
logit(LOG_CONSOLE | LOG_EMERG, "%s system fstab %s, attempting sulogin ...",
|
||||
!fstab ? "Missing" : "Cannot find", fstab ?: "\b");
|
||||
sulogin(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Needed by fsck, both BusyBox and util-linux support this.
|
||||
* We leave it set in the env. for the benefit of any mount
|
||||
* helpers and other system tools that the user expects to
|
||||
* behave even if we've booted with a different fstab.
|
||||
*/
|
||||
setenv("FSTAB_FILE", fstab, 1);
|
||||
|
||||
if (!rescue)
|
||||
fs_remount_root(fsck_all());
|
||||
|
||||
_d("Root FS up, calling hooks ...");
|
||||
plugin_run_hooks(HOOK_ROOTFS_UP);
|
||||
|
||||
if (run_interactive("mount -na", "Mounting filesystems"))
|
||||
if (fstab && strcmp(fstab, "/etc/fstab"))
|
||||
snprintf(cmd, sizeof(cmd), "mount -na -T %s", fstab);
|
||||
|
||||
if (run_interactive(cmd, "Mounting filesystems from %s", fstab))
|
||||
plugin_run_hooks(HOOK_MOUNT_ERROR);
|
||||
|
||||
_d("Calling extra mount hook, after mount -a ...");
|
||||
plugin_run_hooks(HOOK_MOUNT_POST);
|
||||
|
||||
run("swapon -ea");
|
||||
_d("Enable any swap ...");
|
||||
fs_swapon(cmd, sizeof(cmd));
|
||||
|
||||
_d("Finalize, ensure common file systems are available ...");
|
||||
fs_finalize();
|
||||
@@ -291,9 +476,9 @@ static void fs_mount(void)
|
||||
* We need /proc for rs_remount_root() and conf_parse_cmdline(), /dev
|
||||
* for early multi-console, and /sys for the cgroups support. Any
|
||||
* occurrence of these file systems in /etc/fstab will replace these
|
||||
* mounts later in fs_mount()
|
||||
* mounts later in fs_mount_all()
|
||||
*
|
||||
* Ignore any mount errors with EBUSY, kernel likely alread mounted
|
||||
* Ignore any mount errors with EBUSY, kernel likely already mounted
|
||||
* the filesystem for us automatically, e.g., CONFIG_DEVTMPFS_MOUNT.
|
||||
*/
|
||||
static void fs_init(void)
|
||||
@@ -311,8 +496,6 @@ static void fs_init(void)
|
||||
umask(022);
|
||||
|
||||
for (i = 0; i < NELEMS(fs); i++) {
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* Check if already mounted, we may be running in a
|
||||
* container, or an initramfs ran before us. The
|
||||
@@ -322,9 +505,7 @@ static void fs_init(void)
|
||||
if (fismnt(fs[i].file))
|
||||
continue;
|
||||
|
||||
rc = mount(fs[i].spec, fs[i].file, fs[i].type, 0, NULL);
|
||||
if (rc && errno != EBUSY)
|
||||
_pe("Failed mounting %s on %s", fs[i].spec, fs[i].file);
|
||||
fs_mount(fs[i].spec, fs[i].file, fs[i].type, 0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,7 +555,7 @@ static void finalize(void *unused)
|
||||
static void crank_worker(void *unused)
|
||||
{
|
||||
/*
|
||||
* Initalize state machine and start all bootstrap tasks
|
||||
* Initialize state machine and start all bootstrap tasks
|
||||
* NOTE: no network available!
|
||||
*/
|
||||
sm_init(&sm);
|
||||
@@ -389,11 +570,12 @@ static void crank_worker(void *unused)
|
||||
*/
|
||||
static void bootstrap_worker(void *work)
|
||||
{
|
||||
static int cnt = 120;
|
||||
static struct wq final = {
|
||||
.cb = finalize,
|
||||
.delay = 10
|
||||
};
|
||||
static int cnt = 120;
|
||||
int level = cfglevel;
|
||||
|
||||
_d("Step all services ...");
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
@@ -418,11 +600,18 @@ static void bootstrap_worker(void *work)
|
||||
if (runparts && fisdir(runparts) && !rescue)
|
||||
run_parts(runparts, NULL);
|
||||
|
||||
|
||||
/*
|
||||
* Start all tasks/services in the configured runlevel
|
||||
* Start all tasks/services in the configured runlevel, or jump
|
||||
* into the runlevel selected from the command line.
|
||||
*/
|
||||
_d("Change to default runlevel(%d), starting all services ...", cfglevel);
|
||||
service_runlevel(cfglevel);
|
||||
if (cmdlevel) {
|
||||
_d("Runlevel %d requested from command line, starting all services ...", cmdlevel);
|
||||
level = cmdlevel;
|
||||
} else
|
||||
_d("Change to default runlevel(%d), starting all services ...", cfglevel);
|
||||
|
||||
service_runlevel(level);
|
||||
}
|
||||
|
||||
static int version(int rc)
|
||||
@@ -511,17 +700,17 @@ static int telinit(int argc, char *argv[])
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct wq crank = {
|
||||
struct wq crank_work = {
|
||||
.cb = crank_worker,
|
||||
.delay = 10
|
||||
};
|
||||
struct wq bootstrap = {
|
||||
struct wq bootstrap_work = {
|
||||
.cb = bootstrap_worker,
|
||||
.delay = 100
|
||||
};
|
||||
uev_ctx_t loop;
|
||||
|
||||
/* telinit or stand-alone process monitor */
|
||||
/* user calling telinit or init */
|
||||
if (getpid() != 1)
|
||||
return telinit(argc, argv);
|
||||
|
||||
@@ -532,17 +721,17 @@ int main(int argc, char *argv[])
|
||||
|
||||
/*
|
||||
* Parse /proc/cmdline (debug, rescue, console=, etc.)
|
||||
* Also calls log_init() to set correct log level
|
||||
*/
|
||||
conf_parse_cmdline(argc, argv);
|
||||
|
||||
/*
|
||||
* Figure out system console(s)
|
||||
* Figure out system console(s) and call log_init() to set
|
||||
* correct log level, possibly finit.debug enabled.
|
||||
*/
|
||||
console_init();
|
||||
|
||||
/*
|
||||
* Initalize event context.
|
||||
* Initialize event context.
|
||||
*/
|
||||
uev_init1(&loop, 1);
|
||||
ctx = &loop;
|
||||
@@ -550,10 +739,7 @@ int main(int argc, char *argv[])
|
||||
/*
|
||||
* Set PATH, SHELL, and PWD early to something sane
|
||||
*/
|
||||
setenv("PATH", _PATH_STDPATH, 1);
|
||||
setenv("SHELL", _PATH_BSHELL, 1);
|
||||
setenv("LOGNAME", "root", 1);
|
||||
setenv("USER", "root", 1);
|
||||
conf_reset_env();
|
||||
|
||||
if (chdir("/"))
|
||||
_pe("Failed cd /");
|
||||
@@ -561,21 +747,8 @@ int main(int argc, char *argv[])
|
||||
/*
|
||||
* In case of emergency.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (rescue)
|
||||
rescue = sulogin(0);
|
||||
|
||||
/*
|
||||
* Load plugins early, the first hook is in banner(), so we
|
||||
@@ -589,6 +762,11 @@ int main(int argc, char *argv[])
|
||||
enable_progress(1); /* Allow progress, if enabled */
|
||||
banner();
|
||||
|
||||
if (osheading)
|
||||
logit(LOG_CONSOLE | LOG_NOTICE, "%s, entering runlevel S", osheading);
|
||||
else
|
||||
logit(LOG_CONSOLE | LOG_NOTICE, "Entering runlevel S");
|
||||
|
||||
/*
|
||||
* Initial setup of signals, ignore all until we're up.
|
||||
*/
|
||||
@@ -599,14 +777,19 @@ int main(int argc, char *argv[])
|
||||
*/
|
||||
cgroup_init(&loop);
|
||||
|
||||
/* Check and mount filesystems. */
|
||||
fs_mount();
|
||||
/*
|
||||
* Check custom fstab from cmdline, including fallback, then run
|
||||
* fsck before mounting all filesystems, on error call sulogin.
|
||||
*/
|
||||
fs_mount_all();
|
||||
|
||||
/* Bootstrap conditions, needed for hooks */
|
||||
cond_init();
|
||||
|
||||
/* Emit conditions for early hooks that ran before the
|
||||
* condition system was initialized in case anyone . */
|
||||
/*
|
||||
* Emit conditions for early hooks that ran before the condition
|
||||
* system was initialized in case anyone.
|
||||
*/
|
||||
cond_set_oneshot(plugin_hook_str(HOOK_BANNER));
|
||||
cond_set_oneshot(plugin_hook_str(HOOK_ROOTFS_UP));
|
||||
|
||||
@@ -620,7 +803,7 @@ int main(int argc, char *argv[])
|
||||
*/
|
||||
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");
|
||||
wdog = svc_find("watchdog", "finit");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -645,10 +828,15 @@ int main(int argc, char *argv[])
|
||||
api_init(&loop);
|
||||
|
||||
_d("Starting the big state machine ...");
|
||||
schedule_work(&crank);
|
||||
schedule_work(&crank_work);
|
||||
|
||||
_d("Starting bootstrap finalize timer ...");
|
||||
schedule_work(&bootstrap);
|
||||
schedule_work(&bootstrap_work);
|
||||
|
||||
/*
|
||||
* Background service tasks
|
||||
*/
|
||||
service_init();
|
||||
|
||||
/*
|
||||
* Enter main loop to monitor /dev/initctl and services
|
||||
|
||||
+12
-3
@@ -1,7 +1,7 @@
|
||||
/* Finit - Fast /sbin/init replacement w/ I/O, hook & service plugins
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2022 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
|
||||
@@ -34,7 +34,11 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <lite/lite.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
#include <uev/uev.h>
|
||||
|
||||
/* just in case */
|
||||
@@ -91,6 +95,7 @@
|
||||
#define INIT_CMD_SVC_QUERY 130
|
||||
#define INIT_CMD_SVC_FIND 131
|
||||
#define INIT_CMD_SVC_FIND_BYC 132
|
||||
#define INIT_CMD_SIGNAL 133
|
||||
#define INIT_CMD_NACK 254
|
||||
#define INIT_CMD_ACK 255
|
||||
|
||||
@@ -105,16 +110,20 @@ struct init_request {
|
||||
|
||||
extern int runlevel;
|
||||
extern int cfglevel;
|
||||
extern int cmdlevel;
|
||||
extern int prevlevel;
|
||||
extern int debug;
|
||||
extern int rescue;
|
||||
extern int single;
|
||||
extern int bootstrap;
|
||||
extern char *rcsd;
|
||||
extern int kerndebug;
|
||||
extern char *fstab;
|
||||
extern char *sdown;
|
||||
extern char *network;
|
||||
extern char *hostname;
|
||||
extern char *rcsd;
|
||||
extern char *runparts;
|
||||
extern char *osheading;
|
||||
extern uev_ctx_t *ctx;
|
||||
|
||||
#endif /* FINIT_H_ */
|
||||
|
||||
+27
-7
@@ -1,6 +1,6 @@
|
||||
/* Initialize and serve a login terminal
|
||||
*
|
||||
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -21,10 +21,11 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "config.h" /* Generated by configure script */
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h> /* LOGIN_NAME_MAX */
|
||||
#include <paths.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
@@ -33,6 +34,7 @@
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
|
||||
#include <termios.h>
|
||||
#include <unistd.h> /* sysconf() */
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
@@ -42,6 +44,12 @@
|
||||
#define _PATH_LOGIN "/bin/login"
|
||||
#endif
|
||||
|
||||
#ifndef LOGIN_NAME_MIN
|
||||
#define LOGIN_NAME_MIN 64
|
||||
#endif
|
||||
|
||||
static long logname_len = 32; /* useradd(1) limit at 32 chars */
|
||||
|
||||
/*
|
||||
* Read one character from stdin.
|
||||
*/
|
||||
@@ -196,8 +204,9 @@ static int do_login(char *name)
|
||||
|
||||
static int getty(char *tty, speed_t speed, char *term, char *user)
|
||||
{
|
||||
const char cln[] = "\r\e[2K\n";
|
||||
char name[33]; /* useradd(1) limit at 32 chars */
|
||||
const char cln[] = "\r\e[K\n";
|
||||
char name[logname_len + 1]; /* +1 for NUL termination */
|
||||
pid_t sid;
|
||||
|
||||
/*
|
||||
* Clean up tty name.
|
||||
@@ -214,13 +223,18 @@ static int getty(char *tty, speed_t speed, char *term, char *user)
|
||||
restart:
|
||||
stty(STDIN_FILENO, speed);
|
||||
if (!user) {
|
||||
if (get_logname(tty, name, sizeof(name))) {
|
||||
sleep(5);
|
||||
if (get_logname(tty, name, sizeof(name)))
|
||||
goto restart;
|
||||
}
|
||||
} else
|
||||
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])
|
||||
setenv("TERM", term, 1);
|
||||
|
||||
@@ -257,6 +271,12 @@ int main(int argc, char *argv[])
|
||||
if (optind < argc)
|
||||
term = argv[optind++];
|
||||
|
||||
logname_len = sysconf(_SC_LOGIN_NAME_MAX);
|
||||
if (logname_len == -1i)
|
||||
logname_len = LOGIN_NAME_MAX;
|
||||
if (logname_len < LOGIN_NAME_MIN)
|
||||
logname_len = LOGIN_NAME_MIN;
|
||||
|
||||
return getty(tty, atoi(speed), term, NULL);
|
||||
}
|
||||
|
||||
|
||||
+128
-94
@@ -1,7 +1,7 @@
|
||||
/* Misc. utility functions for finit and its plugins
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -22,6 +22,8 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h" /* Generated by configure script */
|
||||
|
||||
#include <ctype.h> /* isblank() */
|
||||
#include <errno.h>
|
||||
#include <grp.h>
|
||||
@@ -30,12 +32,18 @@
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdarg.h>
|
||||
#include <sysexits.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <lite/lite.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "private.h"
|
||||
#include "sig.h"
|
||||
#include "util.h"
|
||||
#include "utmp-api.h"
|
||||
|
||||
@@ -53,7 +61,7 @@ static pstyle_t progress_style = PROGRESS_DEFAULT;
|
||||
#define STATUS_CLASS { \
|
||||
CHOOSE(" OK ", " OK ", "\e[1;32m"), /* Green */ \
|
||||
CHOOSE("FAIL", "FAIL", "\e[1;31m"), /* Red */ \
|
||||
CHOOSE("WARN", "WARN", "\e[1;31m"), /* Red */ \
|
||||
CHOOSE("WARN", "WARN", "\e[1;33m"), /* Yellow */ \
|
||||
CHOOSE(" \\/ ", " ⋯ ", "\e[1;33m"), /* Yellow */ \
|
||||
}
|
||||
|
||||
@@ -75,7 +83,7 @@ char *console(void)
|
||||
|
||||
void console_init(void)
|
||||
{
|
||||
ttinit();
|
||||
log_init();
|
||||
}
|
||||
|
||||
ssize_t cprintf(const char *fmt, ...)
|
||||
@@ -94,6 +102,17 @@ ssize_t cprintf(const char *fmt, ...)
|
||||
return size;
|
||||
}
|
||||
|
||||
void tabstospaces(char *line)
|
||||
{
|
||||
if (!line)
|
||||
return;
|
||||
|
||||
for (int i = 0; line[i]; i++) {
|
||||
if (line[i] == '\t')
|
||||
line[i] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
char *strip_line(char *line)
|
||||
{
|
||||
char *ptr;
|
||||
@@ -124,6 +143,49 @@ void show_progress(pstyle_t 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
|
||||
* accounting for unicode characters as only one screen byte wide
|
||||
@@ -180,7 +242,7 @@ void print_banner(const char *heading)
|
||||
return;
|
||||
|
||||
buf[0] = 0;
|
||||
strlcat(buf, "\r\e[2K", sizeof(buf));
|
||||
strlcat(buf, "\r\e[K", sizeof(buf));
|
||||
|
||||
if (progress_style == PROGRESS_CLASSIC) {
|
||||
strlcat(buf, "\e[1m", sizeof(buf));
|
||||
@@ -265,7 +327,7 @@ void printv(const char *fmt, va_list ap)
|
||||
if (progress_style == PROGRESS_CLASSIC)
|
||||
cprintf("\r%s ", pad(buf, sizeof(buf), ".", sizeof(buf)));
|
||||
else
|
||||
cprintf("\r\e[2K%s%s", status(3), buf);
|
||||
cprintf("\r\e[K%s%s", status(3), buf);
|
||||
}
|
||||
|
||||
void print(int rc, const char *fmt, ...)
|
||||
@@ -446,27 +508,52 @@ void networking(int updown)
|
||||
|
||||
/* Debian/Ubuntu/Busybox/RH/Suse */
|
||||
if (!whichp("ifup"))
|
||||
goto done;
|
||||
goto fallback;
|
||||
|
||||
if (fexist("/etc/network/interfaces")) {
|
||||
pid_t pid;
|
||||
|
||||
pid = fork();
|
||||
if (pid == 0) {
|
||||
int rc = EX_OSERR;
|
||||
const char *cmd;
|
||||
FILE *pp;
|
||||
|
||||
setsid();
|
||||
sig_unblock();
|
||||
|
||||
if (updown)
|
||||
run("ifup -a");
|
||||
cmd = "ifup -a 2>&1";
|
||||
else if (whichp("ifquery"))
|
||||
/* Regular ifodwn supports --force but not -f */
|
||||
cmd = "ifdown -a --force 2>&1";
|
||||
else
|
||||
run("ifdown -a");
|
||||
_exit(0);
|
||||
/* Busybox ifdown support -f, but not --force */
|
||||
cmd = "ifdown -a -f 2>&1";
|
||||
|
||||
pp = popen(cmd, "r");
|
||||
if (pp) {
|
||||
char buf[256];
|
||||
|
||||
while (fgets(buf, sizeof(buf), pp))
|
||||
logit(LOG_NOTICE, "network: %s", buf);
|
||||
|
||||
rc = pclose(pp);
|
||||
}
|
||||
|
||||
_exit(rc);
|
||||
}
|
||||
cgroup_service("network", pid, NULL);
|
||||
print(pid > 0 ? 0 : 1, "%s network interfaces ...",
|
||||
updown ? "Bringing up" : "Taking down");
|
||||
|
||||
print(pid > 0 ? 0 : 1, "%s networking", updown ? "Starting" : "Stopping");
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
fallback:
|
||||
/* Fall back to bring up at least loopback */
|
||||
ifconfig("lo", "127.0.0.1", "255.0.0.0", updown);
|
||||
done:
|
||||
|
||||
/* Hooks that rely on loopback, or basic networking being up. */
|
||||
if (updown) {
|
||||
@@ -475,97 +562,44 @@ done:
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef HAVE_GETFSENT
|
||||
static lfile_t *fstab = NULL;
|
||||
|
||||
int setfsent(void)
|
||||
/*
|
||||
* Very basic, and incomplete, check if we're running in a container.
|
||||
*/
|
||||
int in_container(void)
|
||||
{
|
||||
if (fstab)
|
||||
lfclose(fstab);
|
||||
const char *containers[] = {
|
||||
"lxc",
|
||||
"docker",
|
||||
"kubepod",
|
||||
"unshare"
|
||||
};
|
||||
const char *files[] = {
|
||||
"/run/.containerenv",
|
||||
"/.dockerenv"
|
||||
};
|
||||
static int incont = -1;
|
||||
size_t i;
|
||||
char *c;
|
||||
|
||||
fstab = lfopen("/etc/fstab", " \t\n");
|
||||
if (!fstab)
|
||||
return 0;
|
||||
if (incont > 0)
|
||||
return incont;
|
||||
|
||||
return 1;
|
||||
}
|
||||
c = getenv("container");
|
||||
if (c) {
|
||||
for (i = 0; i < NELEMS(containers); i++) {
|
||||
if (!strcmp(containers[i], c))
|
||||
return incont = 1;
|
||||
}
|
||||
}
|
||||
|
||||
struct fstab *getfsent(void)
|
||||
{
|
||||
static struct fstab fs;
|
||||
|
||||
fs.fs_spec = lftok(fstab);
|
||||
if (fs.fs_spec == NULL)
|
||||
return NULL;
|
||||
|
||||
fs.fs_file = lftok(fstab);
|
||||
fs.fs_vfstype = lftok(fstab);
|
||||
fs.fs_mntops = lftok(fstab);
|
||||
fs.fs_type = "rw";
|
||||
fs.fs_freq = atoi(lftok(fstab) ?: "0");
|
||||
fs.fs_passno = atoi(lftok(fstab) ?: "0");
|
||||
|
||||
return &fs;
|
||||
}
|
||||
|
||||
void endfsent(void)
|
||||
{
|
||||
if (fstab)
|
||||
lfclose(fstab);
|
||||
|
||||
fstab = NULL;
|
||||
}
|
||||
#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, ",");
|
||||
for (i = 0; i < NELEMS(files); i++) {
|
||||
if (!access(files[i], F_OK))
|
||||
return incont = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ismnt(char *file, char *dir, char *mode)
|
||||
{
|
||||
struct mntent *mnt;
|
||||
int found = 0;
|
||||
FILE *fp;
|
||||
|
||||
fp = setmntent(file, "r");
|
||||
if (!fp)
|
||||
return 0; /* Dunno, maybe not */
|
||||
|
||||
while ((mnt = getmntent(fp))) {
|
||||
if (!strcmp(mnt->mnt_dir, dir)) {
|
||||
if (mode) {
|
||||
if (hasopt(mnt->mnt_opts, mode))
|
||||
found = 1;
|
||||
} else
|
||||
found = 1;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
endmntent(fp);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/* Requires /proc to be mounted */
|
||||
int fismnt(char *dir)
|
||||
{
|
||||
return ismnt("/proc/mounts", dir, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
|
||||
+14
-27
@@ -1,7 +1,7 @@
|
||||
/* Misc. utility functions and C-library extensions for finit and its plugins
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2022 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
|
||||
@@ -25,14 +25,16 @@
|
||||
#ifndef FINIT_HELPERS_H_
|
||||
#define FINIT_HELPERS_H_
|
||||
|
||||
#include <mntent.h>
|
||||
#include <sched.h> /* sched_yield() */
|
||||
#include <stdarg.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
|
||||
#include <termios.h>
|
||||
#include <lite/lite.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
#include "log.h"
|
||||
|
||||
#define PROGRESS_DEFAULT PROGRESS_MODERN
|
||||
@@ -43,37 +45,24 @@ typedef enum {
|
||||
PROGRESS_MODERN,
|
||||
} pstyle_t;
|
||||
|
||||
#ifndef HAVE_GETFSENT
|
||||
struct fstab {
|
||||
char *fs_spec; /* block device name */
|
||||
char *fs_file; /* mount point */
|
||||
char *fs_vfstype; /* file-system type */
|
||||
char *fs_mntops; /* mount options */
|
||||
const char *fs_type; /* rw/rq/ro/sw/xx option */
|
||||
int fs_freq; /* dump frequency, in days */
|
||||
int fs_passno; /* pass number on parallel dump */
|
||||
};
|
||||
|
||||
int setfsent (void);
|
||||
void endfsent (void);
|
||||
struct fstab *getfsent (void);
|
||||
#endif /* HAVE_GETFSENT */
|
||||
|
||||
char *console (void);
|
||||
void console_init (void);
|
||||
ssize_t cprintf (const char *fmt, ...);
|
||||
ssize_t cprintf (const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
||||
|
||||
void tabstospaces (char *line);
|
||||
char *strip_line (char *line);
|
||||
|
||||
void enable_progress (int onoff);
|
||||
void show_progress (pstyle_t style);
|
||||
|
||||
char *release_heading (void);
|
||||
|
||||
speed_t stty_parse_speed(char *baud);
|
||||
void stty (int fd, speed_t speed);
|
||||
|
||||
void print_banner (const char *heading);
|
||||
void printv (const char *fmt, va_list ap);
|
||||
void print (int action, const char *fmt, ...);
|
||||
void print (int action, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
void print_desc (char *action, char *desc);
|
||||
int print_result (int fail);
|
||||
|
||||
@@ -87,10 +76,11 @@ int mksubsys (const char *dir, mode_t mode, char *user, char *group);
|
||||
|
||||
void set_hostname (char **hostname);
|
||||
void networking (int updown);
|
||||
int in_container (void);
|
||||
|
||||
int complete (char *cmd, int pid);
|
||||
int run (char *cmd);
|
||||
int run_interactive (char *cmd, char *fmt, ...);
|
||||
int run (char *cmd, char *log);
|
||||
int run_interactive (char *cmd, char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
int exec_runtask (char *cmd, char *args[]);
|
||||
pid_t run_getty (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[]);
|
||||
@@ -124,9 +114,6 @@ static inline int dprint(int fd, const char *s, size_t len)
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ismnt (char *file, char *dir, char *mode);
|
||||
int fismnt (char *dir);
|
||||
|
||||
#endif /* FINIT_HELPERS_H_ */
|
||||
|
||||
/**
|
||||
|
||||
+308
-134
@@ -1,6 +1,6 @@
|
||||
/* New client tool, replaces old /dev/initctl API and telinit tool
|
||||
*
|
||||
* Copyright (c) 2015-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2015-2022 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
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <err.h>
|
||||
#include <ftw.h>
|
||||
#include <ctype.h>
|
||||
#include <getopt.h>
|
||||
@@ -33,8 +32,13 @@
|
||||
#include <time.h>
|
||||
#include <utmp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <lite/lite.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
#include "initctl.h"
|
||||
#include "client.h"
|
||||
#include "cond.h"
|
||||
#include "serv.h"
|
||||
@@ -47,6 +51,8 @@ struct cmd {
|
||||
char *cmd;
|
||||
struct cmd *ctx;
|
||||
int (*cb)(char *arg);
|
||||
int *cond;
|
||||
int (*cb_multiarg)(int argc, char **argv);
|
||||
};
|
||||
|
||||
int icreate = 0;
|
||||
@@ -58,6 +64,9 @@ int verbose = 0;
|
||||
int plain = 0;
|
||||
int quiet = 0;
|
||||
int runlevel = 0;
|
||||
int cgrp = 0;
|
||||
int utmp = 0;
|
||||
|
||||
int iw, pw;
|
||||
|
||||
extern int reboot_main(int argc, char *argv[]);
|
||||
@@ -145,17 +154,40 @@ static int toggle_debug(char *arg)
|
||||
return client_send(&rq, sizeof(rq));
|
||||
}
|
||||
|
||||
static int do_log(char *svc)
|
||||
static int do_log(svc_t *svc, char *tail)
|
||||
{
|
||||
char *logfile = "/var/log/syslog";
|
||||
const char *logfile = "/var/log/syslog";
|
||||
pid_t pid;
|
||||
char *nm;
|
||||
|
||||
if (!svc || !svc[0])
|
||||
svc = "finit";
|
||||
if (svc) {
|
||||
nm = svc_ident(svc, NULL, 0);
|
||||
pid = svc->pid;
|
||||
} else {
|
||||
nm = "finit";
|
||||
pid = 1;
|
||||
}
|
||||
|
||||
if (!fexist(logfile))
|
||||
if (!fexist(logfile)) {
|
||||
logfile = "/var/log/messages";
|
||||
if (!fexist(logfile))
|
||||
return 0; /* bail out, maybe in container */
|
||||
}
|
||||
|
||||
return systemf("cat %s | grep %s | tail -10", logfile, svc);
|
||||
return systemf("cat %s | grep '\\[%d\\]\\|%s' %s", logfile, pid, nm, tail);
|
||||
}
|
||||
|
||||
static int show_log(char *arg)
|
||||
{
|
||||
svc_t *svc = NULL;
|
||||
|
||||
if (arg) {
|
||||
svc = client_svc_find(arg);
|
||||
if (!svc)
|
||||
ERRX(69, "no such task or service(s): %s", arg);
|
||||
}
|
||||
|
||||
return do_log(svc, "");
|
||||
}
|
||||
|
||||
static int do_runlevel(char *arg)
|
||||
@@ -167,11 +199,11 @@ static int do_runlevel(char *arg)
|
||||
|
||||
if (!arg) {
|
||||
int prevlevel = 0;
|
||||
int runlevel;
|
||||
int currlevel;
|
||||
char prev;
|
||||
|
||||
runlevel = runlevel_get(&prevlevel);
|
||||
if (255 == runlevel) {
|
||||
currlevel = runlevel_get(&prevlevel);
|
||||
if (255 == currlevel) {
|
||||
printf("unknown\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -180,7 +212,7 @@ static int do_runlevel(char *arg)
|
||||
if (prev <= '0' || prev > '9')
|
||||
prev = 'N';
|
||||
|
||||
printf("%c %d\n", prev , runlevel);
|
||||
printf("%c %d\n", prev , currlevel);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -217,20 +249,11 @@ static int do_startstop(int cmd, char *arg)
|
||||
};
|
||||
|
||||
if (!arg || !arg[0])
|
||||
errx(1, "missing argument to %s", (cmd == INIT_CMD_START_SVC
|
||||
? "start"
|
||||
: (cmd == INIT_CMD_STOP_SVC
|
||||
? "stop"
|
||||
: "restart")));
|
||||
ERRX(2, "missing command argument");
|
||||
|
||||
strlcpy(rq.data, arg, sizeof(rq.data));
|
||||
if (client_send(&rq, sizeof(rq))) {
|
||||
fprintf(stderr, "No such task or service(s): %s\n\n", arg);
|
||||
fprintf(stderr, "Usage: initctl %s <NAME>[:ID]\n",
|
||||
cmd == INIT_CMD_START_SVC ? "start" :
|
||||
(cmd == INIT_CMD_STOP_SVC ? "stop" : "restart"));
|
||||
return 1;
|
||||
}
|
||||
if (client_send(&rq, sizeof(rq)))
|
||||
ERRX(69, "no such task or service(s): %s", arg);
|
||||
|
||||
return do_svc(cmd, arg);
|
||||
}
|
||||
@@ -262,11 +285,54 @@ static int do_restart(char *arg)
|
||||
}
|
||||
|
||||
if (retries == 0)
|
||||
errx(1, "Failed stopping %s (restart)", arg);
|
||||
ERRX(7, "failed stopping %s (restart)", arg);
|
||||
|
||||
return do_startstop(INIT_CMD_RESTART_SVC, arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* do_signal - Ask finit to send a signal to a service.
|
||||
* @argv: must point to an array of strings, containing a service
|
||||
* and signal name, in that order.
|
||||
* @argc: must be 2.
|
||||
*
|
||||
* A signal can be a complete signal name such as "SIGHUP", or
|
||||
* it can be the shortest unique name, such as "HUP" (no SIG prefix).
|
||||
* It can also be a raw signal number, such as "9" (SIGKILL).
|
||||
*/
|
||||
int do_signal(int argc, char *argv[])
|
||||
{
|
||||
struct init_request rq = {
|
||||
.magic = INIT_MAGIC,
|
||||
.cmd = INIT_CMD_SVC_QUERY
|
||||
};
|
||||
int signo;
|
||||
|
||||
if (argc != 2)
|
||||
ERRX(2, "invalid number of arguments to signal");
|
||||
|
||||
strlcpy(rq.data, argv[0], sizeof(rq.data));
|
||||
if (client_send(&rq, sizeof(rq)))
|
||||
ERRX(69, "no such task or service(s): %s", argv[0]);
|
||||
|
||||
signo = str2sig(argv[1]);
|
||||
if (signo == -1) {
|
||||
const char *errstr = NULL;
|
||||
|
||||
signo = (int)strtonum(argv[1], 1, 31, &errstr);
|
||||
if (errstr)
|
||||
ERRX(65, "%s signal: %s", errstr, argv[1]);
|
||||
}
|
||||
|
||||
/* Reuse runlevel for signal number. */
|
||||
rq.magic = INIT_MAGIC;
|
||||
rq.cmd = INIT_CMD_SIGNAL;
|
||||
rq.runlevel = signo;
|
||||
strlcpy(rq.data, argv[0], sizeof(rq.data));
|
||||
|
||||
return client_send(&rq, sizeof(rq));
|
||||
}
|
||||
|
||||
static int dump_one_cond(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftwbuf)
|
||||
{
|
||||
const char *cond, *asserted;
|
||||
@@ -284,7 +350,7 @@ static int dump_one_cond(const char *fpath, const struct stat *sb, int tflag, st
|
||||
if (strncmp("pid/", cond, 4) == 0) {
|
||||
svc_t *svc;
|
||||
|
||||
svc= client_svc_find_by_cond(cond);
|
||||
svc = client_svc_find_by_cond(cond);
|
||||
if (!svc) {
|
||||
nm = "unknown";
|
||||
pid = 0;
|
||||
@@ -317,44 +383,62 @@ static int do_cond_dump(char *arg)
|
||||
}
|
||||
|
||||
if (nftw(_PATH_COND, dump_one_cond, 20, 0) == -1) {
|
||||
warnx("Failed parsing %s", _PATH_COND);
|
||||
WARNX("Failed parsing %s", _PATH_COND);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_cond_act(char *arg, int creat)
|
||||
typedef enum { COND_CLR, COND_SET, COND_GET } condop_t;
|
||||
|
||||
static int do_cond_act(char *arg, condop_t op)
|
||||
{
|
||||
char oneshot[256];
|
||||
char path[256];
|
||||
size_t off;
|
||||
|
||||
if (arg && strncmp(arg, COND_USR, strlen(COND_USR)) == 0)
|
||||
arg += strlen(COND_USR);
|
||||
|
||||
if (!arg || !arg[0])
|
||||
errx(1, "Invalid condition (empty)");
|
||||
if (strchr(arg, '/'))
|
||||
errx(1, "Invalid condition (slashes)");
|
||||
if (strchr(arg, '.'))
|
||||
errx(1, "Invalid condition (periods)");
|
||||
ERRX(2, "Invalid condition (empty)");
|
||||
|
||||
snprintf(oneshot, sizeof(oneshot), _PATH_CONDUSR "%s", arg);
|
||||
/* allowed to read any condition, but not set/clr */
|
||||
if (op != COND_GET) {
|
||||
if (strchr(arg, '/'))
|
||||
ERRX(2, "Invalid condition (slashes)");
|
||||
if (strchr(arg, '.'))
|
||||
ERRX(2, "Invalid condition (periods)");
|
||||
}
|
||||
|
||||
if (strchr(arg, '/'))
|
||||
snprintf(path, sizeof(path), _PATH_COND "%s", arg);
|
||||
else
|
||||
snprintf(path, sizeof(path), _PATH_CONDUSR "%s", arg);
|
||||
off = strlen(_PATH_COND);
|
||||
|
||||
if (creat) {
|
||||
if (symlink(_PATH_RECONF, oneshot) && errno != EEXIST)
|
||||
err(1, "Failed asserting condition <%s>", &oneshot[off]);
|
||||
} else {
|
||||
if (erase(oneshot) && errno != ENOENT)
|
||||
err(1, "Failed deasserting condition <%s>", &oneshot[off]);
|
||||
switch (op) {
|
||||
case COND_GET:
|
||||
off = !fexist(path);
|
||||
if (verbose)
|
||||
puts(off ? "off" : "on");
|
||||
return off;
|
||||
case COND_SET:
|
||||
if (symlink(_PATH_RECONF, path) && errno != EEXIST)
|
||||
ERR(73, "Failed asserting condition <%s>", &path[off]);
|
||||
break;
|
||||
case COND_CLR:
|
||||
if (erase(path) && errno != ENOENT)
|
||||
ERR(73, "Failed deasserting condition <%s>", &path[off]);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_cond_set(char *arg) { return do_cond_act(arg, 1); }
|
||||
static int do_cond_clr(char *arg) { return do_cond_act(arg, 0); }
|
||||
static int do_cond_get(char *arg) { return do_cond_act(arg, COND_GET); }
|
||||
static int do_cond_set(char *arg) { return do_cond_act(arg, COND_SET); }
|
||||
static int do_cond_clr(char *arg) { return do_cond_act(arg, COND_CLR); }
|
||||
|
||||
static char *svc_cond(svc_t *svc, char *buf, size_t len)
|
||||
{
|
||||
@@ -468,15 +552,12 @@ int do_suspend (char *arg) { return do_cmd(INIT_CMD_SUSPEND); }
|
||||
|
||||
int utmp_show(char *file)
|
||||
{
|
||||
static int once = 0;
|
||||
struct tm *sectm;
|
||||
struct utmp *ut;
|
||||
time_t sec;
|
||||
|
||||
int pid;
|
||||
char id[sizeof(ut->ut_id) + 1], user[sizeof(ut->ut_user) + 1], when[80];
|
||||
|
||||
if (heading) {
|
||||
static int once = 0;
|
||||
|
||||
print_header("%s%s ", once ? "\n" : "", file);
|
||||
once++;
|
||||
}
|
||||
@@ -484,7 +565,12 @@ int utmp_show(char *file)
|
||||
|
||||
setutent();
|
||||
while ((ut = getutent())) {
|
||||
char user[sizeof(ut->ut_user) + 1];
|
||||
char id[sizeof(ut->ut_id) + 1];
|
||||
struct tm *sectm;
|
||||
char when[80];
|
||||
char addr[64];
|
||||
int pid;
|
||||
|
||||
strlcpy(id, ut->ut_id, sizeof(id));
|
||||
strlcpy(user, ut->ut_user, sizeof(user));
|
||||
@@ -509,7 +595,7 @@ int utmp_show(char *file)
|
||||
|
||||
static int do_utmp(char *file)
|
||||
{
|
||||
if (!has_utmp())
|
||||
if (!utmp)
|
||||
return 1;
|
||||
|
||||
if (fexist(file))
|
||||
@@ -538,7 +624,7 @@ static int show_version(char *arg)
|
||||
* Pointer to string on the form [2345], may be up to 12 chars long,
|
||||
* plus escape sequences for highlighting current runlevel.
|
||||
*/
|
||||
char *runlevel_string(int runlevel, int levels)
|
||||
char *runlevel_string(int currlevel, int levels)
|
||||
{
|
||||
int i, pos = 1;
|
||||
static char lvl[21];
|
||||
@@ -548,7 +634,7 @@ char *runlevel_string(int runlevel, int levels)
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
if (ISSET(levels, i)) {
|
||||
if (!plain && runlevel == i)
|
||||
if (!plain && currlevel == i)
|
||||
pos = strlcat(lvl, "\e[1m", sizeof(lvl));
|
||||
|
||||
if (i == 0)
|
||||
@@ -556,7 +642,7 @@ char *runlevel_string(int runlevel, int levels)
|
||||
else
|
||||
lvl[pos++] = '0' + i;
|
||||
|
||||
if (!plain && runlevel == i)
|
||||
if (!plain && currlevel == i)
|
||||
pos = strlcat(lvl, "\e[0m", sizeof(lvl));
|
||||
} else {
|
||||
lvl[pos++] = '-';
|
||||
@@ -595,6 +681,13 @@ static char *svc_command(svc_t *svc, char *buf, size_t len)
|
||||
strlcat(buf, svc->args[i], len);
|
||||
}
|
||||
|
||||
if (svc_is_sysv(svc)) {
|
||||
char *cmd = svc->state == SVC_HALTED_STATE ? "stop" : "start";
|
||||
|
||||
strlcat(buf, " ", len);
|
||||
strlcat(buf, cmd, len);
|
||||
}
|
||||
|
||||
strlcat(buf, bold ? "\e[0m" : "", len);
|
||||
|
||||
return buf;
|
||||
@@ -699,28 +792,47 @@ static int show_status(char *arg)
|
||||
{
|
||||
char ident[MAX_IDENT_LEN];
|
||||
char buf[512];
|
||||
int num = 0;
|
||||
svc_t *svc;
|
||||
|
||||
runlevel = runlevel_get(NULL);
|
||||
|
||||
if (arg && arg[0]) {
|
||||
while (arg && arg[0]) {
|
||||
long now = jiffies();
|
||||
char uptm[42] = "N/A";
|
||||
char grbuf[128];
|
||||
char path[256];
|
||||
struct cg *cg;
|
||||
char *group;
|
||||
char *pidfn = NULL;
|
||||
int exact = 0;
|
||||
|
||||
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
|
||||
svc_ident(svc, ident, sizeof(ident));
|
||||
if (string_compare(ident, arg))
|
||||
num++;
|
||||
if (string_case_compare(ident, arg))
|
||||
exact++;
|
||||
}
|
||||
|
||||
if (num > 1 && !exact)
|
||||
break;
|
||||
|
||||
svc = client_svc_find(arg);
|
||||
if (!svc)
|
||||
return 255;
|
||||
ERRX(69, "no such task or service(s): %s", arg);
|
||||
|
||||
if (quiet)
|
||||
return svc->state != SVC_RUNNING_STATE;
|
||||
if (quiet) {
|
||||
if (svc_is_runtask(svc))
|
||||
if (svc->started)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
else
|
||||
return svc->state != SVC_RUNNING_STATE;
|
||||
}
|
||||
|
||||
group = pid_cgroup(svc->pid, grbuf, sizeof(grbuf));
|
||||
snprintf(path, sizeof(path), "%s/%s", FINIT_CGPATH, group);
|
||||
cg = cg_conf(path);
|
||||
pidfn = svc->pidfile;
|
||||
if (pidfn[0] == '!')
|
||||
pidfn++;
|
||||
else if (pidfn[0] == 0)
|
||||
pidfn = "none";
|
||||
|
||||
printf(" Status : %s\n", status(svc, 1));
|
||||
printf(" Identity : %s\n", svc_ident(svc, ident, sizeof(ident)));
|
||||
@@ -729,22 +841,35 @@ static int show_status(char *arg)
|
||||
printf("Environment : %s\n", svc_environ(svc, buf, sizeof(buf)));
|
||||
printf("Condition(s): %s\n", svc_cond(svc, buf, sizeof(buf)));
|
||||
printf(" Command : %s\n", svc_command(svc, buf, sizeof(buf)));
|
||||
printf(" PID file : %s\n", svc->pidfile);
|
||||
printf(" PID file : %s\n", pidfn);
|
||||
printf(" PID : %d\n", svc->pid);
|
||||
printf(" User : %s\n", svc->username);
|
||||
printf(" Group : %s\n", svc->group);
|
||||
printf(" Uptime : %s\n", svc->pid ? uptime(now - svc->start_time, uptm, sizeof(uptm)) : uptm);
|
||||
printf(" Restarts : %d (%d/%d)\n", svc->restart_tot, svc->restart_cnt, svc->restart_max);
|
||||
printf(" Runlevels : %s\n", runlevel_string(runlevel, svc->runlevels));
|
||||
if (svc->pid > 1) {
|
||||
if (cgrp && svc->pid > 1) {
|
||||
char grbuf[128];
|
||||
char path[256];
|
||||
struct cg *cg;
|
||||
char *group;
|
||||
|
||||
group = pid_cgroup(svc->pid, grbuf, sizeof(grbuf));
|
||||
if (!group)
|
||||
goto no_cgroup; /* ... or PID doesn't exist (anymore) */
|
||||
snprintf(path, sizeof(path), "%s/%s", FINIT_CGPATH, group);
|
||||
cg = cg_conf(path);
|
||||
|
||||
printf(" Memory : %s\n", memsz(cgroup_memory(group), uptm, sizeof(uptm)));
|
||||
printf(" CGroup : %s cpu %s [%s, %s] mem [%s, %s]\n",
|
||||
group, cg->cg_cpu.set, cg->cg_cpu.weight, cg->cg_cpu.max,
|
||||
cg->cg_mem.min, cg->cg_mem.max);
|
||||
show_cgroup_tree(group, " ");
|
||||
}
|
||||
no_cgroup:
|
||||
printf("\n");
|
||||
|
||||
return do_log(svc->cmd);
|
||||
return do_log(svc, "| tail -10");
|
||||
}
|
||||
|
||||
col_widths();
|
||||
@@ -764,9 +889,11 @@ static int show_status(char *arg)
|
||||
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
|
||||
char *lvls;
|
||||
|
||||
printf("%-*d ", pw, svc->pid);
|
||||
|
||||
svc_ident(svc, ident, sizeof(ident));
|
||||
if (num && !string_compare(ident, arg))
|
||||
continue;
|
||||
|
||||
printf("%-*d ", pw, svc->pid);
|
||||
printf("%-*s %s ", iw, ident, status(svc, 0));
|
||||
|
||||
lvls = runlevel_string(runlevel, svc->runlevels);
|
||||
@@ -784,6 +911,30 @@ static int show_status(char *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int show_ident(char *arg)
|
||||
{
|
||||
svc_t *svc;
|
||||
|
||||
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
|
||||
char ident[MAX_IDENT_LEN];
|
||||
size_t len;
|
||||
char *pos;
|
||||
|
||||
svc_ident(svc, ident, sizeof(ident));
|
||||
pos = strchr(ident, ':');
|
||||
if (pos)
|
||||
len = pos - ident;
|
||||
else
|
||||
len = strlen(ident);
|
||||
if (arg && arg[0] && strncasecmp(ident, arg, len))
|
||||
continue;
|
||||
|
||||
puts(ident);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int transform(char *nm)
|
||||
{
|
||||
char *names[] = {
|
||||
@@ -828,17 +979,18 @@ static int usage(int rc)
|
||||
" -b, --batch Batch mode, no screen size probing\n"
|
||||
" -c, --create Create missing paths (and files) as needed\n"
|
||||
" -f, --force Ignore missing files and arguments, never prompt\n"
|
||||
" -h, --help This help text\n"
|
||||
" -1, --once Only one lap in commands like 'top'\n"
|
||||
" -p, --plain Use plain table headings, no ctrl chars\n"
|
||||
" -q, --quiet Silent, only return status of command\n"
|
||||
" -t, --no-heading Skip table headings\n"
|
||||
" -v, --verbose Verbose output\n"
|
||||
" -h, --help This help text\n"
|
||||
" -V, --version Show program version\n"
|
||||
"\n"
|
||||
"Commands:\n"
|
||||
" debug Toggle Finit (daemon) debug\n"
|
||||
" help This help text\n"
|
||||
" version Show Finit version\n"
|
||||
" version Show program version\n"
|
||||
"\n", prognm);
|
||||
|
||||
if (has_rcsd)
|
||||
@@ -865,12 +1017,12 @@ static int usage(int rc)
|
||||
" reload Reload *.conf in " FINIT_RCSD " (activate changes)\n");
|
||||
else
|
||||
fprintf(stderr,
|
||||
" reload Reload " FINIT_CONF " (activate changes)\n");
|
||||
" reload Reload " FINIT_CONF " (activate changes)\n");
|
||||
|
||||
fprintf(stderr,
|
||||
// " reload <NAME>[:ID] Reload (SIGHUP) service by name\n"
|
||||
"\n"
|
||||
" cond set <COND> Set (assert) user-defined condition +usr/COND\n"
|
||||
" cond get <COND> Get status of user-defined condition, see $? and -v\n"
|
||||
" cond clear <COND> Clear (deassert) user-defined condition -usr/COND\n"
|
||||
" cond status Show condition status, default cond command\n"
|
||||
" cond dump Dump all conditions and their status\n"
|
||||
@@ -878,14 +1030,21 @@ static int usage(int rc)
|
||||
" log [NAME] Show ten last Finit, or NAME, messages from syslog\n"
|
||||
" start <NAME>[:ID] Start service by name, with optional ID\n"
|
||||
" stop <NAME>[:ID] Stop/Pause a running service by name\n"
|
||||
" reload <NAME>[:ID] Reload service by name (SIGHUP or restart)\n"
|
||||
" reload <NAME>[:ID] Reload service as if .conf changed (SIGHUP or restart)\n"
|
||||
" This allows restart of run/tasks that have already run\n"
|
||||
" Note: Finit .conf file(s) are *not* reloaded!\n"
|
||||
" restart <NAME>[:ID] Restart (stop/start) service by name\n"
|
||||
" signal <NAME>[:ID] <S> Send signal S to service by name, with optional ID\n"
|
||||
" ident [NAME] Show matching identities for NAME, or all\n"
|
||||
" status <NAME>[:ID] Show service status, by name\n"
|
||||
" status Show status of services, default command\n"
|
||||
"\n"
|
||||
" cgroup List cgroup config overview\n"
|
||||
" ps List processes based on cgroups\n"
|
||||
" top Show top-like listing based on cgroups\n"
|
||||
" status Show status of services, default command\n");
|
||||
if (cgrp)
|
||||
fprintf(stderr,
|
||||
"\n"
|
||||
" cgroup List cgroup config overview\n"
|
||||
" ps List processes based on cgroups\n"
|
||||
" top Show top-like listing based on cgroups\n");
|
||||
fprintf(stderr,
|
||||
"\n"
|
||||
" runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot\n"
|
||||
" reboot Reboot system\n"
|
||||
@@ -893,13 +1052,11 @@ static int usage(int rc)
|
||||
" poweroff Halt and power off system\n"
|
||||
" suspend Suspend system\n");
|
||||
|
||||
if (has_utmp())
|
||||
if (utmp)
|
||||
fprintf(stderr,
|
||||
"\n"
|
||||
" utmp show Raw dump of UTMP/WTMP db\n"
|
||||
"\n");
|
||||
else
|
||||
fprintf(stderr, "\n");
|
||||
" utmp show Raw dump of UTMP/WTMP db\n");
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -918,17 +1075,31 @@ static int do_help(char *arg)
|
||||
return usage(0);
|
||||
}
|
||||
|
||||
static int cmd_cond(struct cmd *cmd)
|
||||
{
|
||||
if (!cmd || !cmd->cond)
|
||||
return 1;
|
||||
|
||||
return *cmd->cond;
|
||||
}
|
||||
|
||||
static int cmd_parse(int argc, char *argv[], struct cmd *command)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; argc > 0 && command[i].cmd; i++) {
|
||||
if (!string_match(command[i].cmd, argv[0]))
|
||||
if (!cmd_cond(&command[i]))
|
||||
continue;
|
||||
|
||||
if (!string_compare(command[i].cmd, argv[0]))
|
||||
continue;
|
||||
|
||||
if (command[i].ctx)
|
||||
return cmd_parse(argc - 1, &argv[1], command[i].ctx);
|
||||
|
||||
if (command[i].cb_multiarg)
|
||||
return command[i].cb_multiarg(argc - 1, argv + 1);
|
||||
|
||||
if (command[i].cb) {
|
||||
int rc = 0;
|
||||
|
||||
@@ -943,7 +1114,7 @@ static int cmd_parse(int argc, char *argv[], struct cmd *command)
|
||||
}
|
||||
|
||||
if (argv[0] && strlen(argv[0]) > 0)
|
||||
errx(1, "No such command. See 'initctl help' for an overview of available commands.");
|
||||
ERRX(3, "No such command. See 'initctl help' for an overview of available commands.");
|
||||
|
||||
return command[0].cb(NULL); /* default cmd */
|
||||
}
|
||||
@@ -961,61 +1132,69 @@ int main(int argc, char *argv[])
|
||||
{ "quiet", 0, NULL, 'q' },
|
||||
{ "no-heading", 0, NULL, 't' },
|
||||
{ "verbose", 0, NULL, 'v' },
|
||||
{ "version", 0, NULL, 'V' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
struct cmd cond[] = {
|
||||
{ "status", NULL, do_cond_show }, /* default cmd */
|
||||
{ "dump", NULL, do_cond_dump },
|
||||
{ "set", NULL, do_cond_set },
|
||||
{ "clr", NULL, do_cond_clr },
|
||||
{ "clear", NULL, do_cond_clr },
|
||||
{ NULL, NULL, NULL }
|
||||
{ "status", NULL, do_cond_show, NULL, NULL }, /* default cmd */
|
||||
{ "dump", NULL, do_cond_dump, NULL, NULL },
|
||||
{ "set", NULL, do_cond_set, NULL, NULL },
|
||||
{ "get", NULL, do_cond_get, NULL, NULL },
|
||||
{ "clr", NULL, do_cond_clr, NULL, NULL },
|
||||
{ "clear", NULL, do_cond_clr, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL, NULL }
|
||||
};
|
||||
struct cmd command[] = {
|
||||
{ "status", NULL, show_status }, /* default cmd */
|
||||
{ "status", NULL, show_status, NULL, NULL }, /* default cmd */
|
||||
{ "ident", NULL, show_ident, NULL, NULL },
|
||||
|
||||
{ "debug", NULL, toggle_debug },
|
||||
{ "devel", NULL, do_devel },
|
||||
{ "help", NULL, do_help },
|
||||
{ "version", NULL, show_version },
|
||||
{ "debug", NULL, toggle_debug, NULL, NULL },
|
||||
{ "devel", NULL, do_devel, NULL, NULL },
|
||||
{ "help", NULL, do_help, NULL, NULL },
|
||||
{ "version", NULL, show_version, NULL, NULL },
|
||||
|
||||
{ "list", NULL, serv_list },
|
||||
{ "ls", NULL, serv_list },
|
||||
{ "enable", NULL, serv_enable },
|
||||
{ "disable", NULL, serv_disable },
|
||||
{ "touch", NULL, serv_touch },
|
||||
{ "show", NULL, serv_show },
|
||||
{ "edit", NULL, serv_edit },
|
||||
{ "create", NULL, serv_creat },
|
||||
{ "delete", NULL, serv_delete },
|
||||
{ "reload", NULL, do_reload },
|
||||
{ "list", NULL, serv_list, NULL, NULL },
|
||||
{ "ls", NULL, serv_list, NULL, NULL },
|
||||
{ "enable", NULL, serv_enable, NULL, NULL },
|
||||
{ "disable", NULL, serv_disable, NULL, NULL },
|
||||
{ "touch", NULL, serv_touch, NULL, NULL },
|
||||
{ "show", NULL, serv_show, NULL, NULL },
|
||||
{ "edit", NULL, serv_edit, NULL, NULL },
|
||||
{ "create", NULL, serv_creat, NULL, NULL },
|
||||
{ "delete", NULL, serv_delete, NULL, NULL },
|
||||
{ "reload", NULL, do_reload, NULL, NULL },
|
||||
|
||||
{ "cond", cond, NULL },
|
||||
{ "cond", cond, NULL, NULL, NULL },
|
||||
|
||||
{ "log", NULL, do_log },
|
||||
{ "start", NULL, do_start },
|
||||
{ "stop", NULL, do_stop },
|
||||
{ "restart", NULL, do_restart },
|
||||
{ "log", NULL, show_log, NULL, NULL },
|
||||
{ "start", NULL, do_start, NULL, NULL },
|
||||
{ "stop", NULL, do_stop, NULL, NULL },
|
||||
{ "restart", NULL, do_restart, NULL, NULL },
|
||||
{ "signal", NULL, NULL, NULL, do_signal },
|
||||
|
||||
{ "cgroup", NULL, show_cgroup },
|
||||
{ "ps", NULL, show_cgps },
|
||||
{ "top", NULL, show_cgtop },
|
||||
{ "cgroup", NULL, show_cgroup, &cgrp, NULL },
|
||||
{ "ps", NULL, show_cgps, &cgrp, NULL },
|
||||
{ "top", NULL, show_cgtop, &cgrp, NULL },
|
||||
|
||||
{ "runlevel", NULL, do_runlevel },
|
||||
{ "reboot", NULL, do_reboot },
|
||||
{ "halt", NULL, do_halt },
|
||||
{ "poweroff", NULL, do_poweroff },
|
||||
{ "suspend", NULL, do_suspend },
|
||||
{ "runlevel", NULL, do_runlevel, NULL, NULL },
|
||||
{ "reboot", NULL, do_reboot, NULL, NULL },
|
||||
{ "halt", NULL, do_halt, NULL, NULL },
|
||||
{ "poweroff", NULL, do_poweroff, NULL, NULL },
|
||||
{ "suspend", NULL, do_suspend, NULL, NULL },
|
||||
|
||||
{ "utmp", NULL, do_utmp },
|
||||
{ NULL, NULL, NULL }
|
||||
{ "utmp", NULL, do_utmp, &utmp, NULL },
|
||||
{ NULL, NULL, NULL, NULL, NULL }
|
||||
};
|
||||
int interactive = 1, c;
|
||||
|
||||
if (transform(progname(argv[0])))
|
||||
return reboot_main(argc, argv);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "1bcdfh?pqtv", long_options, NULL)) != EOF) {
|
||||
/* Enable functionality depending on system capabilities */
|
||||
cgrp = cgroup_avail();
|
||||
utmp = has_utmp();
|
||||
|
||||
while ((c = getopt_long(argc, argv, "1bcdfh?pqtvV", long_options, NULL)) != EOF) {
|
||||
switch(c) {
|
||||
case '1':
|
||||
ionce = 1;
|
||||
@@ -1056,23 +1235,15 @@ int main(int argc, char *argv[])
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
return show_version(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (interactive)
|
||||
ttinit();
|
||||
|
||||
if (!has_utmp()) {
|
||||
/* system w/o utmp support, disable 'utmp' command */
|
||||
for (c = 0; command[c].cmd; c++) {
|
||||
if (!string_compare(command[c].cmd, "utmp"))
|
||||
continue;
|
||||
|
||||
command[c].cb = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return cmd_parse(argc - optind, &argv[optind], command);
|
||||
}
|
||||
|
||||
@@ -1080,6 +1251,9 @@ void logit(int prio, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (quiet)
|
||||
return;
|
||||
|
||||
va_start(ap, fmt);
|
||||
if (prio <= LOG_ERR)
|
||||
verrx(1, fmt, ap);
|
||||
|
||||
+10
-2
@@ -1,6 +1,6 @@
|
||||
/* New client tool, replaces old /dev/initctl API and telinit tool
|
||||
*
|
||||
* Copyright (c) 2015-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2015-2022 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -24,6 +24,8 @@
|
||||
#ifndef FINIT_INITCTL_H_
|
||||
#define FINIT_INITCTL_H_
|
||||
|
||||
#include <err.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "util.h"
|
||||
|
||||
@@ -33,8 +35,14 @@ extern int ionce; /* initctl -1 */
|
||||
extern int heading; /* initctl -t */
|
||||
extern int verbose; /* initctl -v */
|
||||
extern int plain; /* initctl -p */
|
||||
extern int quiet; /* initctl -q */
|
||||
|
||||
extern void print_header(const char *fmt, ...);
|
||||
#define ERR(rc, fmt, args...) do { if (!quiet) err(rc, fmt, ##args); else exit(rc); } while (0)
|
||||
#define ERRX(rc, fmt, args...) do { if (!quiet) errx(rc, fmt, ##args); else exit(rc); } while (0)
|
||||
#define WARN(fmt, args...) do { if (!quiet) warn(fmt, ##args); } while (0)
|
||||
#define WARNX(fmt, args...) do { if (!quiet) warnx(fmt, ##args); } while (0)
|
||||
|
||||
extern void print_header(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
||||
|
||||
#endif /* FINIT_INITCTL_H_ */
|
||||
|
||||
|
||||
+17
-1
@@ -1,7 +1,7 @@
|
||||
/* inotify watcher for files or directories
|
||||
*
|
||||
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
|
||||
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2016-2022 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
|
||||
@@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "iwatch.h"
|
||||
@@ -39,6 +40,9 @@ static int initialized = 0;
|
||||
|
||||
int iwatch_init(struct iwatch *iw)
|
||||
{
|
||||
socklen_t len;
|
||||
int sz;
|
||||
|
||||
if (!iw) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
@@ -51,6 +55,18 @@ int iwatch_init(struct iwatch *iw)
|
||||
_pe("Failed creating inotify descriptor");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Double the size of the socket's receive buffer to address
|
||||
* issues with lost events in some cases, e.g. bootstrap and
|
||||
* reconf of systems with lots of services.
|
||||
*/
|
||||
len = sizeof(sz);
|
||||
if (!getsockopt(iw->fd, SOL_SOCKET, SO_RCVBUF, &sz, &len)) {
|
||||
if (setsockopt(iw->fd, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)))
|
||||
_pe("Failed increasing size of inotify socket");
|
||||
}
|
||||
|
||||
initialized = 1;
|
||||
|
||||
return iw->fd;
|
||||
|
||||
+6
-2
@@ -1,7 +1,7 @@
|
||||
/* inotify watcher for files or directories
|
||||
*
|
||||
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
|
||||
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2016-2022 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
|
||||
@@ -26,7 +26,11 @@
|
||||
#define FINIT_IWATCH_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <lite/queue.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/queue.h> /* BSD sys/queue.h API */
|
||||
#else
|
||||
# include <lite/queue.h> /* BSD sys/queue.h API */
|
||||
#endif
|
||||
#include <sys/inotify.h>
|
||||
|
||||
#ifndef IN_MASK_CREATE
|
||||
|
||||
+47
-7
@@ -1,6 +1,6 @@
|
||||
/* Listens to kernel events like AC power status and manages sys/ conditions
|
||||
*
|
||||
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2021-2022 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
@@ -37,7 +38,11 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/netlink.h>
|
||||
|
||||
#include "lite/lite.h"
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
#include "cond.h"
|
||||
#include "pid.h"
|
||||
@@ -48,6 +53,10 @@
|
||||
static int num_ac_online;
|
||||
static int num_ac;
|
||||
|
||||
static int running = 1;
|
||||
static int level;
|
||||
static int logon;
|
||||
|
||||
int debug; /* debug in other modules as well */
|
||||
|
||||
void logit(int prio, const char *fmt, ...)
|
||||
@@ -55,9 +64,9 @@ void logit(int prio, const char *fmt, ...)
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
if (!debug)
|
||||
if (logon)
|
||||
vsyslog(prio, fmt, ap);
|
||||
else {
|
||||
else if (prio <= level) {
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
@@ -175,6 +184,26 @@ static void init(void)
|
||||
sys_cond("pwr/ac", 1);
|
||||
}
|
||||
|
||||
static void set_logging(int prio)
|
||||
{
|
||||
setlogmask(LOG_UPTO(prio));
|
||||
level = prio;
|
||||
}
|
||||
|
||||
static void toggle_debug(int signo)
|
||||
{
|
||||
(void)signo;
|
||||
|
||||
debug ^= 1;
|
||||
set_logging(debug ? LOG_DEBUG : LOG_NOTICE);
|
||||
}
|
||||
|
||||
static void shut_down(int signo)
|
||||
{
|
||||
(void)signo;
|
||||
running = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Started by Finit as soon as possible when base filesystem is up,
|
||||
* modules have been probed, or insmodded from /etc/finit.conf, so by
|
||||
@@ -194,10 +223,13 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
if (!debug) {
|
||||
openlog("keventd", LOG_CONS | LOG_PID, LOG_DAEMON);
|
||||
setlogmask(LOG_UPTO(LOG_NOTICE));
|
||||
openlog("keventd", LOG_PID, LOG_DAEMON);
|
||||
set_logging(LOG_NOTICE);
|
||||
logon = 1;
|
||||
}
|
||||
|
||||
signal(SIGUSR1, toggle_debug);
|
||||
signal(SIGTERM, shut_down);
|
||||
init();
|
||||
|
||||
pfd.events = POLLIN;
|
||||
@@ -212,11 +244,18 @@ int main(int argc, char *argv[])
|
||||
panic("bind failed");
|
||||
|
||||
logit(LOG_DEBUG, "Waiting for events ...");
|
||||
while (-1 != poll(&pfd, 1, -1)) {
|
||||
while (running) {
|
||||
char *path = NULL;
|
||||
int ac = 0;
|
||||
int i, len;
|
||||
|
||||
if (-1 == poll(&pfd, 1, -1)) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
len = recv(pfd.fd, buf, sizeof(buf), MSG_DONTWAIT);
|
||||
if (len == -1) {
|
||||
switch (errno) {
|
||||
@@ -231,6 +270,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
buf[len] = 0;
|
||||
logit(LOG_DEBUG, "%s", buf);
|
||||
|
||||
/* skip libusb events, focus on kernel events/changes */
|
||||
if (strncmp(buf, "change@", 7))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Finit daemon log functions
|
||||
*
|
||||
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -21,10 +21,15 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "config.h" /* Generated by configure script */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <lite/lite.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
@@ -32,14 +37,16 @@
|
||||
#include "util.h"
|
||||
|
||||
static int up = 0;
|
||||
static int loglevel = LOG_NOTICE;
|
||||
static int loglevel = LOG_INFO;
|
||||
|
||||
void log_init(int dbg)
|
||||
void log_init(void)
|
||||
{
|
||||
ttinit();
|
||||
|
||||
if (debug)
|
||||
loglevel = LOG_DEBUG;
|
||||
else
|
||||
loglevel = LOG_NOTICE;
|
||||
loglevel = LOG_INFO;
|
||||
}
|
||||
|
||||
/* If we enabled terse mode at boot, restore to previous setting at shutdown */
|
||||
@@ -55,18 +62,29 @@ void log_exit(void)
|
||||
enable_progress(1);
|
||||
}
|
||||
|
||||
static void log_open(void)
|
||||
static int log_open(void)
|
||||
{
|
||||
int opts = LOG_PID;
|
||||
int opts;
|
||||
|
||||
closelog();
|
||||
if (up)
|
||||
return 1;
|
||||
if (access("/dev/log", W_OK))
|
||||
return 0;
|
||||
|
||||
opts = LOG_CONS | LOG_PID;
|
||||
if (debug)
|
||||
opts |= LOG_PERROR; /* LOG_CONS | */
|
||||
opts |= LOG_PERROR;
|
||||
|
||||
openlog("finit", opts, LOG_DAEMON);
|
||||
setlogmask(LOG_UPTO(loglevel));
|
||||
|
||||
up = 1;
|
||||
return up = 1;
|
||||
}
|
||||
|
||||
static void log_close(void)
|
||||
{
|
||||
closelog();
|
||||
up = 0;
|
||||
}
|
||||
|
||||
/* Toggle debug mode */
|
||||
@@ -74,12 +92,8 @@ void log_debug(void)
|
||||
{
|
||||
debug = !debug;
|
||||
|
||||
if (debug) {
|
||||
loglevel = LOG_DEBUG;
|
||||
} else {
|
||||
loglevel = LOG_NOTICE;
|
||||
ttinit();
|
||||
}
|
||||
log_close();
|
||||
log_init();
|
||||
log_open();
|
||||
|
||||
logit(LOG_NOTICE, "Debug mode %s", debug ? "enabled" : "disabled");
|
||||
@@ -91,15 +105,12 @@ void log_debug(void)
|
||||
*/
|
||||
void logit(int prio, const char *fmt, ...)
|
||||
{
|
||||
FILE *fp;
|
||||
va_list ap;
|
||||
FILE *fp;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
if (up || fexist("/dev/log")) {
|
||||
if (!up)
|
||||
log_open();
|
||||
|
||||
if (up || log_open()) {
|
||||
vsyslog(prio, fmt, ap);
|
||||
goto done;
|
||||
}
|
||||
@@ -107,9 +118,9 @@ void logit(int prio, const char *fmt, ...)
|
||||
if (LOG_PRI(prio) > loglevel)
|
||||
goto done;
|
||||
|
||||
fp = fopen("/dev/kmsg", "w");
|
||||
if (!fp) {
|
||||
if (in_container() || !(fp = fopen("/dev/kmsg", "w"))) {
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fputs("\n", stderr);
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -121,6 +132,7 @@ void logit(int prio, const char *fmt, ...)
|
||||
va_end(ap);
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fputs("\n", stderr);
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Finit daemon log functions
|
||||
*
|
||||
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -40,17 +40,17 @@
|
||||
* The default log level is LOG_NOTICE. To toggle LOG_DEBUG messages,
|
||||
* use `initctl debug` or add `debug` to the kernel cmdline.
|
||||
*/
|
||||
#define _d(fmt, args...) logit(LOG_DEBUG, "%s():" fmt "\n", __func__, ##args)
|
||||
#define _w(fmt, args...) logit(LOG_WARNING, "%s():" fmt "\n", __func__, ##args)
|
||||
#define _e(fmt, args...) logit(LOG_ERR, "%s():" fmt "\n", __func__, ##args)
|
||||
#define _pe(fmt, args...) logit(LOG_ERR, "%s():" fmt ": %s\n", __func__, ##args, strerror(errno))
|
||||
#define _d(fmt, args...) logit(LOG_DEBUG, "%s():" fmt, __func__, ##args)
|
||||
#define _w(fmt, args...) logit(LOG_WARNING, "%s():" fmt, __func__, ##args)
|
||||
#define _e(fmt, args...) logit(LOG_ERR, "%s():" fmt, __func__, ##args)
|
||||
#define _pe(fmt, args...) logit(LOG_ERR, "%s():" fmt ": %s", __func__, ##args, strerror(errno))
|
||||
|
||||
void log_init (int dbg);
|
||||
void log_init (void);
|
||||
void log_exit (void);
|
||||
|
||||
void log_debug (void);
|
||||
|
||||
void logit (int prio, const char *fmt, ...);
|
||||
void flog (char *file, const char *fmt, ...);
|
||||
void logit (int prio, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
void flog (char *file, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
|
||||
#endif /* FINIT_LOG_H_ */
|
||||
|
||||
+6
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2018-2022 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
|
||||
@@ -30,7 +30,11 @@
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <lite/lite.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
static const char version_info[] = PACKAGE_NAME " v" PACKAGE_VERSION;
|
||||
extern int logrotate(char *file, int num, off_t sz);
|
||||
|
||||
+6
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2018-2022 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
|
||||
@@ -20,12 +20,16 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <lite/lite.h>
|
||||
#include <stdio.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
static int recreate(char *path, mode_t mode, uid_t uid, gid_t gid)
|
||||
{
|
||||
|
||||
+3
-1
@@ -1,6 +1,6 @@
|
||||
/* Handle MD arrays
|
||||
*
|
||||
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -21,6 +21,8 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h" /* Generated by configure script */
|
||||
|
||||
#include <glob.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
+47
-19
@@ -1,6 +1,6 @@
|
||||
/* Mount and unmount helpers
|
||||
*
|
||||
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -21,14 +21,21 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h" /* Generated by configure script */
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_MNTENT_H
|
||||
#include <mntent.h>
|
||||
#endif
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
/*
|
||||
* SysV init on Debian/Ubuntu skips these protected mount points
|
||||
*
|
||||
* It also skips anything below /proc, /sys and /run for good meausre so
|
||||
* It also skips anything below /proc, /sys and /run for good measure so
|
||||
* we do the same here. What we want is a list of non-protected tmpfs
|
||||
* and regular filesystems that can be safely unmounted before we do
|
||||
* swapoff, and remount / as read-only, respectively.
|
||||
@@ -36,7 +43,7 @@
|
||||
static int is_protected(char *dir)
|
||||
{
|
||||
size_t i;
|
||||
char *protected[] = {
|
||||
char *protected_mnts[] = {
|
||||
"/sys", "/proc",
|
||||
"/.dev", "/dev", "/dev/pts", "/dev/shm", "dev/.static/dev", "/dev/vcs",
|
||||
"/run", "/var/run",
|
||||
@@ -46,8 +53,8 @@ static int is_protected(char *dir)
|
||||
"/proc/", "/sys/", "/run/", NULL
|
||||
};
|
||||
|
||||
for (i = 0; protected[i]; i++) {
|
||||
if (!strcmp(dir, protected[i]))
|
||||
for (i = 0; protected_mnts[i]; i++) {
|
||||
if (!strcmp(dir, protected_mnts[i]))
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -59,46 +66,67 @@ static int is_protected(char *dir)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mntent *iterator(char *fstab)
|
||||
static void iterator_end(FILE **fp)
|
||||
{
|
||||
endmntent(*fp);
|
||||
*fp = NULL;
|
||||
}
|
||||
|
||||
static struct mntent *iterator(char *filename, FILE **fp)
|
||||
{
|
||||
static FILE *fp = NULL;
|
||||
static struct mntent *mnt;
|
||||
|
||||
if (!fp && fstab) {
|
||||
fp = setmntent(fstab, "r");
|
||||
if (!fp)
|
||||
if (!*fp && filename) {
|
||||
*fp = setmntent(filename, "r");
|
||||
if (!*fp)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while ((mnt = getmntent(fp))) {
|
||||
while ((mnt = getmntent(*fp))) {
|
||||
if (is_protected(mnt->mnt_dir))
|
||||
continue;
|
||||
|
||||
return mnt;
|
||||
}
|
||||
|
||||
endmntent(fp);
|
||||
fp = NULL;
|
||||
|
||||
iterator_end(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int unmount(const char *target)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = umount(target);
|
||||
if (rc) {
|
||||
if (errno != EBUSY)
|
||||
print(2, "Failed unmounting %s, error %d: %s", target, errno, strerror(errno));
|
||||
return rc;
|
||||
}
|
||||
print(0, "Unmounting %s", target);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void unmount_tmpfs(void)
|
||||
{
|
||||
struct mntent *mnt;
|
||||
FILE *fp = NULL;
|
||||
|
||||
while ((mnt = iterator("/proc/mounts"))) {
|
||||
if (!strcmp("tmpfs", mnt->mnt_fsname))
|
||||
umount(mnt->mnt_dir);
|
||||
while ((mnt = iterator("/proc/mounts", &fp))) {
|
||||
if (!strcmp("tmpfs", mnt->mnt_fsname) && !unmount(mnt->mnt_dir))
|
||||
iterator_end(&fp); /* Restart iteration */
|
||||
}
|
||||
}
|
||||
|
||||
void unmount_regular(void)
|
||||
{
|
||||
struct mntent *mnt;
|
||||
FILE *fp = NULL;
|
||||
|
||||
while ((mnt = iterator("/proc/mounts"))) {
|
||||
umount(mnt->mnt_dir);
|
||||
while ((mnt = iterator("/proc/mounts", &fp))) {
|
||||
if (!unmount(mnt->mnt_dir))
|
||||
iterator_end(&fp); /* Restart iteration */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* PID and PID file helpers
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -22,12 +22,18 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h" /* Generated by configure script */
|
||||
|
||||
#include <errno.h>
|
||||
#include <paths.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <lite/lite.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
#include "pid.h"
|
||||
#include "svc.h"
|
||||
@@ -65,10 +71,11 @@ int pid_alive(pid_t pid)
|
||||
*/
|
||||
char *pid_get_name(pid_t pid, char *name, size_t len)
|
||||
{
|
||||
static char line[64];
|
||||
char *pname = NULL;
|
||||
char path[32];
|
||||
int ret = 1;
|
||||
FILE *fp;
|
||||
char *pname, path[32];
|
||||
static char line[64];
|
||||
|
||||
snprintf(path, sizeof(path), "/proc/%d/status", pid);
|
||||
fp = fopen(path, "r");
|
||||
@@ -109,8 +116,8 @@ char *pid_file(svc_t *svc)
|
||||
pid_t pid_file_read(const char *fn)
|
||||
{
|
||||
pid_t pid = 0;
|
||||
FILE *fp;
|
||||
char buf[42];
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen(fn, "r");
|
||||
if (!fp)
|
||||
@@ -153,6 +160,11 @@ int pid_file_set(svc_t *svc, char *file, int not)
|
||||
file++;
|
||||
}
|
||||
|
||||
if (svc_is_forking(svc) && !not) {
|
||||
logit(LOG_WARNING, "Service %s is forking, adjusting to pid:!%s", svc->name, file);
|
||||
not = 1;
|
||||
}
|
||||
|
||||
pid_runpath(file, &svc->pidfile[not], sizeof(svc->pidfile) - not);
|
||||
if (not)
|
||||
svc->pidfile[0] = '!';
|
||||
@@ -166,7 +178,7 @@ int pid_file_set(svc_t *svc, char *file, int not)
|
||||
* The logic is explained below. Please note that using the first form
|
||||
* of the syntax not only creates and removes the PID file, but it also
|
||||
* calls touch to update the mtime on service_restart(), only applicable
|
||||
* to processes that accept SIGHUP. This to ensure dependant services
|
||||
* to processes that accept SIGHUP. This to ensure dependent services
|
||||
* are sent SIGCONT properly on reload, otherwise their condition would
|
||||
* never be asserted again after `initctl reload`.
|
||||
*
|
||||
@@ -195,8 +207,8 @@ int pid_file_parse(svc_t *svc, char *arg)
|
||||
|
||||
/* 'pid:' implies argument following*/
|
||||
if (!strncmp(arg, "pid:", 4)) {
|
||||
int len, not = 0;
|
||||
char path[MAX_ARG_LEN];
|
||||
int len, not = 0;
|
||||
|
||||
arg += 4;
|
||||
if ((arg[0] == '!' && arg[1] == '/') || arg[0] == '/')
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* PID and PID file helpers
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2022 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
|
||||
|
||||
+11
-5
@@ -1,6 +1,6 @@
|
||||
/* Plugin based services architecture for finit
|
||||
*
|
||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -21,15 +21,21 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h" /* Generated by configure script */
|
||||
|
||||
#include <errno.h>
|
||||
#include <dlfcn.h> /* dlopen() et al */
|
||||
#include <dirent.h> /* readdir() et al */
|
||||
#include <poll.h>
|
||||
#include <string.h>
|
||||
#include <lite/lite.h>
|
||||
#include <lite/queue.h> /* BSD sys/queue.h API */
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
# include <libite/queue.h> /* BSD sys/queue.h API */
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
# include <lite/queue.h> /* BSD sys/queue.h API */
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "cond.h"
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
@@ -274,7 +280,7 @@ static int init_plugins(uev_ctx_t *ctx)
|
||||
* Loads a plugin from @path/@name[.so]. Note, if ".so" is missing from
|
||||
* the plugin @name it is added before attempting to load.
|
||||
*
|
||||
* It is up to the plugin itself ot register itself as a "ctor" with the
|
||||
* It is up to the plugin itself or register itself as a "ctor" with the
|
||||
* %PLUGIN_INIT macro so that plugin_register() is called automatically.
|
||||
*
|
||||
* Returns:
|
||||
|
||||
+6
-2
@@ -1,6 +1,6 @@
|
||||
/* Plugin based services architecture for finit
|
||||
*
|
||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2022 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
|
||||
@@ -25,7 +25,11 @@
|
||||
#define FINIT_PLUGIN_H_
|
||||
|
||||
#include <uev/uev.h>
|
||||
#include <lite/queue.h> /* BSD sys/queue.h API */
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/queue.h> /* BSD sys/queue.h API */
|
||||
#else
|
||||
# include <lite/queue.h> /* BSD sys/queue.h API */
|
||||
#endif
|
||||
|
||||
#include "svc.h"
|
||||
|
||||
|
||||
+4
-1
@@ -1,7 +1,7 @@
|
||||
/* Private header file for main finit daemon, not for plugins
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2022 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
|
||||
@@ -28,6 +28,9 @@
|
||||
#include "svc.h"
|
||||
#include "plugin.h"
|
||||
|
||||
#define SERVICE_INTERVAL_DEFAULT 300000 /* 5 mins */
|
||||
extern int service_interval;
|
||||
|
||||
int api_init (uev_ctx_t *ctx);
|
||||
int api_exit (void);
|
||||
|
||||
|
||||
+9
-10
@@ -1,6 +1,6 @@
|
||||
/* reboot, halt, poweroff, shutdown, suspend for finit
|
||||
*
|
||||
* Copyright (c) 2009-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2009-2022 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
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "util.h"
|
||||
@@ -98,11 +99,6 @@ static void do_kill(int signo, char *msg)
|
||||
do_sleep(5);
|
||||
}
|
||||
|
||||
static void sig(int signo)
|
||||
{
|
||||
(void)signo; /* NOP */
|
||||
}
|
||||
|
||||
static int usage(int rc)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [OPTIONS]\n\n"
|
||||
@@ -164,10 +160,13 @@ int reboot_main(int argc, char *argv[])
|
||||
/* Check for any overrides */
|
||||
transform(NULL);
|
||||
|
||||
/* Catch and ignore SIGTERM on halt/poweroff */
|
||||
signal(SIGTERM, sig);
|
||||
/* Check if we're in sulogin shell */
|
||||
if (getenv("SULOGIN"))
|
||||
force = 1;
|
||||
|
||||
if (force) {
|
||||
sync();
|
||||
|
||||
switch (cmd) {
|
||||
case CMD_REBOOT:
|
||||
c = reboot(RB_AUTOBOOT);
|
||||
@@ -182,9 +181,9 @@ int reboot_main(int argc, char *argv[])
|
||||
break;
|
||||
|
||||
case CMD_SUSPEND:
|
||||
c = reboot(RB_SW_SUSPEND);
|
||||
c = suspend();
|
||||
if (c && errno == EINVAL)
|
||||
errx(1, "Kernel does not support suspend.");
|
||||
errx(1, "Kernel does not support suspend to RAM.");
|
||||
break;
|
||||
|
||||
case CMD_UNKNOWN:
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
# runlevel. Finit does not restart them when they exit.
|
||||
#
|
||||
# - run : wait for completion before continuing with next stanza
|
||||
# - task : like run but started in background, parallell with other stanzas
|
||||
# - task : like run but started in background, parallel with other stanzas
|
||||
# - service : supervised daemon, run in foreground, restarted if it crashes
|
||||
#
|
||||
# The env: is an optional path to a file with environment variables to
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* Work queue helper functions
|
||||
*
|
||||
* Copyright (c) 2018-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2018-2022 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
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* Work queue helper functions
|
||||
*
|
||||
* Copyright (c) 2018-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2018-2022 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
|
||||
|
||||
+60
-27
@@ -1,6 +1,6 @@
|
||||
/* List and enable/disable service configurations
|
||||
*
|
||||
* Copyright (c) 2017-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2017-2022 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
|
||||
@@ -23,16 +23,34 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <err.h>
|
||||
#include <fcntl.h> /* Definition of AT_* constants */
|
||||
#include <glob.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <lite/lite.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
#include "client.h"
|
||||
#include "initctl.h"
|
||||
|
||||
|
||||
static int is_builtin(char *arg)
|
||||
{
|
||||
svc_t *svc;
|
||||
|
||||
svc = client_svc_find(arg);
|
||||
if (!svc)
|
||||
return 0;
|
||||
|
||||
if (svc->file[0])
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int calc_width(char *arr[], size_t len)
|
||||
{
|
||||
int width = 0;
|
||||
@@ -214,7 +232,7 @@ int serv_enable(char *arg)
|
||||
int ena;
|
||||
|
||||
if (!arg || !arg[0]) {
|
||||
warnx("missing argument to enable, may be one of:");
|
||||
WARNX("missing argument to enable, may be one of:");
|
||||
return serv_list("available");
|
||||
}
|
||||
|
||||
@@ -224,18 +242,18 @@ int serv_enable(char *arg)
|
||||
}
|
||||
|
||||
if (chdir(FINIT_RCSD))
|
||||
err(1, "failed cd %s", FINIT_RCSD);
|
||||
ERR(72, "failed cd %s", FINIT_RCSD);
|
||||
|
||||
if (icreate && mkdir("enabled", 0755) && EEXIST != errno)
|
||||
err(1, "failed creating %s/enabled directory", FINIT_RCSD);
|
||||
ERR(73, "failed creating %s/enabled directory", FINIT_RCSD);
|
||||
ena = !chdir("enabled"); /* System *may* have enabled/ dir. */
|
||||
|
||||
snprintf(path, sizeof(path), "%savailable/%s", ena ? "../" : "", arg);
|
||||
if (!fexist(path))
|
||||
errx(1, "cannot find %s", conf(path, sizeof(path), arg, 0));
|
||||
ERRX(72, "cannot find %s", conf(path, sizeof(path), arg, 0));
|
||||
|
||||
if (fexist(arg))
|
||||
errx(1, "%s already enabled", arg);
|
||||
ERRX(1, "%s already enabled", arg);
|
||||
|
||||
return symlink(path, arg) != 0;
|
||||
}
|
||||
@@ -246,7 +264,7 @@ int do_disable(char *arg, int check)
|
||||
char corr[40];
|
||||
|
||||
if (!arg || !arg[0]) {
|
||||
warnx("missing argument to disable, may be one of:");
|
||||
WARNX("missing argument to disable, may be one of:");
|
||||
return serv_list("enabled");
|
||||
}
|
||||
|
||||
@@ -256,15 +274,15 @@ int do_disable(char *arg, int check)
|
||||
}
|
||||
|
||||
if (chdir(FINIT_RCSD))
|
||||
err(1, "failed cd %s", FINIT_RCSD);
|
||||
ERR(72, "failed cd %s", FINIT_RCSD);
|
||||
if (chdir("enabled")) /* System *may* have enabled/ dir. */
|
||||
dbg("Failed changing to %s/enabled/: %s", FINIT_RCSD, strerror(errno));
|
||||
|
||||
if (check && stat(arg, &st))
|
||||
errx(1, "%s not (an) enabled (service).", arg);
|
||||
ERRX(6, "%s not (an) enabled (service).", arg);
|
||||
|
||||
if (check && (st.st_mode & S_IFMT) == S_IFLNK)
|
||||
errx(1, "cannot disable %s, not a symlink.", arg);
|
||||
ERRX(1, "cannot disable %s, not a symlink.", arg);
|
||||
|
||||
return remove(arg) != 0;
|
||||
}
|
||||
@@ -280,14 +298,16 @@ int serv_touch(char *arg)
|
||||
char *fn;
|
||||
|
||||
if (!arg || !arg[0]) {
|
||||
warnx("missing argument to touch, may be one of:");
|
||||
WARNX("missing argument to touch, may be one of:");
|
||||
return serv_list("enabled");
|
||||
}
|
||||
|
||||
fn = conf(path, sizeof(path), arg, 0);
|
||||
if (!fexist(fn)) {
|
||||
if (!strstr(arg, "finit.conf"))
|
||||
errx(1, "%s not available.", arg);
|
||||
ERRX(72, "%s not available.", arg);
|
||||
if (is_builtin(arg))
|
||||
ERRX(4, "%s is a built-in service.", arg);
|
||||
|
||||
strlcpy(path, FINIT_CONF, sizeof(path));
|
||||
fn = path;
|
||||
@@ -295,7 +315,7 @@ int serv_touch(char *arg)
|
||||
|
||||
/* libite:touch() follows symlinks */
|
||||
if (utimensat(AT_FDCWD, fn, NULL, AT_SYMLINK_NOFOLLOW))
|
||||
err(1, "failed marking %s for reload", fn);
|
||||
ERR(71, "failed marking %s for reload", fn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -307,7 +327,10 @@ int serv_show(char *arg)
|
||||
|
||||
fn = conf(path, sizeof(path), arg, 0);
|
||||
if (!fexist(fn)) {
|
||||
warnx("Cannot find %s", arg);
|
||||
if (is_builtin(arg))
|
||||
ERRX(4, "%s is a built-in service.", arg);
|
||||
|
||||
WARNX("Cannot find %s", arg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -341,8 +364,11 @@ static int do_edit(char *arg, int creat)
|
||||
|
||||
fn = conf(path, sizeof(path), arg, creat);
|
||||
if (!fexist(fn)) {
|
||||
if (is_builtin(arg))
|
||||
ERRX(4, "%s is a built-in service.", arg);
|
||||
|
||||
if (!creat) {
|
||||
warnx("Cannot find %s, use -c flag, create command, or select one of:", arg);
|
||||
WARNX("Cannot find %s, use -c flag, create command, or select one of:", arg);
|
||||
return serv_list(NULL);
|
||||
}
|
||||
|
||||
@@ -351,7 +377,7 @@ static int do_edit(char *arg, int creat)
|
||||
copyfile(SAMPLE_CONF, fn, 0, 0);
|
||||
#endif
|
||||
} else if (creat)
|
||||
warnx("the file %s already exists, falling back to edit.", fn);
|
||||
WARNX("the file %s already exists, falling back to edit.", fn);
|
||||
|
||||
for (size_t i = 0; i < NELEMS(editor); i++) {
|
||||
if (systemf("%s %s 2>/dev/null", editor[i], path))
|
||||
@@ -367,6 +393,7 @@ int serv_edit(char *arg)
|
||||
if (!arg || !arg[0]) {
|
||||
if (!yorn("Do you want to edit %s (y/N)? ", FINIT_CONF))
|
||||
return 0;
|
||||
arg = "";
|
||||
}
|
||||
|
||||
return do_edit(arg, icreate);
|
||||
@@ -379,7 +406,10 @@ int serv_creat(char *arg)
|
||||
FILE *fp;
|
||||
|
||||
if (!arg || !arg[0])
|
||||
errx(1, "missing argument to create");
|
||||
ERRX(2, "missing argument to create");
|
||||
|
||||
if (is_builtin(arg))
|
||||
ERRX(4, "%s is a built-in service.", arg);
|
||||
|
||||
/* Input from a pipe or a proper TTY? */
|
||||
if (isatty(STDIN_FILENO))
|
||||
@@ -388,16 +418,16 @@ int serv_creat(char *arg)
|
||||
/* Open fn for writing from pipe */
|
||||
fn = conf(buf, sizeof(buf), arg, 1);
|
||||
if (!fn)
|
||||
err(1, "failed creating conf %s", arg);
|
||||
ERR(73, "failed creating conf %s", arg);
|
||||
|
||||
if (!icreate && fexist(fn)) {
|
||||
warnx("%s already exists, skipping (use -c to override)", fn);
|
||||
WARNX("%s already exists, skipping (use -c to override)", fn);
|
||||
fn = "/dev/null";
|
||||
}
|
||||
|
||||
fp = fopen(fn, "w");
|
||||
if (!fp)
|
||||
err(1, "failed opening %s for writing", fn);
|
||||
ERR(73, "failed opening %s for writing", fn);
|
||||
|
||||
while (fgets(buf, sizeof(buf), stdin))
|
||||
fputs(buf, fp);
|
||||
@@ -411,21 +441,24 @@ int serv_delete(char *arg)
|
||||
char *fn;
|
||||
|
||||
if (!arg || !arg[0]) {
|
||||
warnx("missing argument to delete, may be one of:");
|
||||
WARNX("missing argument to delete, may be one of:");
|
||||
return serv_list("available");
|
||||
}
|
||||
|
||||
fn = conf(buf, sizeof(buf), arg, 0);
|
||||
if (!fn)
|
||||
errx(1, FINIT_RCSD " missing on system.");
|
||||
if (!fn) {
|
||||
if (is_builtin(arg))
|
||||
ERRX(4, "%s is a built-in service.", arg);
|
||||
ERRX(72, FINIT_RCSD " missing on system.");
|
||||
}
|
||||
|
||||
if (!fexist(fn))
|
||||
warnx("cannot find %s", fn);
|
||||
WARNX("cannot find %s", fn);
|
||||
|
||||
if (iforce || yorn("Remove file and symlink(s) to %s (y/N)? ", fn)) {
|
||||
do_disable(arg, 0);
|
||||
if (remove(fn))
|
||||
err(1, "Failed removing %s", fn);
|
||||
ERR(1, "Failed removing %s", fn);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* List and enable/disable service configurations
|
||||
*
|
||||
* Copyright (c) 2017-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2017-2022 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
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user