mirror of
https://github.com/troglobit/finit.git
synced 2026-10-12 10:12:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b321de339 | ||
|
|
1691ebb292 | ||
|
|
c371c10455 | ||
|
|
a23e152f6b | ||
|
|
9210f2851e | ||
|
|
617609cbc5 | ||
|
|
b022916758 | ||
|
|
9a357b7aab | ||
|
|
ffd01b0276 | ||
|
|
2c95f091ee | ||
|
|
b75b107d6d | ||
|
|
1f2c1d2109 | ||
|
|
f328d24d01 | ||
|
|
211293a83d | ||
|
|
446f5bc8b8 | ||
|
|
0c6f748f2c | ||
|
|
a677b94ad9 | ||
|
|
6552cda605 | ||
|
|
3add682be3 | ||
|
|
abac31682d | ||
|
|
cfe915e6d5 | ||
|
|
ecf65ce44b | ||
|
|
0d742d6ae8 | ||
|
|
cf201a43df | ||
|
|
9245869e18 | ||
|
|
0f4a487328 | ||
|
|
f1b5b42919 | ||
|
|
f546129baf | ||
|
|
27451ac3f2 | ||
|
|
0a8f3a6250 | ||
|
|
70c4e7d774 | ||
|
|
5265eee25d | ||
|
|
4b06e1a49f | ||
|
|
6b9aa21509 | ||
|
|
990307fbc9 | ||
|
|
9d8a9b7fba | ||
|
|
bbc83eaa64 | ||
|
|
23d034f521 | ||
|
|
9a3148a49d | ||
|
|
8560103a24 | ||
|
|
7a75e34808 | ||
|
|
4d4fc10d57 | ||
|
|
003faae9e9 | ||
|
|
01a01d65c0 | ||
|
|
048302f06a | ||
|
|
74f0fcfccd | ||
|
|
3cfe0a33b8 | ||
|
|
465bc17ca4 | ||
|
|
d4889b435d | ||
|
|
49c0557ced | ||
|
|
6be16f2f6d | ||
|
|
bc8118d515 | ||
|
|
0c0e880f3f | ||
|
|
119e66a7e9 | ||
|
|
46ffa81f5c | ||
|
|
54701422a5 | ||
|
|
9d463e3823 | ||
|
|
56e558c960 | ||
|
|
dfaf351da1 | ||
|
|
a8433fcb7f | ||
|
|
2daa953bee | ||
|
|
3e3e9aadf5 | ||
|
|
dc873c6548 | ||
|
|
29bd7a504e | ||
|
|
a0685219cf | ||
|
|
13b107b7b1 | ||
|
|
409d68d05b | ||
|
|
ab62b5282b | ||
|
|
d02d65feeb | ||
|
|
9a0dea6aef | ||
|
|
7481505b1a | ||
|
|
8251f1a422 | ||
|
|
e269176a79 | ||
|
|
612f5a9385 | ||
|
|
4a2381eb6f | ||
|
|
0cae7d44dd | ||
|
|
340cae4afd | ||
|
|
6a89e60fc8 | ||
|
|
840d612fc2 | ||
|
|
60c676ab2d | ||
|
|
deada0fa89 | ||
|
|
7b501f255b | ||
|
|
052136cb99 | ||
|
|
742b8b72cc | ||
|
|
c37037c015 | ||
|
|
c32b5a749a | ||
|
|
7701718d7b | ||
|
|
eb4eca9607 | ||
|
|
cab94b81e8 | ||
|
|
5913217808 | ||
|
|
b49f55ab3d | ||
|
|
bf4a584e2e | ||
|
|
90a4df8d12 | ||
|
|
146bf55122 | ||
|
|
c1ed373398 | ||
|
|
5998342b3e | ||
|
|
9dc7b8a6b0 | ||
|
|
c221823654 | ||
|
|
248f7d3110 | ||
|
|
fe90ba5781 | ||
|
|
71c87734b7 | ||
|
|
cd060e8af3 | ||
|
|
33a7f123d7 | ||
|
|
d15e28ea6b | ||
|
|
836bfff08b | ||
|
|
59152b557c | ||
|
|
293b0ffa79 | ||
|
|
d5d9cd5645 | ||
|
|
2f281665af | ||
|
|
b00e7394f8 | ||
|
|
d5a5fffa52 | ||
|
|
4d24c34b28 | ||
|
|
355265651e | ||
|
|
41093df2a9 | ||
|
|
0a816d1fa4 | ||
|
|
3bfc0f0fca | ||
|
|
0aa6ee895c | ||
|
|
b1526fb2d6 | ||
|
|
b2624ac160 | ||
|
|
2c340f83ce | ||
|
|
337ee003bb | ||
|
|
791df0c986 | ||
|
|
f29e92be21 | ||
|
|
379a63fce4 | ||
|
|
b1f9a11809 | ||
|
|
2d9c63e48e | ||
|
|
d66455496a | ||
|
|
77cf72cb40 | ||
|
|
6cc587068b | ||
|
|
cc96e8908a | ||
|
|
adb25d52cd | ||
|
|
7d09567ec8 | ||
|
|
9130af1c77 | ||
|
|
cbea83b369 | ||
|
|
42cd8d284b | ||
|
|
72ebc92622 | ||
|
|
06adecaaea | ||
|
|
efc0592961 | ||
|
|
ed88469276 | ||
|
|
cbf96a1de0 | ||
|
|
cc979f27f1 | ||
|
|
fca5ce57ea | ||
|
|
53aa195ad5 | ||
|
|
e60211168e | ||
|
|
dc3ee9e467 | ||
|
|
6918f3b711 | ||
|
|
66020f48ea | ||
|
|
47b0d4cccf | ||
|
|
92c2efa655 | ||
|
|
b69aa8a8bd | ||
|
|
ca90bbfb04 | ||
|
|
0b5c555c7f | ||
|
|
6443995fc9 | ||
|
|
180faf8a40 | ||
|
|
0ebdd32f6b | ||
|
|
60bf858302 | ||
|
|
7c86b40190 | ||
|
|
4f3f140a09 | ||
|
|
10c24b1674 | ||
|
|
2b4f89ecd1 | ||
|
|
c42a6f2869 | ||
|
|
89bb609a7e | ||
|
|
da6298aecd | ||
|
|
576318cc29 | ||
|
|
0d7d331ad4 | ||
|
|
c886ecb5cc | ||
|
|
304a096877 | ||
|
|
064c7682fc | ||
|
|
58239b897b | ||
|
|
5281d82e80 | ||
|
|
5ff28c4dc6 | ||
|
|
f2218836af | ||
|
|
fbb3779d17 | ||
|
|
68f44f7a97 | ||
|
|
50e587f447 | ||
|
|
fb4c560196 | ||
|
|
8b5fa5eeaa | ||
|
|
88ec21e9cc | ||
|
|
84adec4006 | ||
|
|
19b2b2a279 | ||
|
|
e4163b7221 | ||
|
|
eaef302420 | ||
|
|
d5738da307 | ||
|
|
c9f930c7ad | ||
|
|
e2ee372b5d | ||
|
|
7ff7f93364 | ||
|
|
d5a95760ef | ||
|
|
24d1425b74 | ||
|
|
43d9e25ba7 | ||
|
|
f27998ae4f | ||
|
|
c8e0b6b9ef | ||
|
|
f7e8fccb2f | ||
|
|
7bbccb1213 | ||
|
|
d38c333e04 | ||
|
|
095f6b645c | ||
|
|
b4d10cbade | ||
|
|
5d703fd39e | ||
|
|
eaaf8d862e | ||
|
|
2468f11cd8 | ||
|
|
f8a6a119ac | ||
|
|
1889b88aab | ||
|
|
0d70023bfe | ||
|
|
41648a073b | ||
|
|
33cee0ba5f | ||
|
|
2235fb8352 | ||
|
|
eb9e94935e | ||
|
|
fb230f2137 | ||
|
|
6aa48a8b32 | ||
|
|
5b9cebbfd3 | ||
|
|
38791616e0 | ||
|
|
fede3fd2e1 | ||
|
|
a46a33238d | ||
|
|
afe0488bf2 | ||
|
|
ec5e42694d | ||
|
|
2e73563eea | ||
|
|
338521a748 | ||
|
|
6ae1083c99 | ||
|
|
846806747b | ||
|
|
8904ca993e | ||
|
|
efed0db16b | ||
|
|
11946f12d3 | ||
|
|
2ba359ed80 | ||
|
|
fafd524701 | ||
|
|
1ee6c9f46b | ||
|
|
a88eb82a68 | ||
|
|
a436a1c8cb | ||
|
|
7cb91854b0 | ||
|
|
939ae02a6a | ||
|
|
480d29175c | ||
|
|
ea68413512 | ||
|
|
4edfa9859e | ||
|
|
eb6291c943 | ||
|
|
756b7c3fb6 | ||
|
|
263aec292a | ||
|
|
5a946a4ea7 | ||
|
|
c90b4d797b | ||
|
|
6e7a2fb6d5 | ||
|
|
ddedcf77e8 | ||
|
|
924ec2ef80 | ||
|
|
a49f27c191 | ||
|
|
b41b4ce989 | ||
|
|
3d74e93fa2 | ||
|
|
443700a88e | ||
|
|
4701edef4c | ||
|
|
e6da0a22e7 | ||
|
|
7be2bbbc30 | ||
|
|
3e269c632f | ||
|
|
f2507d9fd7 | ||
|
|
e9f403bceb | ||
|
|
c03176c42a | ||
|
|
9707bfb103 | ||
|
|
11430f83c8 | ||
|
|
a22a794f55 | ||
|
|
5556501287 | ||
|
|
ab554568b2 | ||
|
|
b39a4498a3 | ||
|
|
dead2444e2 | ||
|
|
a58002588e | ||
|
|
28e101aaae | ||
|
|
6da8af8136 | ||
|
|
3069e753e1 | ||
|
|
aafd5c1010 | ||
|
|
2f51c8ea0d | ||
|
|
d1130473fc | ||
|
|
b682a5e4fe | ||
|
|
1fc0f36c6c | ||
|
|
5df5b22327 | ||
|
|
4153c7966d | ||
|
|
458d68533f | ||
|
|
63b5db38df | ||
|
|
2135639508 | ||
|
|
9c8cd6c024 | ||
|
|
450f498061 | ||
|
|
5769500afe | ||
|
|
dc61969164 | ||
|
|
6f0d448765 | ||
|
|
0c9b7a67e0 | ||
|
|
5db2fb2c32 |
@@ -21,26 +21,25 @@ jobs:
|
||||
compiler: [gcc, clang]
|
||||
fail-fast: false
|
||||
env:
|
||||
MAKEFLAGS: -j3
|
||||
CC: ${{ matrix.compiler }}
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y install pkg-config tree jq libuev-dev libite-dev
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Static Finit
|
||||
run: |
|
||||
./autogen.sh
|
||||
./configure --prefix= --enable-static
|
||||
make V=1
|
||||
make -j3 V=1
|
||||
- name: Regular Finit
|
||||
run: |
|
||||
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
|
||||
--enable-x11-common-plugin --enable-testserv-plugin --with-watchdog \
|
||||
--with-keventd
|
||||
make clean
|
||||
make V=1
|
||||
make -j3 clean
|
||||
make -j3 V=1
|
||||
- name: Install to /tmp
|
||||
run: |
|
||||
DESTDIR=/tmp make install-strip
|
||||
@@ -57,11 +56,14 @@ jobs:
|
||||
run: |
|
||||
sudo /tmp/sbin/finit -h
|
||||
sudo /tmp/sbin/initctl -h
|
||||
- name: Enable unprivileged userns (unshare)
|
||||
run: |
|
||||
sudo sysctl kernel.apparmor_restrict_unprivileged_userns=0
|
||||
- name: Run Unit Tests
|
||||
run: |
|
||||
make check || (cat test/test-suite.log; false)
|
||||
- name: Upload Test Results
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: finit-test-${{ matrix.compiler }}
|
||||
path: test/*.log
|
||||
|
||||
@@ -4,6 +4,7 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- 'dev'
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
PROJECT_NAME: finit
|
||||
@@ -15,22 +16,39 @@ jobs:
|
||||
coverity:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
id: coverity-toolchain-cache
|
||||
with:
|
||||
path: cov-analysis-linux64
|
||||
key: ${{ runner.os }}-coverity
|
||||
- name: Download Coverity Scan
|
||||
if: steps.coverity-toolchain-cache.outputs.cache-hit != 'true'
|
||||
- uses: actions/checkout@v4
|
||||
- name: Fetch latest Coverity Scan MD5
|
||||
id: var
|
||||
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
|
||||
wget -q https://scan.coverity.com/download/cxx/linux64 \
|
||||
--post-data "token=$TOKEN&project=${COVERITY_PROJ}&md5=1" \
|
||||
-O coverity-latest.tar.gz.md5
|
||||
echo "md5=$(cat coverity-latest.tar.gz.md5)" | tee -a $GITHUB_OUTPUT
|
||||
- uses: actions/cache@v4
|
||||
id: cache
|
||||
with:
|
||||
path: coverity-latest.tar.gz
|
||||
key: ${{ runner.os }}-coverity-${{ steps.var.outputs.md5 }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-coverity-${{ steps.var.outputs.md5 }}
|
||||
${{ runner.os }}-coverity-
|
||||
${{ runner.os }}-coverity
|
||||
- name: Download Coverity Scan
|
||||
env:
|
||||
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
|
||||
run: |
|
||||
if [ ! -f coverity-latest.tar.gz ]; then
|
||||
wget -q https://scan.coverity.com/download/cxx/linux64 \
|
||||
--post-data "token=$TOKEN&project=${COVERITY_PROJ}" \
|
||||
-O coverity-latest.tar.gz
|
||||
else
|
||||
echo "Latest Coverity Scan available from cache :-)"
|
||||
md5sum coverity-latest.tar.gz
|
||||
fi
|
||||
mkdir coverity
|
||||
tar xzf coverity-latest.tar.gz --strip 1 -C coverity
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get -y update
|
||||
@@ -42,13 +60,15 @@ jobs:
|
||||
(cd libuev-2.4.0 && ./configure --prefix=/usr && make && sudo make install-strip)
|
||||
(cd libite-2.5.2 && ./configure --prefix=/usr && make && sudo make install-strip)
|
||||
sudo ldconfig
|
||||
- name: Build
|
||||
- name: Configure
|
||||
run: |
|
||||
./autogen.sh
|
||||
./configure --prefix= --enable-x11-common-plugin --with-watchdog --with-keventd
|
||||
export PATH=`pwd`/cov-analysis-linux64/bin:$PATH
|
||||
- name: Build
|
||||
run: |
|
||||
export PATH=`pwd`/coverity/bin:$PATH
|
||||
cov-build --dir cov-int make
|
||||
- name: Submit result to Coverity Scan
|
||||
- name: Submit results to Coverity Scan
|
||||
env:
|
||||
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
|
||||
run: |
|
||||
@@ -61,3 +81,8 @@ jobs:
|
||||
--form version=trunk \
|
||||
--form description="${PROJECT_NAME} $(git rev-parse HEAD)" \
|
||||
https://scan.coverity.com/builds?project=${COVERITY_PROJ}
|
||||
- name: Upload build.log
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: coverity-build.log
|
||||
path: cov-int/build-log.txt
|
||||
|
||||
@@ -10,18 +10,38 @@ jobs:
|
||||
name: Build and upload release tarball
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
MAKEFLAGS: -j3
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Installing dependencies ...
|
||||
run: |
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y install pkg-config jq libuev-dev libite-dev
|
||||
- name: Setting release variables ...
|
||||
id: build
|
||||
run: |
|
||||
ver=${GITHUB_REF#refs/tags/}
|
||||
echo "ver=${ver}" >> $GITHUB_OUTPUT
|
||||
if echo $ver | grep -qE '^[0-9]+\.[0-9]+(\.[0-9]+)?(-alpha|-beta|-rc)[0-9]*$'; then
|
||||
echo "pre=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "pre=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
if echo $ver | grep -qE '^[0-9.]+\.[0-9.]+(\.[0-9]+)?$'; then
|
||||
echo "latest=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "latest=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
- name: Creating Makefiles ...
|
||||
run: |
|
||||
./autogen.sh
|
||||
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
|
||||
--enable-x11-common-plugin --enable-testserv-plugin --with-watchdog \
|
||||
--with-keventd
|
||||
- name: Enable unprivileged userns (unshare)
|
||||
run: |
|
||||
sudo sysctl kernel.apparmor_restrict_unprivileged_userns=0
|
||||
- name: Build release ...
|
||||
run: |
|
||||
make release || (cat test/test-suite.log; false)
|
||||
@@ -36,5 +56,7 @@ jobs:
|
||||
- uses: ncipollo/release-action@v1
|
||||
with:
|
||||
name: Finit v${{ github.ref_name }}
|
||||
prerelease: ${{ steps.build.outputs.pre }}
|
||||
makeLatest: ${{ steps.build.outputs.latest }}
|
||||
bodyFile: "release.md"
|
||||
artifacts: "artifacts/*"
|
||||
|
||||
@@ -13,8 +13,9 @@ jobs:
|
||||
outputs:
|
||||
run: ${{ steps.check.outputs.run }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Check for any commits since last week
|
||||
id: schedule
|
||||
run: |
|
||||
commits="$(git log --format=%H --since='1 week ago')"
|
||||
if [ -n "$commits" ]; then
|
||||
@@ -22,7 +23,6 @@ jobs:
|
||||
else
|
||||
echo "run=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
distcheck:
|
||||
needs: schedule
|
||||
if: ${{ needs.schedule.outputs.run == 'true' }}
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
run: |
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y install pkg-config jq libuev-dev libite-dev
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Base run
|
||||
run: |
|
||||
./autogen.sh
|
||||
@@ -41,6 +41,9 @@ jobs:
|
||||
- name: Install to /tmp
|
||||
run: |
|
||||
DESTDIR=/tmp make install-strip
|
||||
- name: Enable unprivileged userns (unshare)
|
||||
run: |
|
||||
sudo sysctl kernel.apparmor_restrict_unprivileged_userns=0
|
||||
- name: Check dist tarball
|
||||
run: |
|
||||
ver=$(/tmp/sbin/initctl -V | awk '/Finit.*/ {print $2;}')
|
||||
|
||||
@@ -14,6 +14,7 @@ GTAGS
|
||||
/autom4te.cache
|
||||
/aclocal.m4
|
||||
/ar-lib
|
||||
/backup/
|
||||
/compile
|
||||
/config.cache
|
||||
/config.h
|
||||
@@ -36,6 +37,9 @@ GTAGS
|
||||
/test-driver
|
||||
/test-suite.log
|
||||
|
||||
# Misc
|
||||
/.gdb_history
|
||||
|
||||
# TroglOS build system
|
||||
/.config
|
||||
/.stamp
|
||||
|
||||
+288
-31
@@ -4,6 +4,257 @@ Change Log
|
||||
All relevant changes are documented in this file.
|
||||
|
||||
|
||||
[4.10][] - 2025-03-03
|
||||
---------------------
|
||||
|
||||
### Changes
|
||||
- Add support for `cleanup:[0-3600,]script`, runs before service is
|
||||
removed, unlike `post:script` that runs when service is stopped
|
||||
- Improved entropy gathering in tertiary fallback of urandom plugin
|
||||
- Reclassify `sysv` from run/task class to `service`
|
||||
|
||||
### Fixes
|
||||
- Fix #427: using an external getty with custom login program cause
|
||||
Finit to use login program as the getty command
|
||||
- Fix #428: allow `sysctl` path to be set at build time
|
||||
- Fix #429: regression in v4.9 causing Finit to segfault at shutdown
|
||||
- Fix possible memory leak when sourcing a service `env:file`
|
||||
- Finit now waits until all `post:scripts` have run before returning
|
||||
OK to `initctl <reload|runlevel>`. This also applies to the new
|
||||
`cleanup:scripts` introduced in this release
|
||||
- RFC3154 conformance formatting fix for `/dev/kmsg` fallback logging
|
||||
|
||||
|
||||
[4.9][] - 2025-02-15
|
||||
--------------------
|
||||
|
||||
> [!CAUTION]
|
||||
> This release changes how Finit reacts to the exit status of `pre:`
|
||||
> scripts. Finit will now no longer start the main process if its
|
||||
> `pre:` script fails for any reason. So, if you have pre scripts that,
|
||||
> e.g., create directories, make sure they are idempotent.
|
||||
|
||||
### Changes
|
||||
- Add individual timeout (optional) support for pre/post/ready scripts
|
||||
- Add support for systems with broken RTC, i.e., those that at power-on
|
||||
may reset the RTC to a random date instead of zero, issue #418
|
||||
- Add support for detecting "in-container" when in `systemd-nspawn`
|
||||
- Check exit status of `pre:` scripts, on failure drive service/sysv to
|
||||
`crashed` state. (The exit code of `post:` scripts remain ignored)
|
||||
- All pre/post/ready scripts are now also searched for in `$PATH`
|
||||
- Reset color attributes and clear screen when starting up. This is
|
||||
for boot loaders like GRUB, which leave background color artifacts
|
||||
|
||||
### Fixes
|
||||
- Fix #415: only mark reverse-dependencies "dirty" if the main service
|
||||
does not support SIGHUP. This helps avoid unnecessary restarts of
|
||||
services that depend on a service that supports SIGHUP
|
||||
- Fix #417: leaking inotify watchers in the cgroup subsystem
|
||||
- Fix #421: add support for `nofail` mount option in `/etc/fstab`
|
||||
- Fix #425: ordering bug in detecting .conf file changes to services
|
||||
and `initctl reload`, or runlevel changes
|
||||
- Fix `initctl touch` of template services, previously marking a
|
||||
service created from a template as "dirty" did not take
|
||||
- Fix unintended restart of template "siblings". I.e., `initctl touch`
|
||||
of instantiated template service A affected B from same template
|
||||
- Fix buggy `--with-rtc-date=DATE` configure option
|
||||
- Fix kill on timeout of pre/post/ready scripts
|
||||
|
||||
|
||||
[4.8][] - 2024-10-13
|
||||
--------------------
|
||||
|
||||
### Changes
|
||||
- Avoid remounting already mounted `/run` and `/tmp` directories. This
|
||||
extends the existing support for detecting mounted directories to
|
||||
include complex mount hierarchies are in use, overlayfs and tmpfs
|
||||
mounts. Feature by Mathias Thore, Atlas Copco
|
||||
- getty: trigger /etc/issue compat mode for Alpine Linux
|
||||
- tmpfiles.d: skip `x11.conf` unless X11 common plugin is enabled
|
||||
- tmpfiles.d: ignore x/X command, nos support for cleanup at runtime
|
||||
- Drop debug mode `-D` from `udevd` in `hotplug.conf.in`, allow the
|
||||
user to set this in `/etc/default/udevd` instead
|
||||
- Certain initctl APIs at bootstrap are not supported, update warning
|
||||
log to include command (number) for troubleshooting, issue #398
|
||||
- Add support for hwrng to urandom plugin and check for empty seed
|
||||
- Add `runparts -b` (batch mode) support, disables escape sequences
|
||||
- New configure `--without-rc-local`, disables `/etc/rc.local` support
|
||||
- New configure `--disable-cgroup` option, disables cgroup v2 detection
|
||||
- `initctl show template@foo.conf` now shows how an enabled template
|
||||
service has been evaluated by Finit, issue #411
|
||||
- Extend `initctl` timeout connecting and waiting for Finit reply. The
|
||||
previous 2 + 2 second poll timeout has proved to be too short on more
|
||||
complex systems. Now a 15 + 15 second timeout is applied which should
|
||||
be more resistant to temporary overload scenarios, issue #407
|
||||
|
||||
### Fixes
|
||||
- Fix #397: system shutdown/reboot can block on console input if action
|
||||
is started remotely (ssh). Caused by legact TTY screen size probing,
|
||||
removed from both bootstrap and shutdown/reboot
|
||||
- Fix #400: both `HOOK_MOUNT_ERROR` and `sulogin()` fail to trigger on
|
||||
either mount or `fsck` errors. Problem caused by unresolved status
|
||||
from pipe, calling `pclose()` without extracting exit status
|
||||
- Fix #402: `initctl touch` does not respect `-n` (no error) flag
|
||||
- Fix #403: `initctl touch` does not support template services
|
||||
- Fix #404: possible undefined behavior when `--with-fstab=no` is set
|
||||
- Fix #405: `@console` getty does not work with `tty0 ttyS0`
|
||||
- Fix #409: prevent tmpfiles from following symlinks for `L+` and `R`,
|
||||
otherwise symlink targets would also be removed. Found and fixed by
|
||||
Mathias Thore and Ming Liu, Atlas Copco
|
||||
- Fix #414: Frr Zebra immediately restarts on `initctl stop zebra`.
|
||||
The fix likely works for all Frr/Quagga services due to the way they
|
||||
create and delete their pid file
|
||||
- Cosmetic issue with `[ OK ]` messages being printed out of order at
|
||||
shutdown/reboot. Caused by nested calls to `service_stop()`
|
||||
- Cosmetic issue with duplicate "Restoring RTC" message at bootstrap
|
||||
|
||||
|
||||
[4.7][] - 2024-01-07
|
||||
--------------------
|
||||
|
||||
### Changes
|
||||
- Silence "not available" messages for run/task/service with `nowarn`
|
||||
- Update docs, `cgroup.root` workaround for `SCHED_RR` tasks
|
||||
- Drop runlevels 0 and 6 from `keventd`, not needed at reboot/poweroff
|
||||
- Mount `/dev/shm` with mode 1777 (sticky bit)
|
||||
- Mount `/dev/mqueue` if available, inspiration from Alpine Linux
|
||||
- Update Alpine Linux installer and configuration files, tested on
|
||||
Alpine v3.19, some assembly still required
|
||||
|
||||
### Fixes
|
||||
- Fix confusing warning message when tmpfiles.d fails to install symlink
|
||||
- Fix tmpfiles.d legacy `/run/lock/subsys`, ordering
|
||||
- Add missing `/var/tmp` and `/var/lock -> /run/lock` (tmpfiles.d)
|
||||
- Fix #388: log redirection broken unless Finit runs in debug mode.
|
||||
Found and fixed by Ryan Rorison
|
||||
- Fix #389: must libc requires `libgen.h` for `basename()` function.
|
||||
Reported and worked around with new `basenm()` function by Stargirl
|
||||
- Fix #392: `service/foo/ready` condition reasserted on pidfile removal
|
||||
|
||||
|
||||
[4.6][] - 2023-11-13
|
||||
--------------------
|
||||
|
||||
### Changes
|
||||
- Add support for service `notify:pid` and `readiness none` global
|
||||
option to change how Finit expects readiness notification, issue #386
|
||||
|
||||
### Fixes
|
||||
- Fix #383: dbus and runparts regression in Finit v4.5. The configure
|
||||
script must expand `FINIT_RUNPATH_` before defining it in `config.h`
|
||||
- Fix #384: service environment variables drop everything but the first
|
||||
argument, e.g., `VAR="foo bar qux"` drops everything but `foo`
|
||||
- Fix #385: internal conditions, e.g., `<int/bootstrap>` turn into flux
|
||||
when leaving bootstrap, causing depending services to stop
|
||||
- Fix #387: global environment variables declared with `set VAR=NAME` do
|
||||
not drop leading `set `, causing `'set VAR'='NAME'` in env.
|
||||
- Sanity check environment variables, for services and globally. Ensure
|
||||
the variable name (key) does not contain spaces, or a leading `set `
|
||||
|
||||
|
||||
[4.5][] - 2023-10-30
|
||||
--------------------
|
||||
|
||||
### Changes
|
||||
- Refactor `runparts` and `/etc/rc.local` to no longer block the main
|
||||
loop, allowing `initctl` calls to interact with Finit. Issue #356
|
||||
- Refactor the `run` stanza to no longer block the main loop, issue #362
|
||||
- Allow `sulogin` with a user different from `root`, issue #357
|
||||
- Allow disabling invocation of rescue mode from kernel command line
|
||||
- Add `initctl -f` to force-skip asking Finit for existing services
|
||||
when creating new services during bootstrap, e.g. `/etc/rc.local`
|
||||
- `initctl runlevel` now returns `N S` instead of `N 10` in bootstrap
|
||||
- `initctl runlevel N` during bootstrap is now allowed. It changes
|
||||
the next runlevel to go to when bootstrap has completed. Effectively
|
||||
overriding the `runlevel N` statement in `/etc/finit.conf`
|
||||
- Improved logging on failure to `execvp()` a run/task/service, now
|
||||
with `errno`, e.g., "No such file or directory" when the command
|
||||
is missing from `$PATH`
|
||||
- Add Bash completion support for `initctl`, configurable, issue #360
|
||||
- Handle absolute path to `initctl [enable|disable]`, not supported
|
||||
- Update `finit.conf(5)` man page with the recommended directory
|
||||
hierarchy in `/etc/finit.d/`
|
||||
- The `runparts` code has been split into `/libexec/finit/runparts`
|
||||
- The `runparts` command now takes two options: `sysv` and `progress`.
|
||||
The former ensures only `SNNfoo` and `KNNfoo` scripts are run.
|
||||
- Add SysV Init Compatibility section to documentation
|
||||
- Increased MAX path for commands, and arguments: 64 -> 256
|
||||
- The bundled watchdog daemon no longer tries to log at startup, because
|
||||
syslog is not available yet, any startup message leak to console
|
||||
- Extend `if:` option with runtime evaluation of conditions. E.g., start
|
||||
a task only `if:<run/foo/failure>` (here the run task 'foo' failed)
|
||||
- Document new `if:`, `conflict:`, `nowarn` options for run/task/service
|
||||
first introduced in v4.4
|
||||
- Failure to open fstab should log to console, not just log to `/dev/kmsg`
|
||||
- Rename `/lib/finit/system/*.conf`, added numbered prefix to ensure
|
||||
proper execution order, e.g., `udevd` should always run first
|
||||
- Plugins and bundled services: dbus, keventd, watchdogd, and runparts,
|
||||
are now loaded *after* all services in `/lib/finit/system/`. A new
|
||||
runtime-only path (for inspection) in `/run/finit/system/` is used
|
||||
- Redirect `log*` output to console when `finit.debug` is enabled
|
||||
- Assert `<int/container>` condition if we detect running in container
|
||||
- Add support for mdev's netlink daemon mode, issue #367
|
||||
- Add support for mdevd in `10-hotplug.conf`, preferred over plain mdev
|
||||
- Disable modprobe plugin by default, udevd and mdev/mdevd loads modules
|
||||
- Update documentation for run/task shell limitations, issue #376
|
||||
- Update documentation regarding automount of `/run` and `/tmp`
|
||||
- Update plugin documentation, add section about limited tmpfiles.d(5) support
|
||||
- Skip registering service when `if:!name` matches a known service.
|
||||
This allows conditional loading of alternative services, e.g. if udevd
|
||||
is already loaded we do not need mdevd
|
||||
- Drop `doc/bootstrap.md`, inaccurate and confusing to users
|
||||
|
||||
### Fixes
|
||||
- Fix #227: believed to have been fixed in v4.3, the root cause was
|
||||
actually that Finit was waiting for a process that was no longer in
|
||||
the system. The fix is to ask the kernel on process-stop-timeout and
|
||||
replay the lost PID so that Finit can continue with reboot/shutdown
|
||||
- Fix #358: fix inotify events for `/etc/finit.conf`, improved log
|
||||
messages and error handling
|
||||
- Fix #361: cgroup move fail if run/task/services start as non-root.
|
||||
Regression in the v4.4 release cycle while adding support for the
|
||||
pre:/post:/ready: scripts. Now the latter scripts also properly run
|
||||
in their correct cgroup
|
||||
- Fix #366: document `fsck.*` kernel command line options and simplify
|
||||
the configure flags `--enable-fsckfix` and `--enable-fastboot` to
|
||||
only adjust the default values for the `fsck.*` options.
|
||||
- Fix #371: swap load order of `/lib/finit/system/*` vs `/etc/finit.d/*`
|
||||
We must run `10-hotplug.conf` first to ensure devices and modules are
|
||||
up and loaded before the user's run/task/services are called. The order
|
||||
at bootstrap is now saved in `/run/finit/conf.order` for inspection,
|
||||
`/run/finit/exec.order` shows the start order of each process
|
||||
- Fix #372: lost `udevadm` calls due to overloading
|
||||
- Adjust final `udevadm settle` timeout: 5 -> 30 sec
|
||||
- Fixed dbus plugin, the function that located `<pidfile> ...` in the
|
||||
`dbus/system.conf` caused spurious line breaks which led to the
|
||||
service not being loaded properly
|
||||
- The `runparts` executor now skips backup files (`foo~`)
|
||||
- The `runparts` stanza now properly appends ` start` to scripts that
|
||||
start with `S[0-9]+`. This has been broken for a very long time.
|
||||
- Fix #377: expand service `env:file` variables, allow constructs like:
|
||||
|
||||
RUNDIR=/var/run/somesvc
|
||||
DAEMON_ARGS=--workdir $RUNDIR --other-args...
|
||||
- Fix #378: warn on console if run/task times out during bootstrap
|
||||
- Fix #378: add run/task support for `<!>` to allow transition from
|
||||
bootstrap to multi-user runlevel even though task has not run yet.
|
||||
- Fix #382: do not clear `<service/foo/STATE>` conditions on reload.
|
||||
Introduced back in v4.3-rc2, 82cc10be8, the support for automatic
|
||||
service conditions have had a weird and unintended behavior. Any
|
||||
change in state (see `doc/svc-machine.png`) caused Finit to clear
|
||||
out *all* previously acquired service conditions.
|
||||
|
||||
However, when moving between RUNNING and PAUSED states, a service
|
||||
should not have its conditions cleared. The PAUSED state, seen
|
||||
also by all conditions moving to FLUX, is only temporary while an
|
||||
`initctl reload` is processed. If a service has no changes to be
|
||||
applied it will move back to RUNNING.
|
||||
|
||||
Also, we cannot clear the service conditions because other run/task
|
||||
or services may depend on it and clearing them would cause Finit to
|
||||
`SIGTERM` these processes (since they are no longer eligible to run).
|
||||
|
||||
|
||||
[4.4][] - 2023-05-15
|
||||
--------------------
|
||||
|
||||
@@ -1510,39 +1761,45 @@ Major bug fix release.
|
||||
|
||||
* Initial release
|
||||
|
||||
[UNRELEASED]: https://github.com/troglobit/finit/compare/4.3...HEAD
|
||||
[4.4]: https://github.com/troglobit/finit/compare/4.3...4.4
|
||||
[4.3]: https://github.com/troglobit/finit/compare/4.2...4.3
|
||||
[4.2]: https://github.com/troglobit/finit/compare/4.1...4.2
|
||||
[4.1]: https://github.com/troglobit/finit/compare/4.0...4.1
|
||||
[4.0]: https://github.com/troglobit/finit/compare/3.1...4.0
|
||||
[3.1]: https://github.com/troglobit/finit/compare/3.0...3.1
|
||||
[3.0]: https://github.com/troglobit/finit/compare/2.4...3.0
|
||||
[2.4]: https://github.com/troglobit/finit/compare/2.3...2.4
|
||||
[2.3]: https://github.com/troglobit/finit/compare/2.2...2.3
|
||||
[2.2]: https://github.com/troglobit/finit/compare/2.1...2.2
|
||||
[2.1]: https://github.com/troglobit/finit/compare/2.0...2.1
|
||||
[2.0]: https://github.com/troglobit/finit/compare/1.12...2.0
|
||||
[UNRELEASED]: https://github.com/troglobit/finit/compare/4.10...HEAD
|
||||
[4.10]: https://github.com/troglobit/finit/compare/4.9...4.10
|
||||
[4.9]: https://github.com/troglobit/finit/compare/4.8...4.9
|
||||
[4.8]: https://github.com/troglobit/finit/compare/4.7...4.8
|
||||
[4.7]: https://github.com/troglobit/finit/compare/4.6...4.7
|
||||
[4.6]: https://github.com/troglobit/finit/compare/4.5...4.6
|
||||
[4.5]: https://github.com/troglobit/finit/compare/4.4...4.5
|
||||
[4.4]: https://github.com/troglobit/finit/compare/4.3...4.4
|
||||
[4.3]: https://github.com/troglobit/finit/compare/4.2...4.3
|
||||
[4.2]: https://github.com/troglobit/finit/compare/4.1...4.2
|
||||
[4.1]: https://github.com/troglobit/finit/compare/4.0...4.1
|
||||
[4.0]: https://github.com/troglobit/finit/compare/3.1...4.0
|
||||
[3.1]: https://github.com/troglobit/finit/compare/3.0...3.1
|
||||
[3.0]: https://github.com/troglobit/finit/compare/2.4...3.0
|
||||
[2.4]: https://github.com/troglobit/finit/compare/2.3...2.4
|
||||
[2.3]: https://github.com/troglobit/finit/compare/2.2...2.3
|
||||
[2.2]: https://github.com/troglobit/finit/compare/2.1...2.2
|
||||
[2.1]: https://github.com/troglobit/finit/compare/2.0...2.1
|
||||
[2.0]: https://github.com/troglobit/finit/compare/1.12...2.0
|
||||
[1.12]: https://github.com/troglobit/finit/compare/1.11...1.12
|
||||
[1.11]: https://github.com/troglobit/finit/compare/1.10...1.11
|
||||
[1.10]: https://github.com/troglobit/finit/compare/1.9...1.10
|
||||
[1.9]: https://github.com/troglobit/finit/compare/1.8...1.9
|
||||
[1.8]: https://github.com/troglobit/finit/compare/1.7...1.8
|
||||
[1.7]: https://github.com/troglobit/finit/compare/1.6...1.7
|
||||
[1.6]: https://github.com/troglobit/finit/compare/1.5...1.6
|
||||
[1.5]: https://github.com/troglobit/finit/compare/1.4...1.5
|
||||
[1.4]: https://github.com/troglobit/finit/compare/1.3...1.4
|
||||
[1.3]: https://github.com/troglobit/finit/compare/1.2...1.3
|
||||
[1.2]: https://github.com/troglobit/finit/compare/1.1...1.2
|
||||
[1.1]: https://github.com/troglobit/finit/compare/1.0...1.1
|
||||
[1.0]: https://github.com/troglobit/finit/compare/0.9...1.0
|
||||
[0.9]: https://github.com/troglobit/finit/compare/0.8...0.9
|
||||
[0.8]: https://github.com/troglobit/finit/compare/0.7...0.8
|
||||
[0.7]: https://github.com/troglobit/finit/compare/0.6...0.7
|
||||
[0.6]: https://github.com/troglobit/finit/compare/0.5...0.6
|
||||
[0.5]: https://github.com/troglobit/finit/compare/0.4...0.5
|
||||
[0.4]: https://github.com/troglobit/finit/compare/0.3...0.4
|
||||
[0.3]: https://github.com/troglobit/finit/compare/0.2...0.3
|
||||
[0.2]: https://github.com/troglobit/finit/compare/0.1...0.2
|
||||
[1.9]: https://github.com/troglobit/finit/compare/1.8...1.9
|
||||
[1.8]: https://github.com/troglobit/finit/compare/1.7...1.8
|
||||
[1.7]: https://github.com/troglobit/finit/compare/1.6...1.7
|
||||
[1.6]: https://github.com/troglobit/finit/compare/1.5...1.6
|
||||
[1.5]: https://github.com/troglobit/finit/compare/1.4...1.5
|
||||
[1.4]: https://github.com/troglobit/finit/compare/1.3...1.4
|
||||
[1.3]: https://github.com/troglobit/finit/compare/1.2...1.3
|
||||
[1.2]: https://github.com/troglobit/finit/compare/1.1...1.2
|
||||
[1.1]: https://github.com/troglobit/finit/compare/1.0...1.1
|
||||
[1.0]: https://github.com/troglobit/finit/compare/0.9...1.0
|
||||
[0.9]: https://github.com/troglobit/finit/compare/0.8...0.9
|
||||
[0.8]: https://github.com/troglobit/finit/compare/0.7...0.8
|
||||
[0.7]: https://github.com/troglobit/finit/compare/0.6...0.7
|
||||
[0.6]: https://github.com/troglobit/finit/compare/0.5...0.6
|
||||
[0.5]: https://github.com/troglobit/finit/compare/0.4...0.5
|
||||
[0.4]: https://github.com/troglobit/finit/compare/0.3...0.4
|
||||
[0.3]: https://github.com/troglobit/finit/compare/0.2...0.3
|
||||
[0.2]: https://github.com/troglobit/finit/compare/0.1...0.2
|
||||
[libuEv]: https://github.com/troglobit/libuev
|
||||
[dea3ae8]: https://github.com/troglobit/finit/commit/dea3ae8
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
Copyright (c) 2008-2024 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
|
||||
|
||||
+8
-3
@@ -10,6 +10,10 @@ if DOC
|
||||
SUBDIRS += doc
|
||||
endif
|
||||
|
||||
if BASH
|
||||
bashdir = $(BASH_DIR)
|
||||
dist_bash_DATA = initctl
|
||||
endif
|
||||
# Compat hook
|
||||
install-dev:
|
||||
@make -C src install-pkgincludeHEADERS
|
||||
@@ -30,6 +34,7 @@ release: distcheck
|
||||
printf "$$file.sha256\t"; cat ../$$file.sha256 | cut -f1 -d' '; \
|
||||
done
|
||||
|
||||
DISTCHECK_CONFIGURE_FLAGS = --prefix=/usr --sysconfdir=/etc --localstatedir=/var \
|
||||
--enable-testserv-plugin --enable-x11-common-plugin \
|
||||
--with-watchdog --with-keventd --with-fstab=/etc/fstab
|
||||
DISTCHECK_CONFIGURE_FLAGS = --prefix=/usr --sysconfdir=/etc --localstatedir=/var \
|
||||
--enable-testserv-plugin --enable-x11-common-plugin \
|
||||
--with-watchdog --with-keventd --with-fstab=/etc/fstab \
|
||||
--with-bash-completion-dir=no
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [Features](#features)
|
||||
* [Bootstrap](doc/bootstrap.md#bootstrap)
|
||||
* [Runlevels](#runlevels)
|
||||
* [Syntax](doc/config.md#syntax)
|
||||
* [Runparts & /etc/rc.local](#runparts--etcrclocal)
|
||||
@@ -23,11 +22,10 @@ Introduction
|
||||
------------
|
||||
|
||||
Fast init for Linux systems. Reverse engineered from the [EeePC
|
||||
fastinit][] over ten years ago by [Claudio Matsuoka][] — "gaps filled
|
||||
with frog DNA …"
|
||||
fastinit][] by [Claudio Matsuoka][] — "gaps filled with frog DNA …"
|
||||
|
||||

|
||||
*Figure 1: Screenshot showing Finit booting [Alpine Linux](https://www.alpinelinux.org/).*
|
||||

|
||||
*Figure 1: Screenshot of Finit booting [Alpine Linux (HowTo)](https://github.com/troglobit/finit/tree/master/contrib/alpine).*
|
||||
|
||||
Features include:
|
||||
|
||||
@@ -66,7 +64,9 @@ distributions:
|
||||
> **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][].
|
||||
> Custom setups, e.g., for embedded systems, can be found in any of the
|
||||
> following [Buildroot][] based examples: [myLinux][], [Infix][], or the
|
||||
> plain [br2-finit-demo](https://github.com/troglobit/br2-finit-demo).
|
||||
|
||||
|
||||
Example
|
||||
@@ -391,8 +391,7 @@ Right after the runlevel change when all services have started properly,
|
||||
No configuration stanza in `/etc/finit.conf` is required for `rc.local`.
|
||||
If it exists and is an executable shell script Finit calls it at the very
|
||||
end of the boot, before calling the `HOOK_SYSTEM_UP`. See more on hooks
|
||||
in [doc/plugins.md](doc/plugins.md#hooks), and about the system bootstrap
|
||||
in [doc/bootstrap.md](doc/bootstrap.md).
|
||||
in [doc/plugins.md](doc/plugins.md#hooks).
|
||||
|
||||
|
||||
### Limitations
|
||||
@@ -406,8 +405,7 @@ The event loop is the whole thing which Finit is built around, except
|
||||
for runlevel S, which remains a slow procession through a lot of set up,
|
||||
with a few hooks and blocking call outs to external scripts.
|
||||
|
||||
However, not all `initctl` commands are prohibited, supported commands:
|
||||
are:
|
||||
However, not all `initctl` commands are prohibited. Supported commands:
|
||||
|
||||
- `inictl cond`: only operate of files in `/run/finit/cond`
|
||||
- `initctl enable/disable`: enabled run/task/service is activated on
|
||||
@@ -707,6 +705,8 @@ and proposed extensions.
|
||||
[EeePC fastinit]: https://web.archive.org/web/20071208212450/http://wiki.eeeuser.com/boot_process:the_boot_process
|
||||
[Claudio Matsuoka]: https://github.com/cmatsuoka
|
||||
[Joachim Wiberg]: https://troglobit.com
|
||||
[Buildroot]: https://buildroot.org
|
||||
[Infix]: https://kernelkit.github.io
|
||||
[finit.conf(5)]: https://man.troglobit.com/man5/finit.conf.5.html
|
||||
[License]: https://en.wikipedia.org/wiki/MIT_License
|
||||
[License Badge]: https://img.shields.io/badge/License-MIT-teal.svg
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
# Run test suite with the correct configure params
|
||||
|
||||
make distclean
|
||||
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
|
||||
--enable-x11-common-plugin --with-watchdog --with-keventd
|
||||
make -j17 clean check
|
||||
+89
-24
@@ -1,4 +1,5 @@
|
||||
AC_INIT([Finit],[4.4],[https://github.com/troglobit/finit/issues],[finit],[https://troglobit.com/projects/finit/])
|
||||
AC_INIT([Finit], [4.10], [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])
|
||||
@@ -14,10 +15,10 @@ AC_CONFIG_FILES([Makefile
|
||||
man/Makefile
|
||||
plugins/Makefile
|
||||
src/Makefile
|
||||
system/Makefile
|
||||
tmpfiles.d/Makefile
|
||||
system/Makefile system/10-hotplug.conf
|
||||
test/test.env test/Makefile
|
||||
test/lib/Makefile test/src/Makefile])
|
||||
test/lib/Makefile test/src/Makefile
|
||||
tmpfiles.d/Makefile])
|
||||
|
||||
# Older versions of autoconf (<2.58) do not have AC_CONFIG_MACRO_DIR()
|
||||
#m4_include([m4/plugin.m4])
|
||||
@@ -66,12 +67,20 @@ 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(cgroup,
|
||||
AS_HELP_STRING([--disable-cgroup], [Disable cgroup v2 support, default: autodetect from /sys/fs/cgroup]),,[
|
||||
enable_cgroup=yes])
|
||||
|
||||
AC_ARG_ENABLE(redirect,
|
||||
AS_HELP_STRING([--disable-redirect], [Disable redirection of service output to /dev/null]),,[
|
||||
enable_redirect=yes])
|
||||
|
||||
AC_ARG_ENABLE(kernel_logging,
|
||||
AS_HELP_STRING([--disable-kernel-logging], [Disable kernel logging to console (use 'quiet' instead!]),,[
|
||||
enable_kernel_logging=yes])
|
||||
|
||||
AC_ARG_ENABLE(logrotate,
|
||||
AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp, default enabled]),,[
|
||||
AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp]),,[
|
||||
enable_logrotate=yes])
|
||||
|
||||
AC_ARG_ENABLE(doc,
|
||||
@@ -82,6 +91,10 @@ AC_ARG_ENABLE(contrib,
|
||||
AS_HELP_STRING([--disable-contrib], [Disable build and install of contrib section]),,[
|
||||
enable_contrib=yes])
|
||||
|
||||
AC_ARG_ENABLE([rescue],
|
||||
AS_HELP_STRING([--disable-rescue], [Disable potentially unsafe rescue mode]),,
|
||||
[enable_rescue=yes])
|
||||
|
||||
# Check for extra plugins to enable
|
||||
AC_ARG_ENABLE(all_plugins,
|
||||
AS_HELP_STRING([--enable-all-plugins], [Enable all plugins, default: auto]),
|
||||
@@ -89,18 +102,22 @@ AC_ARG_ENABLE(all_plugins,
|
||||
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([modprobe], [no], [Coldplug modules using modalias magic])
|
||||
AC_PLUGIN([resolvconf], [no], [Setup necessary files for resolvconf])
|
||||
AC_PLUGIN([x11-common], [no], [Console setup (for X)])
|
||||
AC_PLUGIN([netlink], [yes], [Basic netlink plugin for IFUP/IFDN and GW events. Can be replaced with externally built plugin that links with libnl or similar.])
|
||||
AC_PLUGIN([hook-scripts], [no], [Trigger script execution from hook points])
|
||||
AC_PLUGIN([hotplug], [yes], [Setup and start udev or mdev hotplug daemon])
|
||||
AC_PLUGIN([hotplug], [yes], [Start udevd or mdev kernel event datamon])
|
||||
AC_PLUGIN([rtc], [yes], [Save and restore RTC using hwclock])
|
||||
AC_PLUGIN([tty], [yes], [Automatically activate new TTYs, e.g. USB-to-serial])
|
||||
AC_PLUGIN([urandom], [yes], [Setup and save random seed at boot/shutdown])
|
||||
AC_PLUGIN([testserv], [no], [Test plugin to start test serv daemon])
|
||||
|
||||
# Check for extra arguments or packages
|
||||
AC_ARG_WITH([bash-completion-dir],
|
||||
AS_HELP_STRING([--with-bash-completion-dir[=PATH]], [Directory to install Bash completion, default: auto]),
|
||||
[bash_dir=$withval], [bash_dir=yes])
|
||||
|
||||
AC_ARG_WITH(fstab,
|
||||
AS_HELP_STRING([--with-fstab=FILE], [System default fstab, default $sysconfdir/fstab]),
|
||||
[fstab=$withval], [fstab=yes])
|
||||
@@ -145,10 +162,10 @@ 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])
|
||||
AS_HELP_STRING([--with-sulogin@<:@=USER@:>@], [Enable built-in sulogin, optional USER to request password for (default root), default: no.]),[sulogin=$withval],[with_sulogin=no])
|
||||
|
||||
AC_ARG_WITH(watchdog,
|
||||
AS_HELP_STRING([--with-watchdog=[DEV]], [Enable built-in watchdog, default: /dev/watchdog]),
|
||||
AS_HELP_STRING([--with-watchdog@<:@=DEV@:>@], [Enable built-in watchdog, default: /dev/watchdog]),
|
||||
[watchdog=$withval], [with_watchdog=no watchdog=])
|
||||
|
||||
AC_ARG_WITH(hook-scripts-path,
|
||||
@@ -160,9 +177,13 @@ AC_ARG_WITH(plugin-path,
|
||||
[plugin_path=$withval], [plugin_path=yes])
|
||||
|
||||
AC_ARG_WITH(rtc-date,
|
||||
AS_HELP_STRING([--with-rtc-date=DATE], [If RTC date/time is too old, restore to DATE, format "YYYY-MM-DD HH:MM", default "2000-01-01 00:00"]),
|
||||
AS_HELP_STRING([--with-rtc-date=DATE], [If RTC date/time is too old, restore to DATE, format "YYYY-MM-DD HH:MM:SS", default "2000-01-01 00:00:00"]),
|
||||
[rtc_date=$withval], [rtc_date=no])
|
||||
|
||||
AC_ARG_WITH(rtc-file,
|
||||
AS_HELP_STRING([--with-rtc-file=FILE], [If RTC is missing, save and restore system clock from this file, default: no]),
|
||||
[rtc_file=$withval], [rtc_file=no])
|
||||
|
||||
### Enable features ###########################################################################
|
||||
|
||||
# Create config.h from selected features and fallback defaults
|
||||
@@ -172,6 +193,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_kernel_logging" = "xyes"], [
|
||||
AC_DEFINE(KERNEL_LOGGING, 1, [Keep kernel warn/err logs to console])])
|
||||
|
||||
AS_IF([test "x$enable_cgroup" = "xyes"], [
|
||||
AC_DEFINE(CGROUP2_ENABLED, 1, [Autodetect cgroup v2 support from /sys/fs/cgroup])])
|
||||
|
||||
AS_IF([test "x$enable_fastboot" = "xyes"], [
|
||||
AC_DEFINE(FAST_BOOT, 1, [Skip fsck check on filesystems listed in /etc/fstab])])
|
||||
|
||||
@@ -185,9 +212,18 @@ AS_IF([test "x$enable_redirect" = "xyes"], [
|
||||
AS_IF([test "x$enable_logrotate" != "xno"], [
|
||||
AC_DEFINE(LOGROTATE_ENABLED, 1, [Enable built-in rotation of /var/log/wtmp et al.])])
|
||||
|
||||
AS_IF([test "x$enable_rescue" != "xno"], [
|
||||
AC_DEFINE([RESCUE_MODE], 1, [Define to enable support for rescue mode.])])
|
||||
|
||||
AM_CONDITIONAL(LOGROTATE, [test "x$enable_logrotate" = "xyes"])
|
||||
|
||||
### With features ##############################################################################
|
||||
AS_IF([test "x$bash_dir" = "xyes"], [
|
||||
PKG_CHECK_MODULES([BASH_COMPLETION], [bash-completion >= 2.0],
|
||||
[BASH_DIR="$(pkg-config --variable=completionsdir bash-completion)"],
|
||||
[BASH_DIR="$datadir/bash-completion/completions"])], [
|
||||
BASH_DIR="$bash_dir"])
|
||||
|
||||
AS_IF([test "x$with_fstab" != "xno"], [
|
||||
AS_IF([test "x$fstab" = "xyes"], [fstab=$sysconfdir/fstab])
|
||||
AC_EXPAND_DIR(fstab_path, "$fstab")
|
||||
@@ -209,10 +245,9 @@ AC_DEFINE_UNQUOTED(FINIT_RCSD, "$rcsd_path", [Finit rcS.d/, default /etc/finit.d
|
||||
AC_SUBST(FINIT_RCSD, "$rcsd_path")
|
||||
|
||||
AS_IF([test "x$with_rc_local" != "xno"], [
|
||||
AS_IF([test "x$rclocal" = "xyes"], [
|
||||
rclocal=$sysconfdir/rc.local])])
|
||||
AC_EXPAND_DIR(rclocal_path, "$rclocal")
|
||||
AC_DEFINE_UNQUOTED(FINIT_RC_LOCAL, "$rclocal_path", [Compat SysV /etc/rc.local file to run last at boot.])
|
||||
AS_IF([test "x$rclocal" = "xyes"], [rclocal=$sysconfdir/rc.local])
|
||||
AC_EXPAND_DIR(rclocal_path, "$rclocal")
|
||||
AC_DEFINE_UNQUOTED(FINIT_RC_LOCAL, "$rclocal_path", [Compat SysV /etc/rc.local file to run last at boot.])])
|
||||
|
||||
AS_IF([test "x$with_sysconfig" != "xno"], [
|
||||
AS_IF([test "x$sysconfig" != "xdefault"], [
|
||||
@@ -247,12 +282,24 @@ AS_IF([test "x$with_random_seed" != "xno"], [
|
||||
AC_DEFINE_UNQUOTED(RANDOMSEED, "$random_path", [Improve random at boot by seeding it with sth from before.])])
|
||||
|
||||
AS_IF([test "x$rtc_date" != "xno"], [
|
||||
AC_DEFINE(RTC_TIMESTAMP_CUSTOM, "$rtc_date", [Custom RTC restore date, default: 2000-01-01 00:00])], [
|
||||
AC_DEFINE_UNQUOTED(RTC_TIMESTAMP_CUSTOM, "$rtc_date", [Custom RTC restore date, default: 2000-01-01 00:00])], [
|
||||
rtc_date=""])
|
||||
|
||||
AS_IF([test "x$rtc_file" != "xno"], [
|
||||
AS_IF([test "x$rtc_file" = "xyes"], [
|
||||
rtc_file=/var/lib/misc/rtc])
|
||||
AC_EXPAND_DIR(rtcfile_path, "$rtc_file")
|
||||
AC_DEFINE_UNQUOTED(RTC_FILE, "$rtcfile_path", [Save and restore system time from this file if /dev/rtc is missing.])],[
|
||||
AC_DEFINE_UNQUOTED(RTC_FILE, NULL)])
|
||||
|
||||
AS_IF([test "x$with_keventd" != "xno"], [with_keventd=yes])
|
||||
|
||||
AS_IF([test "x$with_sulogin" != "xno"], [with_sulogin=yes])
|
||||
AS_IF([test "x$with_sulogin" != "xno"], [
|
||||
AS_IF([test "x$sulogin" = "xyes"], [
|
||||
sulogin=root])
|
||||
with_sulogin=yes
|
||||
AC_DEFINE_UNQUOTED(SULOGIN_USER, "$sulogin", [Built-in sulogin user, default: root])], [
|
||||
sulogin=])
|
||||
|
||||
AS_IF([test "x$with_watchdog" != "xno"], [
|
||||
AS_IF([test "x$watchdog" = "xyes"], [
|
||||
@@ -272,19 +319,27 @@ AS_IF([test "x$with_plugin_path" != "xno"], [
|
||||
AC_DEFINE_UNQUOTED(EXTERNAL_PLUGIN_PATH, "$plugin_path", [Built-in default: /usr/lib/finit/plugins:/usr/local/lib/finit/plugins])])
|
||||
|
||||
# Control build with automake flags
|
||||
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
||||
AM_CONDITIONAL(BASH, [test "x$bash_dir" != "xno"])
|
||||
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(DOC, [test "x$enable_doc" = "xyes"])
|
||||
AM_CONDITIONAL(CONTRIB, [test "x$enable_contrib" = "xyes"])
|
||||
AM_CONDITIONAL(TESTSERV, [test "x$enable_testserv_plugin" = "xyes"])
|
||||
|
||||
# Workaround for as-of-yet unreleased runstatedir support, planned for
|
||||
# autoconf 2.70, which some major distros have backported.
|
||||
AS_IF([test -z "$runstatedir"], runstatedir="$localstatedir/run")
|
||||
AC_SUBST(runstatedir)
|
||||
|
||||
# Override default libdir, used for plugins and rescue.conf
|
||||
pkglibdir=$libdir/finit
|
||||
AC_SUBST(pkglibexecdir)
|
||||
AC_EXPAND_DIR(pkglibexecdir, "$libexecdir/finit")
|
||||
AC_DEFINE_UNQUOTED(FINIT_EXECPATH_, "$pkglibexecdir", [Finit libexec path])
|
||||
AC_EXPAND_DIR(finit_runpath, "$runstatedir/finit/system")
|
||||
AC_DEFINE_UNQUOTED(FINIT_RUNPATH_, "$finit_runpath", [Finit runtime dynamic system services])
|
||||
|
||||
AC_EXPAND_DIR(plugin_path, "$pkglibdir/plugins")
|
||||
AC_SUBST(plugin_path)
|
||||
@@ -292,7 +347,7 @@ AC_DEFINE_UNQUOTED(PLUGIN_PATH, "$plugin_path", [Finit plugin path])
|
||||
|
||||
AC_EXPAND_DIR(tmpfiles_path, "$libdir/tmpfiles.d")
|
||||
AC_SUBST(tmpfiles_path)
|
||||
AC_DEFINE_UNQUOTED(TMPFILES_PATH, "$tmpfiles_path", [Main tmpfiles.d/, override in /etc])
|
||||
AC_DEFINE_UNQUOTED(TMPFILES_PATH_, "$tmpfiles_path", [Main tmpfiles.d/, override in /etc])
|
||||
|
||||
AC_EXPAND_DIR(finit_tmpfiles, "$pkglibdir/tmpfiles.d")
|
||||
AC_SUBST(finit_tmpfiles)
|
||||
@@ -300,13 +355,16 @@ AC_DEFINE_UNQUOTED(FINIT_TMPFILES, "$finit_tmpfiles", [Finit tmpfiles.d/ .conf p
|
||||
|
||||
AC_EXPAND_DIR(system_path, "$pkglibdir/system")
|
||||
AC_SUBST(system_path)
|
||||
AC_DEFINE_UNQUOTED(FINIT_SYSPATH, "$system_path", [Static services, previously generated at runtime by plugins])
|
||||
AC_DEFINE_UNQUOTED(FINIT_SYSPATH_, "$system_path", [Static services, previously generated at runtime by plugins])
|
||||
|
||||
AC_EXPAND_DIR(rescue_conf, "$pkglibdir/rescue.conf")
|
||||
AC_DEFINE_UNQUOTED(RESCUE_CONF, "$rescue_conf", [Finit rescue mode .conf])
|
||||
AC_EXPAND_DIR(sample_conf, "$pkglibdir/sample.conf")
|
||||
AC_DEFINE_UNQUOTED(SAMPLE_CONF, "$sample_conf", [Finit sameple.conf for initctl create])
|
||||
|
||||
AC_EXPAND_DIR(bash_completion_dir, "$BASH_DIR")
|
||||
AC_SUBST(BASH_DIR, "$bash_completion_dir")
|
||||
|
||||
AS_IF([test "$heading" = ""], [heading="<DEFAULT>"])
|
||||
AS_IF([test "$heading" = "no"], [heading="<NONE>"])
|
||||
|
||||
@@ -321,15 +379,16 @@ cat <<EOF
|
||||
|
||||
------------------ Summary ------------------
|
||||
$PACKAGE_NAME version $PACKAGE_VERSION
|
||||
Prefix................: $prefix
|
||||
Exec prefix...........: $eprefix
|
||||
Prefix................: $(eval echo $prefix)
|
||||
Exec prefix...........: $(eval echo $exec_prefix)
|
||||
Libdir................: $(eval echo $libdir)
|
||||
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
|
||||
Compat rc.local path..: $rclocal_path
|
||||
Compat rc.local path..: `eval echo $rclocal`
|
||||
System environment....: ${sysconfig_path:-${sysconfig}}
|
||||
Random seed path......: $random_path
|
||||
C Compiler............: $CC $CFLAGS $CPPFLAGS $LDFLAGS $LIBS
|
||||
@@ -339,17 +398,23 @@ Behavior:
|
||||
Boot heading..........: $heading
|
||||
Plugins...............: $plugins
|
||||
RTC restore date......: $RTC_DATE
|
||||
RTC fallback file.....: $rtc_file
|
||||
|
||||
Optional features:
|
||||
Install doc/..........: $enable_doc
|
||||
Install contrib/......: $enable_contrib
|
||||
Bash completion.......: $bash_completion_dir
|
||||
Built-in keventd......: $with_keventd
|
||||
Built-in sulogin......: $with_sulogin
|
||||
Built-in sulogin......: $with_sulogin $sulogin
|
||||
Built-in watchdogd....: $with_watchdog $watchdog
|
||||
Built-in logrotate....: $enable_logrotate
|
||||
Use cgroup v2.........: $enable_cgroup
|
||||
Parse kernel cmdline..: $enable_kernel_cmdline
|
||||
Keep kernel logging...: $enable_kernel_logging
|
||||
Skip fsck check.......: $enable_fastboot
|
||||
Run fsck fix mode.....: $enable_fsckfix
|
||||
Redirect output.......: $enable_redirect
|
||||
Rescue mode...........: $enable_rescue
|
||||
Default hostname......: $hostname
|
||||
Default group.........: $group
|
||||
Default runlevel......: $runlevel
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
HowTo: Finit on Alpine Linux 3.4-3.6
|
||||
====================================
|
||||
HowTo: Finit on Alpine Linux 3.4...3.19
|
||||
=======================================
|
||||
|
||||
> **Blog** https://troglobit.com/post/2021-02-12-alpine-linux-with-finit/
|
||||
|
||||
HowTo use Finit to boot an [Alpine Linux][] system. It is assumed that
|
||||
the user has already installed make, a compiler, C library header files,
|
||||
|
||||
@@ -17,7 +17,7 @@ PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig ./configure \
|
||||
--prefix=/usr --exec-prefix= \
|
||||
--sysconfdir=/etc --localstatedir=/var \
|
||||
--enable-dbus-plugin --enable-x11-common-plugin \
|
||||
--enable-alsa-utils-plugin --with-watchdog \
|
||||
--enable-alsa-utils-plugin --without-watchdog \
|
||||
--with-keventd --with-sulogin
|
||||
|
||||
echo
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
SUBDIRS = available
|
||||
docsdir := @docdir@/contrib/alpine/finit.d
|
||||
d_LINKS = acpid.conf crond.conf dropbear.conf getty.conf \
|
||||
keymap.conf modules.conf ntpd.conf \
|
||||
klogd.conf syslogd.conf
|
||||
keymap.conf modules.conf ntpd.conf syslogd.conf
|
||||
|
||||
install-exec-hook:
|
||||
@$(MKDIR_P) $(DESTDIR)$(docsdir)/available
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
docsdir := @docdir@/contrib/alpine/finit.d/available
|
||||
docs_DATA = acpid.conf crond.conf dropbear.conf getty.conf keymap.conf \
|
||||
lxdm.conf modules.conf ntpd.conf syslog.conf watchdog.conf
|
||||
lxdm.conf modules.conf ntpd.conf syslogd.conf watchdog.conf
|
||||
EXTRA_DIST = $(docs_DATA)
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
#module evdev
|
||||
#module mousedev
|
||||
#module 8139cp
|
||||
module softdog
|
||||
#module softdog
|
||||
|
||||
+35
-29
@@ -1,45 +1,53 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ "x`id -u`" != "x0" ]; then
|
||||
echo
|
||||
echo "*** This script must run as root"
|
||||
echo
|
||||
if [ "$(id -u)" != "0" ]; then
|
||||
printf "\n\e[1m*** This script must run as root\e[0m\n\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC3037,SC3045,SC2154
|
||||
yorn()
|
||||
{
|
||||
printf "\e[1m> %s (y/N)?\e[0m " "$*"
|
||||
read -rn1 yorn
|
||||
echo
|
||||
|
||||
if [ "$yorn" = "y" ] || [ "$yorn" = "Y" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Adjust base directory
|
||||
grep -q alpine Makefile 2>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
if grep -q contrib/alpine Makefile 2>/dev/null; then
|
||||
cd ../..
|
||||
elif [ ! -e configure.ac ]; then
|
||||
echo "*** Please run this script from the Finit base directory."
|
||||
fi
|
||||
|
||||
if [ ! -e configure.ac ]; then
|
||||
printf "\n\e[1m*** Please run this script from the Finit base directory.\e[0m\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "*** Install Finit on Alpine Linux"
|
||||
echo "========================================================================"
|
||||
echo "/sbin/finit - PID 1"
|
||||
echo "/lib/finit/plugins/* - All enabled Finit plugins"
|
||||
echo "/etc/finit.conf - Finit configuration file"
|
||||
echo "/etc/finit.d/ - Finit services"
|
||||
echo
|
||||
read -p "Do you want to continue (y/N)? " yorn
|
||||
printf "\n\e[1mInstall Finit on Alpine Linux\n"
|
||||
printf "========================================================================\e[0m\n"
|
||||
printf "/sbin/finit - PID 1\n"
|
||||
printf "/lib/finit/plugins/* - All enabled Finit plugins\n"
|
||||
printf "/etc/finit.conf - Finit configuration file\n"
|
||||
printf "/etc/finit.d/ - Finit services\n"
|
||||
|
||||
if [ "x$yorn" = "xy" -o "x$yorn" = "xY" ]; then
|
||||
echo
|
||||
echo "*** Installing Finit files ..."
|
||||
if yorn "Do you want to continue"; then
|
||||
printf "\n\e[1m*** Installing Finit files ...\e[0m\n"
|
||||
make install
|
||||
cd /usr/share/doc/finit/contrib/alpine
|
||||
cd /usr/share/doc/finit/contrib/alpine || exit 1
|
||||
for file in finit.conf rc.local; do
|
||||
install -vbD $file /etc/$file
|
||||
done
|
||||
cp -va finit.d /etc/
|
||||
|
||||
read -p "*** Install Finit as the system default Init (y/N)? " yorn
|
||||
if [ "x$yorn" = "xy" -o "x$yorn" = "xY" ]; then
|
||||
echo "*** Updating /sbin/init symlink --> finit ..."
|
||||
cd /sbin
|
||||
if yorn "Install Finit as the system default Init"; then
|
||||
printf "\e[1m*** Updating /sbin/init symlink --> finit ...\e[0m\n"
|
||||
cd /sbin || exit 1
|
||||
rm init
|
||||
ln -s finit init
|
||||
|
||||
@@ -48,10 +56,8 @@ if [ "x$yorn" = "xy" -o "x$yorn" = "xY" ]; then
|
||||
ln -s reboot shutdown
|
||||
ln -s reboot suspend
|
||||
fi
|
||||
echo "*** Done"
|
||||
printf "\n\e[1m*** Done\e[0m\n"
|
||||
echo
|
||||
else
|
||||
echo
|
||||
echo "*** Aborting install."
|
||||
echo
|
||||
printf "\n\e[1m*** Aborting install.\e[0m\n\n"
|
||||
fi
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
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
|
||||
4. Mount `/proc` and `/sys`
|
||||
5. Check kernel command line for `debug` to figure out log level
|
||||
6. Load all `.so` plugins
|
||||
7. Call `fsck` on file systems listed in `/etc/fstab`
|
||||
8. Populate `/dev` using either udev or mdev, depending on system type
|
||||
9. Parse `/etc/finit.conf`
|
||||
10. Start built-in watchdog, if enabled and `WDT_DEVNODE` exists. This
|
||||
means any WDT that requires a kernel module need to be either
|
||||
compiled into the kernel, or insmod'ed in `/etc/finit.conf`
|
||||
11. Load all `/etc/finit.d/*.conf` files and set hostname
|
||||
12. Remount `/` read-write if `/` is listed in `/etc/fstab` without `ro`
|
||||
13. Call 1st level hooks, `HOOK_ROOTFS_UP`
|
||||
14. Mount all file systems listed in `/etc/fstab` and swap, if available.
|
||||
On mount error `HOOK_MOUNT_ERROR` is called. After mount, regardless
|
||||
of error, `HOOK_MOUNT_POST` is called
|
||||
15. Enable SysV init signals
|
||||
16. Call 2nd level hooks, `HOOK_BASEFS_UP`
|
||||
17. Cleanup stale files from `/tmp/*` et al, handled by `bootmisc` plugin
|
||||
18. Load kernel params from `/etc/sysctl.d/*.conf`, `/etc/sysctl.conf`
|
||||
et al. (Supports all locations that SysV init does.), handled by
|
||||
`procps` plugin
|
||||
19. Start all 'S' runlevel tasks and services
|
||||
20. Bring up loopback interface and all `/etc/network/interfaces`, if
|
||||
the `.conf` setting `network <SCRIPT>` is set, it is called instead
|
||||
21. Call 3rd level hooks, `HOOK_NETWORK_UP`
|
||||
22. If `runparts <DIR>` is set, [run-parts(8)][] is called on `<DIR>`
|
||||
23. Switch to the configured runlevel from `/etc/finit.conf`, default 2.
|
||||
At every runlevel change all `*.conf` files in `/etc/finit.d/` are
|
||||
(re)loaded and new services, tasks, and blocking run commands are
|
||||
started. Provided they are allowed in the new runlevel and all of
|
||||
their conditions, if any, are set.
|
||||
24. Call 4th level hooks, `HOOK_SVC_UP`
|
||||
25. Call `/etc/rc.local`, if it exists and is an executable shell script
|
||||
26. Call 5th level (last) hooks, `HOOK_SYSTEM_UP`
|
||||
27. Start all configured TTYs
|
||||
|
||||
In (19) and (23) tasks and services defined in `/etc/finit.conf` and
|
||||
`/etc/finit.d/*.conf` are started.
|
||||
|
||||
Notice the seven hook points that are called at various point in the
|
||||
bootstrap process. This is where plugins can extend the boot in any
|
||||
way they please. There are other hook points available, for more on
|
||||
this, see [plugins.md](plugins.md).
|
||||
|
||||
For instance, at `HOOK_BASEFS_UP` a plugin could read an XML file from a
|
||||
USB stick, convert/copy its contents to the system's `/etc/` directory,
|
||||
well before all 'S' runlevel tasks are started. This could be used with
|
||||
system images that are created read-only and all configuration is stored
|
||||
on external media.
|
||||
|
||||
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
||||
+16
-4
@@ -12,6 +12,15 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
|
||||
* `debug`: Enable kernel debug. Debug messages are printed to the
|
||||
console until Finit starts up, unless `loglevel=7` (below) is used.
|
||||
|
||||
* `fsck.mode=<auto,force,skip>`, default: `auto`, unless built with
|
||||
`configure --enable-fastboot`, in which case the default is `skip`
|
||||
|
||||
* `fsck.repair=<preen,yes,no>`, default: `preen`, unless built with
|
||||
`configure --enable-fsckfix`, in which case the default is `yes`.
|
||||
This configure option also sets `fsck.mode=force`, unless fastboot
|
||||
is selected at the same time. I.e., the `--enable-fastboot` build
|
||||
option overrides the `fsck.mode` default value.
|
||||
|
||||
* `finit.cond=foo[,bar[,baz]]`: set `<boot/foo>` condition, optionally
|
||||
multiple conditions can be set using the same option, separated with a
|
||||
comma. Alternatively, multiple `foo.cond=arg` can be given. Each will
|
||||
@@ -86,13 +95,16 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
|
||||
the system booted in a limited fallback mode. See [config.md][]
|
||||
for more information.
|
||||
|
||||
This option can be disabled with `configure --without-rescue`
|
||||
|
||||
**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.
|
||||
* `single`, or `S`: Overrides the configured runlevel (default: 2) to go
|
||||
to after bootstrap by forcing it to runlevel 1, this is also known
|
||||
as single user mode. Useful to debug startup problems. All services
|
||||
and TTYs in `[1]` will be started, so a `tty [1] @console nologin`
|
||||
configuration presents you with a root console without login.
|
||||
|
||||
* `1-9`, except `6`: override the configured `runlevel`. Like the `S`
|
||||
and `rescue`, giving a single number on the kernel command line tells
|
||||
|
||||
@@ -27,6 +27,16 @@ specified separated by comma. Multiple conditions are logically AND'ed
|
||||
during evaluation, i.e. all conditions must be satisfied in order for a
|
||||
service to run.
|
||||
|
||||
A special syntax, using a leading `!` in run/task/service conditions,
|
||||
denote if a:
|
||||
|
||||
- service does not support `SIGHUP`
|
||||
- run/task should not block runlevel changes (i.e., bootstrap)
|
||||
|
||||
Finit guarantees by default that all run/tasks run (at least) once
|
||||
per runlevel. For most tasks this is a good default, for example
|
||||
checking SSH host keys or loading keymap. However, for conditions
|
||||
that are unlikely to happen it is not. (See example below.)
|
||||
|
||||
### Example
|
||||
|
||||
@@ -41,6 +51,19 @@ being created, i.e., the service's default readiness notification.
|
||||
asserted. I.e., if the Zebra process above stops or restarts, netd
|
||||
will also stop or restart.
|
||||
|
||||
Another example is `dropbear`, it does not support `SIGHUP`, but we can
|
||||
also see optional sourcing of arguments from an environment file:
|
||||
|
||||
service [2345789] <!> env:-/etc/default/dropbear dropbear -F -R $DROPBEAR_ARGS -- Dropbear SSH daemon
|
||||
|
||||
Finally, the weird "block runlevel changes" example. Here we see what
|
||||
happens when Finit receives `SIGPWR`, sent from a power daemon like
|
||||
[powstatd(8)][]. A condition is asserted and a user can set up their
|
||||
own task to act on it. We do not want this task to block Finit from
|
||||
moving to the next runlevel after bootstrap, so we set `<!>`:
|
||||
|
||||
task [S0123456789] <!sys/pwr/fail> name:pwrfail initctl poweroff -- Power failure, shutting down
|
||||
|
||||
|
||||
Triggering
|
||||
----------
|
||||
@@ -260,3 +283,5 @@ Therefore, any plugin that supplies Finit with conditions must ensure
|
||||
that their state is updated after each reconfiguration. This can be
|
||||
done by binding to the `HOOK_SVC_RECONF` hook. For an example of how
|
||||
to do this, see `plugins/pidfile.c`.
|
||||
|
||||
[powstatd(8)]: https://manpages.ubuntu.com/manpages/trusty/en/man8/powstatd.8.html
|
||||
|
||||
+381
-127
@@ -28,6 +28,7 @@ Finit Configuration
|
||||
* [TTYs and Consoles](#ttys-and-consoles)
|
||||
* [Non-privileged Services](#non-privileged-services)
|
||||
* [Redirecting Output](#redirecting-output)
|
||||
* [SysV Init Compatibility](#sysv-init-compatibility)
|
||||
* [Rescue Mode](#rescue-mode)
|
||||
* [Limitations](#limitations)
|
||||
* [/etc/finit.conf](#etcfinitconf)
|
||||
@@ -45,31 +46,86 @@ Plugins start at [hook points](plugins.md#hooks) and can run various set
|
||||
up, or install event handlers that later provide runtime services, e.g.,
|
||||
PID file monitoring, or [conditions](conditions.md).
|
||||
|
||||
> **Tip:** see [SysV Init Compatibility](#sysv-init-compatibility) for
|
||||
> help to quickly get going with an existing SysV or BusyBox init setup.
|
||||
|
||||
|
||||
### Configuration Files
|
||||
|
||||
Originally Finit was configured using a single file, `/etc/finit.conf`.
|
||||
Although still possible, today we recommended using the Apache-style
|
||||
`available/*.conf` and `enabled/*.conf` layaout. These are called
|
||||
dynamic services, in contrast to static -- the only difference being
|
||||
where they are installed and if the `initctl` tool can manage them.
|
||||
Originally Finit was configured using a single file, `/etc/finit.conf`,
|
||||
and although still possible to use a single configuration file, today
|
||||
the following layout is recommended:
|
||||
|
||||
/etc/
|
||||
|- finit.d/
|
||||
| |- available/
|
||||
| | `- my-service.conf
|
||||
: |- enabled/
|
||||
: | `- my-service.conf -> ../available/my-service.conf
|
||||
: :
|
||||
: |- static-service.conf
|
||||
: `- another-static.conf # eg. bootstrap run/task commands
|
||||
:
|
||||
`- finit.conf # global settings
|
||||
/
|
||||
|- etc/
|
||||
| |- finit.d/
|
||||
| | |- available/
|
||||
| | | `- my-service.conf
|
||||
| : |- enabled/
|
||||
| : | `- my-service.conf -> ../available/my-service.conf
|
||||
| : :
|
||||
| : |- static-service.conf
|
||||
| : `- another-static.conf
|
||||
| :
|
||||
| `- finit.conf
|
||||
|- lib
|
||||
| `- finit/
|
||||
| `- system/
|
||||
| |- 10-hotplug.conf
|
||||
| `- ...
|
||||
`- run/
|
||||
`- finit/
|
||||
`- system/
|
||||
|- dbus.conf
|
||||
|- keventd.conf
|
||||
|- runparts.conf
|
||||
|- watchdogd.conf
|
||||
`- ...
|
||||
|
||||
Configuration files in `/etc` are provided by the user, or projects like
|
||||
[finit-skel](https://github.com/troglobit/finit-skel) and extended by
|
||||
the user.
|
||||
|
||||
The files in `/lib/finit/system/*.conf` are system critical services and
|
||||
setup provided by Finit, e.g. udev/mdev that must run very early at system
|
||||
bootstrap. This system directory was introduced in Finit v4.4 to replace
|
||||
the hard-coded services provided by plugins before. All .conf files in this
|
||||
directory be either replaced by a system administrator or overridden by a
|
||||
file with the same name in `/etc/finit.d/`.
|
||||
|
||||
The files in `/run/finit/system/*.conf` are created by plugins and Finit
|
||||
bundled services like runparts, the [watchdog](#watchdog), and `keventd`
|
||||
if they are enabled. Like `/lib/finit/system/*.conf`, these files can
|
||||
be overridden by file with the same name in `/etc/finit.d/`.
|
||||
|
||||
Services in the `available/` and `enabled/` sub-directories are called
|
||||
dynamic services, in contrast to static services -- the only difference
|
||||
being where they are installed and if the `initctl` tool can manage them
|
||||
with the `enable` and `disable` commands. An administrator can always
|
||||
create files and symlinks manually.
|
||||
|
||||
At bootstrap, and `initctl reload`, all .conf files are read, starting
|
||||
with `finit.conf`, then, in alphabetical order, all `finit.d/*.conf`
|
||||
files, and finally (still in alphabetical order) all `enabled/*.conf`
|
||||
files.
|
||||
with `finit.conf`, then `/lib/finit/system/*.conf`, `finit.d/*.conf`,
|
||||
and finally all `finit.d/enabled/*.conf` files. Each directory is a
|
||||
unique group, where files within each group are sorted alphabetically.
|
||||
|
||||
**Example:**
|
||||
|
||||
/lib/finit/system/10-hotplug.conf
|
||||
/lib/finit/system/90-testserv.conf
|
||||
/run/finit/system/dbus.conf
|
||||
/run/finit/system/runparts.conf
|
||||
/etc/finit.d/10-abc.conf
|
||||
/etc/finit.d/20-abc.conf
|
||||
/etc/finit.d/enabled/1-aaa.conf
|
||||
/etc/finit.d/enabled/1-abc.conf
|
||||
|
||||
The resulting combined configuration is read line by line, each `run`,
|
||||
`task`, and `service` added to an ordered list that ensures they are
|
||||
started in the same order. This is important because of the blocking
|
||||
properties of the `run` statement. For an example on the relation of
|
||||
`service` and `run` statements, and dependency handling between them,
|
||||
see [Conditional Loading](#conditional-loading), below.
|
||||
|
||||
> **Note:** the `finit.conf` and `finit.d/` names are only defaults.
|
||||
> They can be changed at compile-time with two `configure` options:
|
||||
@@ -118,21 +174,25 @@ layout, as specified in the [FHS][]:
|
||||
|- spool/
|
||||
`- tmp/
|
||||
|
||||
Finit starts (very early) by mounting `/dev`, `/proc/`, and `/sys`,
|
||||
unless they (i.e., `/dev`) are already mounted. When all plugins and
|
||||
other, core Finit functions, have been set up, all relevant filesystems
|
||||
(`PASS > 0`) are checked and mounted from the selected `fstab`, either
|
||||
Finit starts by mounting the critical file systems `/dev`, `/proc/`, and
|
||||
`/sys`, unless they are already mounted. When all plugins and other,
|
||||
core Finit functions, have been set up, all relevant filesystems (where
|
||||
`PASS > 0`) are checked and mounted from the selected `fstab`, either
|
||||
the default `/etc/fstab`, or any custom one selected from the command
|
||||
line, or at build time.
|
||||
|
||||
Any file system not listed `fstab` are automatically mounted by Finit,
|
||||
as listed above, provided their respective mount point exists.
|
||||
To provide a smooth ride, file system not listed in the given `fstab`,
|
||||
e.g. `/tmp` and `/run`, are automatically mounted by Finit, as listed
|
||||
above, provided their respective mount point exists.
|
||||
|
||||
With all filesystems mounted, Finit calls `swapon`.
|
||||
|
||||
> **Tip:** to see what happens when all filesystems are mounted, have a
|
||||
> look at the [`bootmisc.so` plugin](plugins.md).
|
||||
|
||||
At shutdown, and after having stopped all services and other lingering
|
||||
processes killed, filesystems are unmounted in the reverse order, and
|
||||
`swapoff` is called.
|
||||
processes have been killed, filesystems are unmounted in the reverse
|
||||
order, and `swapoff` is called.
|
||||
|
||||
[FHS]: https://refspecs.linuxfoundation.org/FHS_3.0/fhs/index.html
|
||||
|
||||
@@ -146,24 +206,30 @@ processes killed, filesystems are unmounted in the reverse order, and
|
||||
- ` 0`: shutdown
|
||||
|
||||
Runlevels are declared per service/run/task/sysv command. Starting in
|
||||
runlevel S ([bootStrap](bootstrap.md)), usually only for tasks supposed
|
||||
to run once at boot, and services like `syslogd`, which you need to
|
||||
start and run throughout the whole time your system is up. Before `S`
|
||||
is started, however, Finit performs a lot of housekeeping tasks like
|
||||
mounting all filesystems, calling `fsck` if needed, and making sure the
|
||||
everything is OK.
|
||||
runlevel S (bootStrap), usually only for tasks supposed to run once at
|
||||
boot, and services like `syslogd`, which you need to start and run
|
||||
throughout the whole time your system is up.
|
||||
|
||||
Before `S` is started, however, Finit performs a lot of housekeeping
|
||||
tasks like mounting all filesystems, calling `fsck` if needed, and
|
||||
making sure the everything is OK.
|
||||
|
||||
task [S] /lib/console-setup/console-setup.sh
|
||||
service [S12345] env:-/etc/default/rsyslog rsyslogd -n $RSYSLOGD_ARGS
|
||||
|
||||
After runlevel S, Finit proceeds to runlevel 2. (This can be changed in
|
||||
`/etc/finit.conf` using the `runlevel N` directive.) Before starting
|
||||
the services in runlevel 2, Finit first stops everything that is not
|
||||
allowed to run in 2, and then brings up networking. Networking is
|
||||
expected to be available in all runlevels except: S, 1 (single user
|
||||
level), 6, and 0. Networking is enabled either by the `network script`
|
||||
directive, or if you have an `/etc/network/interfaces` file, Finit calls
|
||||
`ifup -a` -- at the very least the loopback interface is brought up.
|
||||
After runlevel S, Finit proceeds to runlevel 2. This can be changed in
|
||||
`/etc/finit.conf` using the `runlevel N` directive, or by a script
|
||||
running in runlevel S that calls, e.g., `initctl runlevel 9`. The
|
||||
latter is useful if startup scripts detect problems outside of Finit's
|
||||
control, e.g., critical services/devices missing or hardware problems.
|
||||
|
||||
Before starting the services in runlevel 2, Finit first stops everything
|
||||
that is not allowed to run in 2, and then brings up networking.
|
||||
Networking is expected to be available in all runlevels except: S, 1
|
||||
(single user level), 6, and 0. Networking is enabled either by the
|
||||
`network script` directive, or if you have an `/etc/network/interfaces`
|
||||
file, Finit calls `ifup -a` -- at the very least the loopback interface
|
||||
is brought up.
|
||||
|
||||
> **Note:** when moving from runlevel S to 2, all run/task/services that
|
||||
> were constrained to runlevel S only are dropped from bookkeeping. So
|
||||
@@ -290,17 +356,31 @@ most notably systemd and s6, other methods for signaling "readiness"
|
||||
arrived and daemons were adapted to these new schemes to a larger
|
||||
extent.
|
||||
|
||||
As of Finit v4.4 partial support for systemd and s6 is available. The
|
||||
native PID file mode of operation is still default, the other's can be
|
||||
defined per service, like this:
|
||||
As of Finit v4.4 partial support for systemd and s6 style readiness
|
||||
notification is available, and the native PID file mode of operation is,
|
||||
as of Finit v4.6 optional, by default it is still enabled, but this can
|
||||
be changed in `finit.conf`:
|
||||
|
||||
readiness none
|
||||
|
||||
This will be made the default in Finit 5.0. In this mode of operation,
|
||||
every service needs to explicitly declare their readiness notification,
|
||||
like this:
|
||||
|
||||
service notify:pid watchdogd
|
||||
service notify:systemd foo
|
||||
service notify:s6 bar
|
||||
service notify:none qux
|
||||
|
||||
The `notify:none` syntax is for completeness in systems which run in
|
||||
`readiness pid` mode (default). Services declared with `notify:none`
|
||||
will assert ready condition as soon as Finit has started them, e.g.,
|
||||
`service/qux/ready`.
|
||||
|
||||
To synchronize two services the following condition can be used:
|
||||
|
||||
service notify:systemd A
|
||||
service <service/A/ready> B
|
||||
service notify:pid watchdogd
|
||||
service <service/watchdogd/ready> stress-ng --cpu 8
|
||||
|
||||
For details on the syntax and options, see below.
|
||||
|
||||
@@ -379,7 +459,7 @@ Cgroups
|
||||
|
||||
There are three major cgroup configuration directives:
|
||||
|
||||
1. Global top-level group: init, system, user, or a custom group
|
||||
1. Global top-level group: `init`, `system`, `user`, or a custom group
|
||||
2. Selecting a top-level group for a set of run/task/services
|
||||
3. Per run/task/service limits
|
||||
|
||||
@@ -430,6 +510,10 @@ 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.
|
||||
|
||||
A daemon using `SCHED_RR` currently need to run outside the default cgroups.
|
||||
|
||||
service [...] <...> cgroup.root /path/to/daemon arg -- Real-Time process
|
||||
|
||||
> Linux cgroups and details surrounding values are not explained in the
|
||||
> Finit documentation. The Linux admin-guide cover this well:
|
||||
> <https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html>
|
||||
@@ -459,7 +543,7 @@ following directives:
|
||||
|
||||
|
||||
> **Note:** not all directives are available in `/etc/finit.d/*.conf`
|
||||
> and some directives are only available at [bootstrap][], runlevel `S`,
|
||||
> and some directives are only available at bootstrap, runlevel `S`,
|
||||
> see [Limitations](#limitations) below for details.
|
||||
|
||||
|
||||
@@ -472,7 +556,7 @@ the contents of that file is used.
|
||||
|
||||
Deprecated. We recommend using `/etc/hostname` instead.
|
||||
|
||||
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
||||
|
||||
|
||||
### Kernel Modules
|
||||
@@ -490,7 +574,7 @@ BusyBox mdev tool, add to `/etc/mdev.conf`:
|
||||
|
||||
$MODALIAS=.* root:root 0660 @modprobe -b "$MODALIAS"
|
||||
|
||||
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
||||
|
||||
|
||||
### Networking
|
||||
@@ -503,7 +587,7 @@ Deprecated. We recommend using dedicated task/run stanzas per runlevel,
|
||||
or `/etc/network/interfaces` if you have a system with `ifupdown`, like
|
||||
Debian, Ubuntu, Linux Mint, or an embedded BusyBox system.
|
||||
|
||||
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
||||
|
||||
|
||||
### Alternate finit.d/
|
||||
@@ -558,7 +642,7 @@ stanzas can share the same rlimits if they are in the same .conf.
|
||||
|
||||
**Syntax:** `runlevel <N>`
|
||||
|
||||
The system runlevel to go to after [bootstrap][] (S) has completed. `N`
|
||||
The system runlevel to go to after bootstrap (S) has completed. `N`
|
||||
is the runlevel number 0-9, where 6 is reserved for reboot and 0 for
|
||||
halt.
|
||||
|
||||
@@ -567,40 +651,61 @@ Finit disables networking in this mode.
|
||||
|
||||
*Default:* 2
|
||||
|
||||
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
||||
|
||||
|
||||
### One-shot Commands (sequence)
|
||||
|
||||
**Syntax:** `run [LVLS] <COND> /path/to/cmd ARGS -- Optional description`
|
||||
|
||||
One-shot command to run in sequence when entering a runlevel, with
|
||||
optional arguments and description.
|
||||
|
||||
`run` commands are guaranteed to be completed before running the next
|
||||
command. Highly useful if true serialization is needed.
|
||||
|
||||
> `<COND>` is described in the [Services](#services) section.
|
||||
|
||||
One-shot command to run in sequence when entering a runlevel, with
|
||||
optional arguments and description. `run` commands are guaranteed to be
|
||||
completed before running the next command. Useful when serialization is
|
||||
required.
|
||||
|
||||
> **Warning:** try to avoid the `run` command. It blocks much of the
|
||||
> functionality in Finit, like (re)starting other (perhaps crashing)
|
||||
> services while a `run` task is executing. Use other synchronization
|
||||
> mechanisms instead, like conditions.
|
||||
|
||||
Incomplete list of unsupported `initctl` commands in `run` tasks:
|
||||
|
||||
- `initctl runlevel N`, setting runlevel
|
||||
- `initctl reboot`
|
||||
- `initctl halt`
|
||||
- `initctl poweroff`
|
||||
- `initctl suspend`
|
||||
|
||||
To prevent `initctl` from calling Finit when enabling and disabling
|
||||
services from inside a `run` task, use the `--force` option. See
|
||||
also the `--quiet` and `--batch` options.
|
||||
|
||||
|
||||
### One-shot Commands (parallel)
|
||||
|
||||
**Syntax:** `task [LVLS] <COND> /path/to/cmd ARGS -- Optional description`
|
||||
|
||||
> `<COND>` is described in the [Services](#services) section.
|
||||
|
||||
One-shot like 'run', but starts in parallel with the next command.
|
||||
|
||||
Both `run` and `task` commands are run in a shell, so pipes and
|
||||
redirects can be freely used:
|
||||
Both `run` and `task` commands are run in a shell, so basic pipes and
|
||||
redirects can be used:
|
||||
|
||||
task [s] echo "foo" | cat >/tmp/bar
|
||||
|
||||
> `<COND>` is described in the [Services](#services) section.
|
||||
Please note, `;`, `&&`, `||`, and similar are *not supported*. Any
|
||||
non-trivial constructs are better placed in a separate shell script.
|
||||
|
||||
|
||||
### SysV Init Scripts
|
||||
|
||||
**Syntax:** `sysv [LVLS] <COND> /path/to/init-script -- Optional description`
|
||||
|
||||
> `<COND>` is described in the [Services](#services) section.
|
||||
|
||||
Similar to `task` is the `sysv` stanza, which can be used to call SysV
|
||||
style scripts. The primary intention for this command is to be able to
|
||||
re-use much of existing setup and init scripts in Linux distributions.
|
||||
@@ -618,7 +723,7 @@ 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.
|
||||
> **Tip:** see also [SysV Init Compatibility](#sysv-init-compatibility).
|
||||
|
||||
|
||||
### Services
|
||||
@@ -785,73 +890,153 @@ configurable with the following options:
|
||||
* `oncrash:script` -- similarly, but instead of rebooting, call the
|
||||
`post:script` action if set, see below.
|
||||
|
||||
When stopping a service (run/task/sysv/service), either manually or
|
||||
when moving to another runlevel, Finit starts by sending `SIGTERM`, to
|
||||
allow the process to shut down gracefully. If the process has not
|
||||
been collected within 3 seconds, Finit sends `SIGKILL`. To halt the
|
||||
process using a different signal, use the option `halt:SIGNAL`, e.g.,
|
||||
`halt:SIGPWR`. To change the delay between your halt signal and KILL,
|
||||
use the option `kill:SEC`, e.g., `kill:10` to wait 10 seconds before
|
||||
sending `SIGKILL`.
|
||||
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. However, if the process has not
|
||||
been collected within 3 seconds, Finit will send `SIGKILL`. To stop the
|
||||
process using a different signal than `SIGTERM`, use `halt:SIGNAL`,
|
||||
e.g., `halt:SIGPWR`. To change the delay between the stop signal and
|
||||
KILL, use the option `kill:<1-60>`, e.g., `kill:10` to wait 10 seconds
|
||||
before sending `SIGKILL`.
|
||||
|
||||
Services support `pre:script` and `post:script` actions as well. These
|
||||
run as the same `@USER:GROUP` as the service itself, with any `env:file`
|
||||
sourced. The scripts must use an absolute path, but are executed from
|
||||
the `$HOME` of the given user. The scripts are not called with any
|
||||
argument (currently), but both get the `SERVICE_IDENT=foo` environment
|
||||
variable set. Here `foo` denotes the identity of the service, which if
|
||||
there are multiple services named `foo`, may be `foo:1`, or any unique
|
||||
identifier specified in the .conf file. The `post:script` is called
|
||||
with an additional set of environment variables:
|
||||
Services, including the `sysv` variant, support pre/post/ready and
|
||||
cleanup scripts:
|
||||
|
||||
- `EXIT_CODE=[exited,signal]`: set to one of `exited` or `signal`
|
||||
* `pre:[0-3600,]script` -- called before the sysv/service is stated
|
||||
* `post:[0-3600,]script` -- called after the sysv/service has stopped
|
||||
* `ready:[0-3600,]script` -- called when the sysv/service is ready
|
||||
* `cleanup:[0-3600,]script` -- called when run/task/sysv/service is removed
|
||||
|
||||
The optional number (0-3600) is the timeout before Finit kills the
|
||||
script, it defaults to the kill delay value and can be disabled by
|
||||
setting it to zero. These scripts run as the same `@USER:GROUP` as the
|
||||
service itself, with any `env:file` sourced. The scripts are executed
|
||||
from the `$HOME` of the given user. The scripts are not called with any
|
||||
argument, but get a set of environment variables:
|
||||
|
||||
* `SERVICE_IDENT=foo:1`
|
||||
* `SERVICE_NAME=foo`
|
||||
* `SERVICE_ID=1`
|
||||
|
||||
The `post:script` is called with an additional set of environment
|
||||
variables. Yes, the text is correct, the naming was an accident:
|
||||
|
||||
- `EXIT_CODE=[exited,signal,crashed]`: normal exit, signaled, or
|
||||
crashed
|
||||
- `EXIT_STATUS=[num,SIGNAME]`: set to one of exit status code from
|
||||
the program, if it exited normally, or the signal name (`HUP`,
|
||||
`TERM`, etc.) if it exited due to signal
|
||||
|
||||
These script actions *must terminate*, so they have a default execution
|
||||
time of 3 seconds before they are SIGKILLed, this can be adjusted using
|
||||
the above `kill:SEC` syntax.
|
||||
When a run/task/sys/service is removed (disable + reload) it is first
|
||||
stopped and then removed from the runlevel. The `post:script` always
|
||||
runs when the process has stopped, and the `cleanup:script` runs when
|
||||
the the stanza has been removed from the runlevel.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> These script actions are intended for setup, cleanup, and readiness
|
||||
> notification. It is up to the user to ensure the scripts terminate.
|
||||
|
||||
|
||||
#### Conditional Loading
|
||||
|
||||
Finit support conditional loading of stanzas. The following example is
|
||||
take from the `system/hotplug.conf` file in the Finit distribution.
|
||||
Here we only show a simplified subset.
|
||||
|
||||
Starting with the `nowarn` option.
|
||||
|
||||
service nowarn name:udevd pid:udevd /lib/systemd/systemd-udevd
|
||||
service nowarn name:udevd pid:udevd udevd
|
||||
|
||||
When loading the .conf file Finit looks for `/lib/systemd/systemd-udevd`
|
||||
if that is not found Finit automatically logs a warning. The `nowarn`
|
||||
option disables this warning so that the second line can be evaluated,
|
||||
which also provides a service named `udevd`.
|
||||
|
||||
run nowarn if:udevd <pid/udevd> :1 udevadm settle -t 0
|
||||
|
||||
This line is only loaded if we know of a service named `udevd`. Again,
|
||||
we do not warn if `udevadm` is not found, Execution will also stop here
|
||||
until the PID condition is asserted, i.e., Finit detecting udevd has
|
||||
started.
|
||||
|
||||
run nowarn conflict:udevd [S] mdev -s -- Populating device tree
|
||||
|
||||
If `udevd` is not available, we try to run `mdev`, but if that is not
|
||||
found, again we do not warn.
|
||||
|
||||
Conditional loading statements can also be negated, so the previous stanza
|
||||
can also be written as:
|
||||
|
||||
run nowarn if:!udevd [S] mdev -s -- Populating device tree
|
||||
|
||||
The reason for using `confict` in this example is that a conflict can be
|
||||
resolved. Stanzas marked with `conflict:foo` are rechecked at runtime.
|
||||
|
||||
#### Conditional Execution
|
||||
|
||||
Similar to conditional loading of stanzas there is conditional runtime
|
||||
execution. This can be confusing at first, since Finit already has a
|
||||
condition subsystem, but this is more akin to the qualification to a
|
||||
runlevel. E.g., a `task [123]` is qualified to run only in runlevel 1,
|
||||
2, and 3. It is not considered for other runlevels.
|
||||
|
||||
Conditional execution qualify a run/task/service based on a condition.
|
||||
Consider this (simplified) example from the Infix operating system:
|
||||
|
||||
run [S] name:startup <pid/sysrepo> confd -b --load startup-config
|
||||
run [S] if:<usr/fail-startup> name:failure <pid/sysrepo> confd --load failure-config
|
||||
|
||||
The two run statements reside in the same .conf file so Finit runs them
|
||||
in true sequence. If loading the file `startup-config` fails confd sets
|
||||
the condition `usr/fail-startup`, thus allowing the next run statement
|
||||
to load `failure-config`.
|
||||
|
||||
Notice critical the difference between `<pid/sysrepo>` condition and
|
||||
`if:<usr/fail-startup>`. The former is a condition for starting and the
|
||||
latter is a condition to check if a run/task/service is qualified to
|
||||
even be considered.
|
||||
|
||||
Conditional execution statements can also be negated, so provided the
|
||||
file loaded did the opposite, i.e., set a condition on success, the
|
||||
previous stanza can also be written as:
|
||||
|
||||
run [S] if:<!usr/startup-ok> name:failure <pid/sysrepo> confd ...
|
||||
|
||||
### Run-parts Scripts
|
||||
|
||||
**Syntax:** `runparts <DIR>`
|
||||
**Syntax:** `runparts [progress] [sysv] <DIR>`
|
||||
|
||||
Call [run-parts(8)][] on `DIR` to run start scripts. All executable
|
||||
files, or scripts, in the directory are called, in alphabetic order.
|
||||
The scripts in this directory are executed at the very end of runlevel
|
||||
`S`, [bootstrap][].
|
||||
files in the directory are called, in alphabetic order. The scripts in
|
||||
this directory are executed at the very end of runlevel `S`.
|
||||
|
||||
A common use-case for runparts scripts is to create and enable/disable
|
||||
services, which Finit will then apply when changing runlevel from S to
|
||||
whatever the next runlevel is set to be (default 2). E.g., generate a
|
||||
`/etc/chrony.conf` and `initctl enable chronyd`.
|
||||
`/etc/chrony.conf` and call `initctl enable chronyd`.
|
||||
|
||||
**Options:**
|
||||
|
||||
- `progress`: display the progress of each script being executed
|
||||
- `sysv`: run only SysV style scripts, i.e., `SNNfoo`, or `KNNbar`,
|
||||
where `NN` is a number (0-99).
|
||||
|
||||
If global debug mode is enabled, the `runparts` program is also called
|
||||
with the debug flag.
|
||||
|
||||
**Limitations:**
|
||||
|
||||
Scripts called from `runparts`, or hook scripts (see below), are limited
|
||||
in what they can do and expect from Finit:
|
||||
in their interaction with Finit. Like the standalone `run` stanza and
|
||||
the `/etc/rc.local` shell script, Finit waits for their completion
|
||||
before continuing. None of them can issue commands to start, stop, or
|
||||
restart other services. Also, ensure all your services and programs
|
||||
either terminate or start in the background or you will block Finit.
|
||||
|
||||
1. Finit is single threaded and all scripts executed from these two
|
||||
mechanisms are limited to file system operations (early or late
|
||||
hooks may not have write access!) and standard UNIX programs.
|
||||
2. Thus, it is *not possible* to call `initctl` to query status of
|
||||
services since that calls Finit over the `/run/finit/socket`.
|
||||
3. Confusingly enough, there are some commands to `initctl` that are
|
||||
available; `ls`, `enable`, `disable`, `touch`, `create`, `delete`,
|
||||
and all the `cond` commands. Because all these are basically just
|
||||
wrappers for manipulating files (again, write access for early/late
|
||||
hooks may not be available).
|
||||
|
||||
Also, similar to the `/etc/rc.local` shell script, make sure that all
|
||||
your services and programs either terminate or start in the background
|
||||
or you will block Finit.
|
||||
|
||||
> **Note:** `runparts` scrips are only read and executed in runlevel S
|
||||
> ([bootstrap][]). See [hook scripts](plugins.md#hooks) for other ways
|
||||
> to run scripts at certain points during the complete lifetime of the
|
||||
> system.
|
||||
> **Note:** `runparts` scrips are only read and executed in runlevel S.
|
||||
> See [hook scripts](plugins.md#hooks) for other ways to run scripts at
|
||||
> certain points during the complete lifetime of the system.
|
||||
|
||||
**Recommendations:**
|
||||
|
||||
@@ -964,8 +1149,8 @@ can be omitted to keep the kernel default.
|
||||
tty [12345] @console noclear vt220
|
||||
|
||||
On really bare bones systems, or for board bringup, Finit can give you a
|
||||
shell prompt as soon as [bootstrap][] is done, without opening any
|
||||
device node:
|
||||
shell prompt as soon as bootstrap is done, without opening any device
|
||||
node:
|
||||
|
||||
tty [12345789] notty
|
||||
|
||||
@@ -1044,6 +1229,72 @@ sync(2) has been called, twice.
|
||||
> finally written.
|
||||
|
||||
|
||||
SysV Init Compatibility
|
||||
-----------------------
|
||||
|
||||
It is not possible to run unmodified SysV init systems with Finit. This
|
||||
was never the intention and is not the strength of Finit. However, it
|
||||
comes with a few SysV Init compatibility features to ease the transition
|
||||
from a serialized boot process.
|
||||
|
||||
### `runparts DIRECTORY`
|
||||
|
||||
For a directory with traditional start/stop scripts that should run, in
|
||||
order, at bootstrap, Finit provides the `runparts` directive. It runs
|
||||
in runlevel S, at the very end of it (before calling `/etc/rc.local`)
|
||||
making it perfect for most scenarios.
|
||||
|
||||
For syntax details, see [Run-parts Scripts](#run-parts-scripts) above.
|
||||
Here is an example take from a Debian installation:
|
||||
|
||||
runparts /etc/rc2.d
|
||||
|
||||
Files in these directories are usually named `SNNfoo` and `KNNfoo`,
|
||||
which Finit knows about and automatically appends the correct argument:
|
||||
|
||||
/bin/sh -c /etc/rc2.d/S01openbsd-inetd start
|
||||
|
||||
or
|
||||
|
||||
/bin/sh -c /etc/rc0.d/K01openbsd-inetd stop
|
||||
|
||||
Files that do not match this pattern are started similarly but without
|
||||
the extra command line argument.
|
||||
|
||||
|
||||
### Start/Stop Scripts
|
||||
|
||||
For syntax details, see [SysV Init Scripts](#sysv-init-scripts), above.
|
||||
Here follows an example taken from a Debian installation:
|
||||
|
||||
sysv [2345] <pid/syslogd> /etc/init.d/openbsd-inetd -- OpenBSD inet daemon
|
||||
|
||||
The init script header could be parsed to extract `Default-Start:` and
|
||||
other parameters for the `sysv` command to Finit. There is currently no
|
||||
way to detail a generic syslogd dependency in Finit, so `Should-Start:`
|
||||
in the header must be mapped to the condition system in Finit using an
|
||||
absolute reference, here we depend on the sysklogd project's syslogd.
|
||||
|
||||
### `/etc/rc.local`
|
||||
|
||||
One often requested feature, early on, was a way to run a site specific
|
||||
script to set up, e.g., static routes or firewall rules. A user can add
|
||||
a `task` or `run` command in the Finit configuration for this, but for
|
||||
compatibility reasons the more widely know `/etc/rc.local` is used if
|
||||
it exists, and is executable. It is called very late in the boot process
|
||||
when the system has left runlevel S, stopped all old and started all new
|
||||
services in the target runlevel (default 2).
|
||||
|
||||
> In Finit releases before v4.5 this script blocked Finit execution and
|
||||
> made it as good as impossible to call `initctl` during that time.
|
||||
|
||||
### `init q`
|
||||
|
||||
When `/sbin/finit` is installed as `/sbin/init`, it is possible to use
|
||||
`init q` to reload the configuration. This is the same as calling
|
||||
`initctl reload`.
|
||||
|
||||
|
||||
Rescue Mode
|
||||
-----------
|
||||
|
||||
@@ -1051,6 +1302,10 @@ Finit supports a rescue mode which is activated by the `rescue` option
|
||||
on the kernel command line. See [cmdline docs](cmdline.md) for how to
|
||||
activate it.
|
||||
|
||||
This rescue mode can be disabled at configure time using:
|
||||
|
||||
configure --without-rescue
|
||||
|
||||
The rescue mode comes in two flavors; *traditional* and *fallback*.
|
||||
|
||||
> **Note:** in this mode `initctl` will not work. Use the `-f` flag to
|
||||
@@ -1060,15 +1315,17 @@ The rescue mode comes in two flavors; *traditional* and *fallback*.
|
||||
### Traditional
|
||||
|
||||
This is what most users expect. A very early maintenance login prompt,
|
||||
served by the bundled `/libexec/finit/sulogin` program, or the standard
|
||||
`sulogin` from util-linux or BusyBox is searched for in the UNIX default
|
||||
`$PATH`. If a successful login is made, or the user exits (Ctrl-D), the
|
||||
rescue mode is ended and the system boots up normally.
|
||||
served by the system `sulogin` program from util-linux, or BusyBox. If
|
||||
that is not found in `$PATH`, the bundled `/libexec/finit/sulogin`
|
||||
program is used instead. If a successful login is made, or if the user
|
||||
exits (Ctrl-D), the rescue mode is ended and the system boots up
|
||||
normally.
|
||||
|
||||
> **Note:** if the user (UID 0 and GID 0) does not have a password, or
|
||||
> __the account is locked__, the user is presented with a password-less
|
||||
> `"Press enter to enter maintenance mode."`, prompt which opens up a
|
||||
> root shell.
|
||||
> **Note:** the bundled sulogin in Finit can at configure time be given
|
||||
> another user than the default (root). If the sulogin user does not
|
||||
> have a password, or __the account is locked__, the user is presented
|
||||
> with a password-less `"Press enter to enter maintenance mode."`,
|
||||
> prompt which opens up a root shell.
|
||||
|
||||
|
||||
### Fallback
|
||||
@@ -1128,12 +1385,11 @@ Watchdog
|
||||
When built `--with-watchdog` a separate service is built and installed
|
||||
in `/libexec/finit/watchdogd`. If this exists at runtime, and the WDT
|
||||
device node exists, Finit will start it and treat it as the elected
|
||||
watchdog service to delegate its reboot to. See [bootstrap][] for
|
||||
details. This delegation is to ensure that the system is rebooted by a
|
||||
hardware watchdog timer -- on many embedded systems this is crucial to
|
||||
ensure all circuits on the board are properly reset for the next boot,
|
||||
in effect ensuring the system works the same after both a power-on and
|
||||
reboot event.
|
||||
watchdog service to delegate its reboot to. This delegation is to
|
||||
ensure that the system is rebooted by a hardware watchdog timer -- on
|
||||
many embedded systems this is crucial to ensure all circuits on the
|
||||
board are properly reset for the next boot, in effect ensuring the
|
||||
system works the same after both a power-on and reboot event.
|
||||
|
||||
The delegation is performed at the very last steps of system shutdown,
|
||||
if reboot has been selected and an elected watchdog is known, first a
|
||||
@@ -1155,8 +1411,6 @@ device descriptor. If the kernel driver has been built without this,
|
||||
the only option is to remove `/libexec/finit/watchdogd` or build without
|
||||
it at configure time.
|
||||
|
||||
[bootstrap]: bootstrap.md
|
||||
|
||||
|
||||
keventd
|
||||
-------
|
||||
|
||||
+19
-7
@@ -28,9 +28,16 @@ For your convenience a set of *optional* plugins are available:
|
||||
system and runs at `HOOK_BASEFS_UP`. The `/var`, `/run`, and `/dev`
|
||||
file systems must be writable for this plugin to work.
|
||||
|
||||
Note: On an embedded system both `/var` and `/run` can be `tmpfs` RAM
|
||||
disks and `/dev` is usually a `devtmpfs`. This must be defined in the
|
||||
`/etc/fstab` file and in the Linux kernel config.
|
||||
This plugin is a wrapper for the [tmpfiles.d(5)][] implementation that
|
||||
Finit has. Capable but limited: no aging, attributes, or subvolumes.
|
||||
|
||||
By default, `/lib/finit/tmpfiles.d` carries all the default .conf
|
||||
files distributed with Finit. It is read first but can be overridden
|
||||
by any of the standard tmpfiles.d directories, e.g. `/etc/tmpfiles.d`.
|
||||
|
||||
> **Note:** On an embedded system both `/var` and `/run` can be `tmpfs`
|
||||
> RAM disks and `/dev` is usually a `devtmpfs`. This must be defined
|
||||
> in the `/etc/fstab` file and in the Linux kernel config.
|
||||
|
||||
* *dbus.so*: Setup and start system message bus, D-Bus, at boot.
|
||||
_Optional plugin._
|
||||
@@ -50,8 +57,11 @@ For your convenience a set of *optional* plugins are available:
|
||||
customized at build-time using the `--with-hook-scripts-path=PATH`
|
||||
argument to `configure`.
|
||||
|
||||
* *hotplug.so*: Setup and start either udev or mdev hotplug daemon, if
|
||||
available. Enabled by default.
|
||||
* *hotplug.so*: Replaced with `/lib/finit/system/10-hotplug.conf`, which
|
||||
checks for `udevd` and `mdev` at boot. This file can be overridden by a
|
||||
file in `/etc/finit.d/10-hotplug.conf`.
|
||||
|
||||
Enabled by default.
|
||||
|
||||
> See the [Services](config.md#services) section in the configuration
|
||||
> guide for an example how to run `mdevd`, alternative to plain mdev.
|
||||
@@ -136,7 +146,7 @@ hook points:
|
||||
**Example:**
|
||||
|
||||
$ mkdir -p /libexec/finit/hook/sys/down
|
||||
$ cat <<EOF >/libexec/finit/hook/sys/foo.sh
|
||||
$ cat <<EOF >/libexec/finit/hook/sys/down/foo.sh
|
||||
#!/bin/sh
|
||||
echo 'I run just before the reboot() syscall at shutdown/reboot'
|
||||
echo 'I have access to /dev since devtmpfs is exempt from umount'
|
||||
@@ -146,7 +156,7 @@ hook points:
|
||||
fi
|
||||
exit 0
|
||||
EOF
|
||||
$ chmod +x /libexec/finit/hook/sys/foo.sh
|
||||
$ chmod +x /libexec/finit/hook/sys/down/foo.sh
|
||||
|
||||
> **Note:** to use hook scripts, even for pre-bootstrap and pre-shutdown
|
||||
> tasks, you must build with `configure --enable-hook-scripts-plugin`.
|
||||
@@ -217,3 +227,5 @@ Plugins like `tty.so` extend finit by acting on events, they are called
|
||||
I/O plugins and are called from the finit main loop when `poll()`
|
||||
detects an event. See the source code for `plugins/*.c` for more help
|
||||
and ideas.
|
||||
|
||||
[tmpfiles.d(5)]: https://www.freedesktop.org/software/systemd/man/tmpfiles.d.html
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 230 KiB After Width: | Height: | Size: 320 KiB |
+2
-2
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 164 KiB After Width: | Height: | Size: 814 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
@@ -0,0 +1,141 @@
|
||||
_cond()
|
||||
{
|
||||
initctl -pt cond dump | awk '{print $4}' | sed 's/<\(.*\)>/\1/'
|
||||
}
|
||||
|
||||
_ident()
|
||||
{
|
||||
if [ -n "$1" ]; then
|
||||
initctl ident | grep -q $1
|
||||
else
|
||||
initctl ident
|
||||
fi
|
||||
}
|
||||
|
||||
_svc()
|
||||
{
|
||||
initctl ls -pt | grep $1 | sed "s/.*\/\(.*\)/\1/g" | sort -u
|
||||
}
|
||||
|
||||
_enabled()
|
||||
{
|
||||
echo "$(_svc enabled)"
|
||||
}
|
||||
|
||||
_available()
|
||||
{
|
||||
all=$(mktemp)
|
||||
ena=$(mktemp)
|
||||
echo "$(_svc available)" >$all
|
||||
echo "$(_svc enabled)" >$ena
|
||||
grep -v -f $ena $all
|
||||
rm $all $ena
|
||||
}
|
||||
|
||||
# Determine first non-option word. Usually the command
|
||||
_firstword() {
|
||||
local firstword i
|
||||
|
||||
firstword=
|
||||
for ((i = 1; i < ${#COMP_WORDS[@]}; ++i)); do
|
||||
if [[ ${COMP_WORDS[i]} != -* ]]; then
|
||||
firstword=${COMP_WORDS[i]}
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
echo $firstword
|
||||
}
|
||||
|
||||
# Determine last non-option word. Uusally a sub-command
|
||||
_lastword() {
|
||||
local lastword i
|
||||
|
||||
lastword=
|
||||
for ((i = 1; i < ${#COMP_WORDS[@]}; ++i)); do
|
||||
if [[ ${COMP_WORDS[i]} != -* ]] && [[ -n ${COMP_WORDS[i]} ]] && [[ ${COMP_WORDS[i]} != $cur ]]; then
|
||||
lastword=${COMP_WORDS[i]}
|
||||
fi
|
||||
done
|
||||
|
||||
echo $lastword
|
||||
}
|
||||
|
||||
_initctl()
|
||||
{
|
||||
local cur command
|
||||
|
||||
cur=${COMP_WORDS[COMP_CWORD]}
|
||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
firstword=$(_firstword)
|
||||
lastword=$(_lastword)
|
||||
|
||||
commands="status cond debug help kill ls log version list enable \
|
||||
disable touch show cat edit create delete reload start \
|
||||
stop restart signal cgroup ps top plugins runlevel reboot \
|
||||
halt poweroff suspend utmp"
|
||||
cond_cmds="set get clear status dump"
|
||||
cond_types="hook net pid service task usr"
|
||||
signals="int term hup stop tstp cont usr1 usr2 pwr"
|
||||
options="-b --batch \
|
||||
-c --create \
|
||||
-d --debug \
|
||||
-f --force \
|
||||
-h --help \
|
||||
-j --json \
|
||||
-n --noerr \
|
||||
-1 --once \
|
||||
-p --plain \
|
||||
-q --quiet \
|
||||
-t --no-heading \
|
||||
-v --verbose \
|
||||
-V --version"
|
||||
|
||||
case "${firstword}" in
|
||||
enable)
|
||||
COMPREPLY=($(compgen -W "$(_available)" -- $cur))
|
||||
;;
|
||||
disable|touch)
|
||||
COMPREPLY=($(compgen -W "$(_enabled)" -- $cur))
|
||||
;;
|
||||
show|cat|edit|delete)
|
||||
COMPREPLY=($(compgen -W "$(_svc .)" -- $cur))
|
||||
;;
|
||||
start|stop|restart|log|status)
|
||||
COMPREPLY=($(compgen -W "$(_ident)" -- $cur))
|
||||
;;
|
||||
signal|kill)
|
||||
if $(_ident "${prev}"); then
|
||||
COMPREPLY=($(compgen -W "$signals" -- $cur))
|
||||
else
|
||||
COMPREPLY=($(compgen -W "$(_ident)" -- $cur))
|
||||
fi
|
||||
;;
|
||||
cond)
|
||||
case "${lastword}" in
|
||||
set|clear)
|
||||
compopt -o nospace
|
||||
COMPREPLY=($(compgen -W "usr/" -- $cur))
|
||||
;;
|
||||
get)
|
||||
COMPREPLY=($(compgen -W "$(_cond)" -- $cur))
|
||||
;;
|
||||
dump)
|
||||
COMPREPLY=($(compgen -W "$cond_types" -- $cur))
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=($(compgen -W "$cond_cmds" -- $cur))
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=($(compgen -W "$commands" -- $cur))
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ $cur == -* ]]; then
|
||||
COMPREPLY=($(compgen -W "$options" -- $cur))
|
||||
fi
|
||||
}
|
||||
|
||||
complete -F _initctl initctl
|
||||
+1
-1
@@ -275,7 +275,7 @@ The following condition families are available today:
|
||||
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
|
||||
PID files based on the service declaration
|
||||
.Cm name:id ,
|
||||
gives the condition pid/name:id
|
||||
.It Cm service
|
||||
|
||||
+89
-51
@@ -2,7 +2,7 @@
|
||||
.\" First parameter, NAME, should be all caps
|
||||
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||
.\" other parameters are allowed: see man(7), man(1)
|
||||
.Dd Apr 24, 2023
|
||||
.Dd July 11, 2023
|
||||
.Dt FINIT.CONF 5 SMM
|
||||
.Os Linux
|
||||
.Sh NAME
|
||||
@@ -12,40 +12,64 @@
|
||||
.Nm /etc/finit.conf
|
||||
.Nm /etc/finit.d/*.conf
|
||||
.Nm /etc/finit.d/available/*.conf
|
||||
.Nm /etc/finit.d/enabled/*.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.
|
||||
.Nm Finit
|
||||
based systems can be set up with a single file:
|
||||
.Pa /etc/finit.conf .
|
||||
This is the traditional way of doing it which can be ideal for some
|
||||
setups since it gives a great overview of the system configuration.
|
||||
.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
|
||||
More comprehensive setups, however, require more careful planning.
|
||||
The recommendation is per-package
|
||||
.Cm *.conf
|
||||
files in
|
||||
.Pa /etc/finit.d/available/ .
|
||||
This allows end users to enable and disable parts of the system
|
||||
configuration at runtime. Finit tracks which tasks and services belong
|
||||
to a given file, so that when the user calls
|
||||
.Cm initctl reload
|
||||
to activate the changes they have made, only the affected tasks and
|
||||
services are stopped, started, or restarted. Hence, this approach is
|
||||
useful for modern package-based Linux distributions.
|
||||
.Pp
|
||||
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.
|
||||
The following sections describe the more of this in detail, starting
|
||||
with files, the file format, and available directives. Remember to
|
||||
also visit the other manual pages (references at the bottom).
|
||||
.Sh FILES
|
||||
.Bl -tag -width /etc/finit.d/available/*.conf -compact
|
||||
.It Pa /etc/finit.conf
|
||||
Main configuration file
|
||||
Main configuration file, optional
|
||||
.It Pa /etc/finit.d/*.conf
|
||||
Static service definitions
|
||||
Static (system) service definitions
|
||||
.It Pa /etc/finit.d/available/*.conf
|
||||
Available services
|
||||
Available (installed) services
|
||||
.It Pa /etc/finit.d/enabled/*.conf
|
||||
Enabled services, symlinks from available
|
||||
Enabled services (symlink back)
|
||||
.El
|
||||
.Pp
|
||||
Static services,
|
||||
.Cm .conf
|
||||
files in
|
||||
.Pa /etc/finit.d/ ,
|
||||
cannot be enabled or disabled using
|
||||
.Cm initctl [enable | disable] service[.conf] .
|
||||
An enabled service is a symlink back to the corresponding
|
||||
.Cm ../available/
|
||||
service
|
||||
.Cm .conf
|
||||
file. Please use the
|
||||
.Cm initctl
|
||||
tool to manage these symlinks to ensure proper operation.
|
||||
.Pp
|
||||
.Sy NOTE:
|
||||
Previous versions of
|
||||
.Nm Finit
|
||||
created symlinks in
|
||||
.Pa /etc/finit.d/
|
||||
if
|
||||
.Pa /etc/finit.d/enabled/
|
||||
was missing, this is as of v4.4 not supported.
|
||||
.Sh FILE FORMAT
|
||||
The file format is line based, empty lines and comments, lines starting
|
||||
with `#', are ignored. A configuration directive starts with a keyword
|
||||
@@ -151,13 +175,13 @@ 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
|
||||
.Cm service
|
||||
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
|
||||
primary intention for this command is to be able to re-use traditional
|
||||
SysV init scripts in Linux distributions.
|
||||
.Pp
|
||||
When entering an allowed runlevel, Finit calls
|
||||
.Cm init-script start ,
|
||||
when entering a disallowed runlevel, Finit calls
|
||||
@@ -410,30 +434,42 @@ 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
|
||||
Services, including the
|
||||
.Cm sysv
|
||||
variant, support pre/post/ready and cleanup scripts:
|
||||
.Bl -tag -width 1n
|
||||
.It Cm pre:[0-3600,]script
|
||||
called before the sysv/service is stated
|
||||
.It Cm post:[0-3600,]script
|
||||
called after the sysv/service has stopped
|
||||
.It Cm ready:[0-3600,]script
|
||||
called when the sysv/service is ready
|
||||
.It Cm cleanup:[0-3600,]script
|
||||
called when run/task/sysv/service is removed
|
||||
.El
|
||||
.Pp
|
||||
The optional number (0-3600) is the timeout before Finit kills the
|
||||
script, it defaults to the kill delay value and can be disabled by
|
||||
setting it to zero. These scripts run as the same
|
||||
.Cm @USER:GROUP
|
||||
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
|
||||
of the given user. The scripts are not called with any argument, but
|
||||
both get a set of environment variables:
|
||||
.Pp
|
||||
.Bl -tag -width 1n -compact
|
||||
.It Cm SERVICE_IDENT=foo:1
|
||||
.It Cm SERVICE_NAME=foo
|
||||
.It Cm SERVICE_ID=1
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Cm post:script
|
||||
is called with an additional set of environment variables:
|
||||
is called with an additional set of environment variables, and yes the
|
||||
naming looks like it should be swapped:
|
||||
.Bl -tag -offset indent -width 1n
|
||||
.It Cm EXIT_CODE=[exited,signal,crashed]
|
||||
set to one of
|
||||
@@ -447,10 +483,12 @@ 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.
|
||||
When a run/task/sys/service is removed (disable + reload) it is first
|
||||
stopped and then removed from the runlevel. The
|
||||
.Cm post:script
|
||||
always runs when the process has stopped, and the
|
||||
.Cm cleanup:script
|
||||
runs when the the stanza has been removed from the runlevel.
|
||||
.It Cm runparts Aq DIR
|
||||
Call
|
||||
.Xr run-parts 8
|
||||
@@ -960,6 +998,6 @@ settings in
|
||||
.Xr finit 8 ,
|
||||
.Xr initctl 8
|
||||
.Sh AUTHORS
|
||||
.Nm finit
|
||||
.Nm Finit
|
||||
was conceived and reverse engineered by Claudio Matsuoka. Since v1.0,
|
||||
maintained by Joachim Wiberg, with contributions by many others.
|
||||
|
||||
@@ -240,6 +240,11 @@ Show top-like listing based on cgroups.
|
||||
List installed plugins.
|
||||
.It Nm Ar runlevel Op Ar 0-9
|
||||
Show or set runlevel: 0 halt, 6 reboot.
|
||||
.Pp
|
||||
If called at boot (runlevel S) to set the runlevel, Finit only schedules
|
||||
the change, effectively overriding the configured runlevel from
|
||||
.Pa /etc/finit.conf .
|
||||
Useful to trigger a fail-safe mode, or similar.
|
||||
.It Nm Ar reboot
|
||||
Reboot system, default if
|
||||
.Cm reboot
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Save and restore ALSA sound settings using alsactl
|
||||
*
|
||||
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2024 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 @@
|
||||
/* Setup necessary system files for, e.g. UTMP (tracking logins)
|
||||
*
|
||||
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2024 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
|
||||
|
||||
+6
-7
@@ -1,6 +1,6 @@
|
||||
/* Setup and start system message bus, D-Bus
|
||||
*
|
||||
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2024 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
|
||||
@@ -83,6 +83,7 @@ static char *dbus_pidfn(void)
|
||||
break;
|
||||
}
|
||||
*pos = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
@@ -142,23 +143,21 @@ static void setup(void *arg)
|
||||
|
||||
/* Generate machine id for dbus */
|
||||
if (whichp("dbus-uuidgen"))
|
||||
run_interactive("dbus-uuidgen --ensure", "Creating machine UUID for D-Bus");
|
||||
run_interactive("dbus-uuidgen --ensure", "Verifying D-Bus machine UUID");
|
||||
|
||||
/*
|
||||
* Register service with Finit
|
||||
* Note: dbus drops privs after starting up.
|
||||
*/
|
||||
if (pidfn) {
|
||||
snprintf(line, sizeof(line), "[S123456789] cgroup.system name:dbus pid:!%s %s %s -- %s",
|
||||
snprintf(line, sizeof(line), "[S123456789] cgroup.system notify:none name:dbus pid:!%s %s %s -- %s",
|
||||
pidfn, cmd, DBUS_ARGS, DBUS_DESC);
|
||||
free(pidfn);
|
||||
} else
|
||||
snprintf(line, sizeof(line), "[S123456789] cgroup.system name:dbus %s %s -- %s",
|
||||
snprintf(line, sizeof(line), "[S123456789] cgroup.system notify:none name:dbus %s %s -- %s",
|
||||
cmd, DBUS_ARGS, DBUS_DESC);
|
||||
|
||||
if (service_register(SVC_TYPE_SERVICE, line, global_rlimit, NULL))
|
||||
err(1, "Failed registering %s", DBUS_DAEMON);
|
||||
|
||||
conf_save_service(SVC_TYPE_SERVICE, line, "dbus.conf");
|
||||
free(cmd);
|
||||
}
|
||||
|
||||
|
||||
+3
-4
@@ -1,6 +1,6 @@
|
||||
/* Coldplug modules using modalias magic
|
||||
*
|
||||
* Copyright (c) 2021-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2021-2024 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
|
||||
@@ -132,11 +132,10 @@ static FILE *maybe_fopen_alias(const char *file, const char *path)
|
||||
{
|
||||
const char *basename;
|
||||
|
||||
basename = rindex(path, '/');
|
||||
if (!basename)
|
||||
basename = basenm(path);
|
||||
if (!strcmp(basename, path))
|
||||
return NULL;
|
||||
|
||||
basename++;
|
||||
if (strcmp(file, basename))
|
||||
return NULL;
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ static int modules_load(const char *file, int index)
|
||||
}
|
||||
|
||||
while ((line = fparseln(fp, NULL, NULL, NULL, 0))) {
|
||||
char cmd[CMD_SIZE * 2], *mod, *args, *set;
|
||||
char cmd[CMD_SIZE], *mod, *args, *set;
|
||||
|
||||
/*
|
||||
* fparseln() skips regular UNIX comments only.
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
/* Netlink plugin for IFUP/IFDN and GW events
|
||||
*
|
||||
* Copyright (C) 2009-2011 Mårten Wikström <marten.wikstrom@keystream.se>
|
||||
* Copyright (C) 2009-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (C) 2009-2024 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
|
||||
|
||||
+21
-11
@@ -1,7 +1,7 @@
|
||||
/* Simple pidfile event monitor for the Finit condition engine
|
||||
*
|
||||
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
|
||||
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2016-2024 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,7 +52,7 @@ static int pidfile_add_path(struct iwatch *iw, char *path)
|
||||
ptr = slash++;
|
||||
slash = strchr(ptr, '/');
|
||||
if (slash) {
|
||||
dbg("Path too deep, skipping.");
|
||||
dbg("Path too deep, skipping %s", path);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -66,6 +66,7 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
|
||||
char cond[MAX_COND_LEN];
|
||||
char fn[PATH_MAX];
|
||||
svc_t *svc;
|
||||
char *nm;
|
||||
|
||||
paste(fn, sizeof(fn), dir, name);
|
||||
if (fnmatch("*\\.pid", fn, 0) && fnmatch("*/pid", fn, 0))
|
||||
@@ -79,16 +80,23 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
|
||||
return;
|
||||
}
|
||||
|
||||
dbg("Found svc %s for %s with pid %d", svc->name, fn, svc->pid);
|
||||
/* Service condistion to set/clear */
|
||||
mkcond(svc, cond, sizeof(cond));
|
||||
|
||||
nm = svc_ident(svc, NULL, 0);
|
||||
dbg("Found svc %s for %s with pid %d", nm, fn, svc->pid);
|
||||
if (svc_is_stopping(svc)) {
|
||||
dbg("Ignoring pidfile death rattles while service %s is %s", nm, svc_status(svc));
|
||||
goto sneaky_zebra;
|
||||
}
|
||||
|
||||
if (mask & (IN_CLOSE_WRITE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) {
|
||||
/*
|
||||
* only mark native services as started, the s6 and
|
||||
* systemd style services rely on their respective
|
||||
* readiness notification. Issue #343
|
||||
*/
|
||||
if (!svc->notify)
|
||||
if (svc->notify == SVC_NOTIFY_PID)
|
||||
svc_started(svc);
|
||||
|
||||
if (!svc_has_pidfile(svc)) {
|
||||
@@ -120,13 +128,15 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
|
||||
}
|
||||
}
|
||||
|
||||
cond_set(cond);
|
||||
if (!svc->notify)
|
||||
service_ready(svc);
|
||||
if (svc->notify == SVC_NOTIFY_PID)
|
||||
cond_set(cond);
|
||||
if (svc->notify == SVC_NOTIFY_PID || svc->notify == SVC_NOTIFY_NONE)
|
||||
service_ready(svc, 1);
|
||||
} else if (mask & IN_DELETE) {
|
||||
sneaky_zebra:
|
||||
cond_clear(cond);
|
||||
if (!svc->notify)
|
||||
service_ready(svc);
|
||||
if (svc->notify == SVC_NOTIFY_PID)
|
||||
service_ready(svc, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,8 +250,8 @@ static void pidfile_reconf(void *arg)
|
||||
if (svc_is_changed(svc) || svc_is_starting(svc))
|
||||
continue;
|
||||
|
||||
if (!svc->notify)
|
||||
service_ready(svc);
|
||||
if (svc->notify == SVC_NOTIFY_PID)
|
||||
service_ready(svc, 1);
|
||||
|
||||
mkcond(svc, cond, sizeof(cond));
|
||||
if (cond_get(cond) == COND_ON)
|
||||
|
||||
+6
-2
@@ -1,6 +1,6 @@
|
||||
/* Set kernel variables from /etc/sysctl.conf et al
|
||||
*
|
||||
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2016-2024 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
|
||||
@@ -32,6 +32,10 @@
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
|
||||
#ifndef SYSCTL_PATH
|
||||
#define SYSCTL_PATH "/sbin/sysctl"
|
||||
#endif
|
||||
|
||||
static void setup(void *arg)
|
||||
{
|
||||
glob_t gl;
|
||||
@@ -54,7 +58,7 @@ static void setup(void *arg)
|
||||
for (i = 0; i < gl.gl_pathc; i++) {
|
||||
char cmd[160];
|
||||
|
||||
snprintf(cmd, sizeof(cmd), "/sbin/sysctl -e -p %s >/dev/null", gl.gl_pathv[i]);
|
||||
snprintf(cmd, sizeof(cmd), "%s -e -p %s >/dev/null", SYSCTL_PATH, gl.gl_pathv[i]);
|
||||
run(cmd, "sysctl");
|
||||
}
|
||||
globfree(&gl);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Setup necessary files for resolvconf
|
||||
*
|
||||
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2024 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
|
||||
@@ -45,7 +45,7 @@ static void setup(void *arg)
|
||||
|
||||
touch("/etc/resolvconf/run/enable-updates");
|
||||
chdir("/etc/resolvconf/run/interface");
|
||||
run_parts("/etc/resolvconf/update.d", "-i", NULL, 0);
|
||||
run_parts("/etc/resolvconf/update.d", "-i", NULL, 0, 0);
|
||||
chdir("/");
|
||||
}
|
||||
|
||||
|
||||
+179
-61
@@ -1,6 +1,6 @@
|
||||
/* Save and restore RTC using hwclock
|
||||
*
|
||||
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2024 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
|
||||
@@ -36,8 +36,15 @@
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
|
||||
/* Kernel RTC driver validates against this date for sanity check */
|
||||
/*
|
||||
* Kernel RTC driver validates against this date for sanity check. The
|
||||
* on NTP sync the driver can also update the RTC every 11 mins. We use
|
||||
* the same update interval to handle manual time set and file save.
|
||||
*/
|
||||
#define RTC_TIMESTAMP_BEGIN_2000 "2000-01-01 00:00:00"
|
||||
#define RTC_FMT "%Y-%m-%d %H:%M:%S"
|
||||
#define RTC_PERIOD (11 * 60 * 1000)
|
||||
|
||||
#ifdef RTC_TIMESTAMP_CUSTOM
|
||||
static char *rtc_timestamp = RTC_TIMESTAMP_CUSTOM;
|
||||
#else
|
||||
@@ -45,6 +52,10 @@ static char *rtc_timestamp = RTC_TIMESTAMP_BEGIN_2000;
|
||||
#endif
|
||||
static time_t rtc_date_fallback = 946684800LL;
|
||||
|
||||
static char *rtc_file = RTC_FILE;
|
||||
static uev_t rtc_timer;
|
||||
|
||||
|
||||
static void tz_set(char *tz, size_t len)
|
||||
{
|
||||
char *ptr;
|
||||
@@ -68,6 +79,125 @@ static void tz_restore(char *tz)
|
||||
tzset();
|
||||
}
|
||||
|
||||
static int time_set(struct tm *tm)
|
||||
{
|
||||
struct tm fallback = { 0 };
|
||||
struct timeval tv = { 0 };
|
||||
char tz[128];
|
||||
int rc = 0;
|
||||
|
||||
tz_set(tz, sizeof(tz));
|
||||
|
||||
if (!tm) {
|
||||
logit(LOG_NOTICE, "Resetting system clock to kernel default, %s.", rtc_timestamp);
|
||||
tm = &fallback;
|
||||
|
||||
/* Attempt to set RTC to a sane value ... */
|
||||
tv.tv_sec = rtc_date_fallback;
|
||||
if (!gmtime_r(&tv.tv_sec, tm)) {
|
||||
rc = 1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
tm->tm_isdst = -1; /* Use tzdata to figure it out, please. */
|
||||
tv.tv_sec = mktime(tm);
|
||||
if (tv.tv_sec == (time_t)-1 || tv.tv_sec < rtc_date_fallback) {
|
||||
errno = EINVAL;
|
||||
rc = 2;
|
||||
} else {
|
||||
if (settimeofday(&tv, NULL) == -1)
|
||||
rc = 1;
|
||||
}
|
||||
out:
|
||||
tz_restore(tz);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int time_get(struct tm *tm)
|
||||
{
|
||||
struct timeval tv = { 0 };
|
||||
char tz[128];
|
||||
int rc = 0;
|
||||
|
||||
tz_set(tz, sizeof(tz));
|
||||
|
||||
rc = gettimeofday(&tv, NULL);
|
||||
if (rc < 0 || tv.tv_sec < rtc_date_fallback)
|
||||
rc = 2;
|
||||
else
|
||||
gmtime_r(&tv.tv_sec, tm);
|
||||
|
||||
tz_restore(tz);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void file_save(void *arg)
|
||||
{
|
||||
struct tm tm = { 0 };
|
||||
int rc = 0;
|
||||
FILE *fp;
|
||||
|
||||
if (!rtc_file)
|
||||
return;
|
||||
|
||||
fp = fopen(rtc_file, "w");
|
||||
if (!fp) {
|
||||
logit(LOG_WARNING, "Failed saving system clock to %s, code %d: %s",
|
||||
rtc_file, errno, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
if ((rc = time_get(&tm))) {
|
||||
logit(LOG_WARNING, "System clock invalid, before %s, not saving", rtc_timestamp);
|
||||
print_desc(NULL, "System clock invalid, skipping");
|
||||
} else {
|
||||
char buf[32] = { 0 };
|
||||
|
||||
print_desc(NULL, "Saving system clock to file");
|
||||
strftime(buf, sizeof(buf), RTC_FMT, &tm);
|
||||
fprintf(fp, "%s\n", buf);
|
||||
}
|
||||
|
||||
print(rc, NULL);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
static void file_restore(void *arg)
|
||||
{
|
||||
struct tm tm = { 0 };
|
||||
int rc = 1;
|
||||
FILE *fp;
|
||||
|
||||
if (!rtc_file) {
|
||||
logit(LOG_NOTICE, "System has no RTC (missing driver?), skipping restore.");
|
||||
return;
|
||||
}
|
||||
|
||||
print_desc(NULL, "Restoring system clock from backup");
|
||||
|
||||
fp = fopen(rtc_file, "r");
|
||||
if (fp) {
|
||||
char buf[32];
|
||||
|
||||
if (fgets(buf, sizeof(buf), fp)) {
|
||||
chomp(buf);
|
||||
strptime(buf, RTC_FMT, &tm);
|
||||
rc = time_set(&tm);
|
||||
}
|
||||
fclose(fp);
|
||||
} else
|
||||
logit(LOG_WARNING, "Missing %s", rtc_file);
|
||||
|
||||
if (rc) {
|
||||
time_set(NULL);
|
||||
rc = 2;
|
||||
}
|
||||
|
||||
print(rc, NULL);
|
||||
}
|
||||
|
||||
static int rtc_open(void)
|
||||
{
|
||||
char *alt[] = {
|
||||
@@ -91,10 +221,8 @@ static int rtc_open(void)
|
||||
|
||||
static void rtc_save(void *arg)
|
||||
{
|
||||
struct timeval tv = { 0 };
|
||||
struct tm tm = { 0 };
|
||||
int fd, rc = 0;
|
||||
char tz[128];
|
||||
|
||||
if (rescue) {
|
||||
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||
@@ -105,38 +233,26 @@ static void rtc_save(void *arg)
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
tz_set(tz, sizeof(tz));
|
||||
rc = gettimeofday(&tv, NULL);
|
||||
if (rc < 0 || tv.tv_sec < rtc_date_fallback) {
|
||||
if ((rc = time_get(&tm))) {
|
||||
print_desc(NULL, "System clock invalid, not saving to RTC");
|
||||
invalid:
|
||||
logit(LOG_ERR, "System clock invalid, before %s, not saving to RTC", rtc_timestamp);
|
||||
} else {
|
||||
print_desc(NULL, "Saving system clock (UTC) to RTC");
|
||||
rc = ioctl(fd, RTC_SET_TIME, &tm);
|
||||
}
|
||||
|
||||
if (rc && errno == EINVAL) {
|
||||
logit(LOG_WARNING, "System clock invalid, before %s, not saving to RTC", rtc_timestamp);
|
||||
rc = 2;
|
||||
goto out;
|
||||
}
|
||||
|
||||
print_desc(NULL, "Saving system time (UTC) to RTC");
|
||||
|
||||
gmtime_r(&tv.tv_sec, &tm);
|
||||
if (ioctl(fd, RTC_SET_TIME, &tm) < 0) {
|
||||
if (EINVAL == errno)
|
||||
goto invalid;
|
||||
rc = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
tz_restore(tz);
|
||||
print(rc, NULL);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void rtc_restore(void *arg)
|
||||
{
|
||||
struct timeval tv = { 0 };
|
||||
struct tm tm = { 0 };
|
||||
int fd, rc = 0;
|
||||
char tz[128];
|
||||
|
||||
if (rescue) {
|
||||
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||
@@ -145,65 +261,62 @@ static void rtc_restore(void *arg)
|
||||
|
||||
fd = rtc_open();
|
||||
if (fd < 0) {
|
||||
logit(LOG_NOTICE, "System has no RTC (missing driver?), skipping restore.");
|
||||
file_restore(arg);
|
||||
return;
|
||||
}
|
||||
|
||||
tz_set(tz, sizeof(tz));
|
||||
if (ioctl(fd, RTC_RD_TIME, &tm) < 0) {
|
||||
if ((rc = ioctl(fd, RTC_RD_TIME, &tm)) < 0) {
|
||||
char msg[120];
|
||||
|
||||
snprintf(msg, sizeof(msg), "Failed restoring system clock, %s",
|
||||
EINVAL == errno ? "RTC time is too old" :
|
||||
ENOENT == errno ? "RTC has no saved time" : "see log for details");
|
||||
print_desc(NULL, msg);
|
||||
} else {
|
||||
print_desc(NULL, "Restoring system clock (UTC) from RTC");
|
||||
rc = time_set(&tm);
|
||||
}
|
||||
|
||||
invalid:
|
||||
logit(LOG_ERR, "Failed restoring system clock from RTC.");
|
||||
if (rc) {
|
||||
logit(LOG_WARNING, "Failed restoring system clock from RTC.");
|
||||
if (EINVAL == errno)
|
||||
logit(LOG_ERR, "RTC time is too old (before %s)", rtc_timestamp);
|
||||
logit(LOG_WARNING, "RTC time is too old (before %s)", rtc_timestamp);
|
||||
else if (ENOENT == errno)
|
||||
logit(LOG_ERR, "RTC has no previously saved (valid) time.");
|
||||
logit(LOG_WARNING, "RTC has no previously saved (valid) time.");
|
||||
else
|
||||
logit(LOG_ERR, "RTC error code %d: %s", errno, strerror(errno));
|
||||
logit(LOG_WARNING, "RTC error code %d: %s", errno, strerror(errno));
|
||||
|
||||
/* Been here already? */
|
||||
if (rc)
|
||||
goto out;
|
||||
print(2, NULL);
|
||||
|
||||
/* Attempt to set RTC to a sane value ... */
|
||||
tv.tv_sec = rtc_date_fallback;
|
||||
if (!gmtime_r(&tv.tv_sec, &tm))
|
||||
goto out;
|
||||
/* Try restoring from last save game */
|
||||
if (rtc_file)
|
||||
file_restore(arg);
|
||||
} else
|
||||
print(0, NULL);
|
||||
|
||||
logit(LOG_NOTICE, "Resetting RTC to kernel default, %s.", rtc_timestamp);
|
||||
rc = 2;
|
||||
}
|
||||
|
||||
print_desc(NULL, "Restoring system clock (UTC) from RTC");
|
||||
tm.tm_isdst = -1; /* Use tzdata to figure it out, please. */
|
||||
tv.tv_sec = mktime(&tm);
|
||||
if (tv.tv_sec == (time_t)-1 || tv.tv_sec < rtc_date_fallback) {
|
||||
errno = EINVAL;
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
if (settimeofday(&tv, NULL) == -1)
|
||||
rc = 1;
|
||||
|
||||
out:
|
||||
tz_restore(tz);
|
||||
print(rc, NULL);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
||||
static void save(void *arg)
|
||||
{
|
||||
rtc_save(arg);
|
||||
file_save(arg);
|
||||
}
|
||||
|
||||
static void update(uev_t *w, void *arg, int events)
|
||||
{
|
||||
save(arg);
|
||||
}
|
||||
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_BASEFS_UP] = {
|
||||
.cb = rtc_restore
|
||||
},
|
||||
.hook[HOOK_SHUTDOWN] = {
|
||||
.cb = rtc_save
|
||||
.cb = save
|
||||
}
|
||||
};
|
||||
|
||||
@@ -211,16 +324,21 @@ PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
struct tm tm = { 0 };
|
||||
|
||||
if (!strptime(rtc_timestamp, "%Y-%m-%d %H:%M", &tm))
|
||||
rtc_date_fallback = mktime(&tm);
|
||||
else
|
||||
if (!strptime(rtc_timestamp, RTC_FMT, &tm)) {
|
||||
logit(LOG_WARNING, "Invalid restore date '%s', reverting to '%s'",
|
||||
rtc_timestamp, RTC_TIMESTAMP_BEGIN_2000);
|
||||
rtc_timestamp = RTC_TIMESTAMP_BEGIN_2000;
|
||||
} else
|
||||
rtc_date_fallback = mktime(&tm);
|
||||
|
||||
uev_timer_init(ctx, &rtc_timer, update, NULL, RTC_PERIOD, RTC_PERIOD);
|
||||
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
uev_timer_stop(&rtc_timer);
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* System condition event monitor for the Finit condition engine
|
||||
*
|
||||
* Copyright (c) 2021-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2021-2024 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,7 +1,7 @@
|
||||
/* Optional TTY Watcher, used to catch new TTYs that are discovered, e.g., USB
|
||||
*
|
||||
* Copyright (c) 2013 Mattias Walström <lazzer@gmail.com>
|
||||
* Copyright (c) 2013-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2013-2024 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
|
||||
|
||||
+50
-11
@@ -1,6 +1,6 @@
|
||||
/* Setup and save random seed at boot/shutdown
|
||||
*
|
||||
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2024 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 <sys/stat.h>
|
||||
#include <sys/time.h> /* gettimeofday() */
|
||||
#include <sys/types.h>
|
||||
#include <sys/resource.h> /* getrusage() */
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
@@ -42,11 +43,43 @@
|
||||
#define RANDOM_BYTES (32*1024)
|
||||
#endif
|
||||
|
||||
#ifdef RANDOMSEED
|
||||
/*
|
||||
* This is the fallback seed function, please make sure you have drivers
|
||||
* enabling /dev/hwrng instead.
|
||||
*/
|
||||
static void fallback(FILE *fp)
|
||||
{
|
||||
unsigned long seed;
|
||||
struct timeval tv;
|
||||
struct rusage ru;
|
||||
int iter = 128;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
getrusage(RUSAGE_SELF, &ru);
|
||||
|
||||
/* Mix multiple sources of "randomness" */
|
||||
seed = tv.tv_sec ^ (tv.tv_usec << 16);
|
||||
seed ^= ru.ru_utime.tv_sec ^ (ru.ru_utime.tv_usec << 16);
|
||||
seed ^= ru.ru_stime.tv_sec ^ (ru.ru_stime.tv_usec << 16);
|
||||
seed ^= getpid() << 8;
|
||||
|
||||
srandom(seed);
|
||||
while (iter--) {
|
||||
uint32_t i, prng = random();
|
||||
|
||||
for (i = 0; i < sizeof(prng); i++)
|
||||
fputc((prng >> (i * CHAR_BIT)) & UCHAR_MAX, fp);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void setup(void *arg)
|
||||
{
|
||||
#ifdef RANDOMSEED
|
||||
struct rand_pool_info *rpi;
|
||||
ssize_t len = 0;
|
||||
struct stat st;
|
||||
int rc = -1;
|
||||
int fd, err;
|
||||
|
||||
@@ -55,7 +88,7 @@ static void setup(void *arg)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fexist(RANDOMSEED)) {
|
||||
if (stat(RANDOMSEED, &st) || st.st_size < 512) {
|
||||
int ret = 1;
|
||||
mode_t prev;
|
||||
FILE *fp;
|
||||
@@ -64,16 +97,22 @@ static void setup(void *arg)
|
||||
prev = umask(077);
|
||||
fp = fopen(RANDOMSEED, "w");
|
||||
if (fp) {
|
||||
int iter = 128;
|
||||
struct timeval tv;
|
||||
const char *hwrng = "/dev/hwrng";
|
||||
FILE *hw;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
srandom(tv.tv_sec % 3600);
|
||||
while (iter--) {
|
||||
uint32_t i, prng = random();
|
||||
hw = fopen(hwrng, "r");
|
||||
if (hw) {
|
||||
char buf[512];
|
||||
size_t len;
|
||||
|
||||
for (i = 0; i < sizeof(prng); i++)
|
||||
fputc((prng >> (i * CHAR_BIT)) & UCHAR_MAX, fp);
|
||||
len = fread(buf, sizeof(buf[0]), sizeof(buf), hw);
|
||||
if (len == 0)
|
||||
fallback(fp);
|
||||
else
|
||||
len = fwrite(buf, sizeof(buf[0]), len, fp);
|
||||
fclose(hw);
|
||||
} else {
|
||||
fallback(fp);
|
||||
}
|
||||
ret = fclose(fp);
|
||||
}
|
||||
@@ -130,7 +169,7 @@ static void setup(void *arg)
|
||||
close(fd);
|
||||
free(rpi);
|
||||
if (rc < 0)
|
||||
logit(LOG_ERR, "Failed adding entropy to kernel random pool: %s", strerror(err));
|
||||
logit(LOG_WARNING, "Failed adding entropy to kernel random pool: %s", strerror(err));
|
||||
print_result(rc < 0);
|
||||
return;
|
||||
fallback:
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* User-defined condition event monitor for the Finit condition engine
|
||||
*
|
||||
* Copyright (c) 2021-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2021-2024 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,6 +1,6 @@
|
||||
/* Console setup (for X)
|
||||
*
|
||||
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2024 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
|
||||
|
||||
@@ -5,6 +5,7 @@ initctl
|
||||
keventd
|
||||
logit
|
||||
reboot
|
||||
runparts
|
||||
sulogin
|
||||
watchdogd
|
||||
Makefile
|
||||
|
||||
+9
-2
@@ -8,7 +8,7 @@ AM_LDFLAGS = -export-dynamic
|
||||
endif
|
||||
|
||||
sbin_PROGRAMS = finit initctl
|
||||
pkglibexec_PROGRAMS = getty logit
|
||||
pkglibexec_PROGRAMS = getty logit runparts
|
||||
if SULOGIN
|
||||
pkglibexec_PROGRAMS += sulogin
|
||||
endif
|
||||
@@ -19,6 +19,8 @@ if WATCHDOGD
|
||||
pkglibexec_PROGRAMS += watchdogd
|
||||
endif
|
||||
|
||||
dist_pkglibexec_SCRIPTS = coldplug
|
||||
|
||||
finit_pkglibdir = $(pkglibdir)
|
||||
finit_pkglib_SCRIPTS = rescue.conf sample.conf
|
||||
|
||||
@@ -32,6 +34,11 @@ keventd_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||
keventd_CFLAGS += $(lite_CFLAGS)
|
||||
keventd_LDADD = $(lite_LIBS)
|
||||
|
||||
runparts_SOURCES = runparts.c
|
||||
runparts_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||
runparts_CFLAGS += $(lite_CFLAGS)
|
||||
runparts_LDADD = $(lite_LIBS)
|
||||
|
||||
sulogin_SOURCES = sulogin.c
|
||||
sulogin_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||
sulogin_LDADD = -lcrypt
|
||||
@@ -54,7 +61,7 @@ finit_SOURCES = api.c cgroup.c cgroup.h \
|
||||
mdadm.c mount.c \
|
||||
pid.c pid.h \
|
||||
plugin.c plugin.h private.h \
|
||||
schedule.c schedule.h \
|
||||
runparts.c schedule.c schedule.h \
|
||||
service.c service.h \
|
||||
sig.c sig.h \
|
||||
sm.c sm.h \
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* External client API, using UNIX domain socket.
|
||||
*
|
||||
* Copyright (c) 2015-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2015-2024 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
|
||||
@@ -332,6 +332,11 @@ static void api_cb(uev_t *w, void *arg, int events)
|
||||
int sd, lvl;
|
||||
svc_t *svc;
|
||||
|
||||
if (UEV_ERROR == events) {
|
||||
dbg("%s(): api socket %d invalid.", __func__, w->fd);
|
||||
goto error;
|
||||
}
|
||||
|
||||
sd = accept(w->fd, NULL, NULL);
|
||||
if (sd < 0) {
|
||||
err(1, "Failed serving API request");
|
||||
@@ -367,7 +372,6 @@ static void api_cb(uev_t *w, void *arg, int events)
|
||||
}
|
||||
|
||||
switch (rq.cmd) {
|
||||
case INIT_CMD_RUNLVL:
|
||||
case INIT_CMD_RELOAD:
|
||||
case INIT_CMD_START_SVC:
|
||||
case INIT_CMD_RESTART_SVC:
|
||||
@@ -378,7 +382,9 @@ static void api_cb(uev_t *w, void *arg, int events)
|
||||
case INIT_CMD_POWEROFF:
|
||||
case INIT_CMD_SUSPEND:
|
||||
if (IS_RESERVED_RUNLEVEL(runlevel)) {
|
||||
warnx("Unsupported command in runlevel S and 6.");
|
||||
strterm(rq.data, sizeof(rq.data));
|
||||
warnx("Unsupported command (cmd: %d, data: %s) in runlevel S and 6/0.",
|
||||
rq.cmd, rq.data);
|
||||
goto leave;
|
||||
}
|
||||
default:
|
||||
@@ -387,6 +393,14 @@ static void api_cb(uev_t *w, void *arg, int events)
|
||||
|
||||
switch (rq.cmd) {
|
||||
case INIT_CMD_RUNLVL:
|
||||
/* Allow changing cfglevel in runlevel S */
|
||||
if (IS_RESERVED_RUNLEVEL(runlevel)) {
|
||||
if (runlevel != INIT_LEVEL) {
|
||||
warnx("Cannot abort runlevel 6/0.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (rq.runlevel) {
|
||||
case 's':
|
||||
case 'S':
|
||||
@@ -400,7 +414,12 @@ static void api_cb(uev_t *w, void *arg, int events)
|
||||
halt = SHUT_OFF;
|
||||
if (lvl == 6)
|
||||
halt = SHUT_REBOOT;
|
||||
service_runlevel(lvl);
|
||||
|
||||
/* User requested change in next runlevel */
|
||||
if (runlevel == INIT_LEVEL)
|
||||
cfglevel = lvl;
|
||||
else
|
||||
service_runlevel(lvl);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -564,8 +583,6 @@ static void api_cb(uev_t *w, void *arg, int events)
|
||||
|
||||
leave:
|
||||
close(sd);
|
||||
if (UEV_ERROR == events)
|
||||
goto error;
|
||||
return;
|
||||
error:
|
||||
api_exit();
|
||||
|
||||
+11
-1
@@ -1,6 +1,6 @@
|
||||
/* Finit control group support functions
|
||||
*
|
||||
* Copyright (c) 2019-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2019-2024 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
|
||||
@@ -259,6 +259,11 @@ static void cgroup_events_cb(uev_t *w, void *arg, int events)
|
||||
ssize_t sz;
|
||||
size_t off;
|
||||
|
||||
if (UEV_ERROR == events) {
|
||||
dbg("%s(): inotify socket %d invalid.", __func__, w->fd);
|
||||
return;
|
||||
}
|
||||
|
||||
sz = read(w->fd, ev_buf, sizeof(ev_buf) - 1);
|
||||
if (sz <= 0) {
|
||||
err(1, "invalid inotify event");
|
||||
@@ -463,6 +468,11 @@ void cgroup_init(uev_ctx_t *ctx)
|
||||
FILE *fp;
|
||||
int fd;
|
||||
|
||||
#ifndef CGROUP2_ENABLED
|
||||
avail = 0;
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (mount("none", FINIT_CGPATH, "cgroup2", opts, NULL)) {
|
||||
if (errno == ENOENT)
|
||||
logit(LOG_INFO, "Kernel does not support cgroups v2, disabling.");
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* Finit control group support functions
|
||||
*
|
||||
* Copyright (c) 2019-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2019-2024 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 @@
|
||||
/* New client tool, replaces old /dev/initctl API and telinit tool
|
||||
*
|
||||
* Copyright (c) 2019-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2019-2024 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 @@
|
||||
/* Cgroup utility functions for initctl
|
||||
*
|
||||
* Copyright (c) 2019-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2019-2024 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
|
||||
|
||||
+5
-3
@@ -1,6 +1,6 @@
|
||||
/* External client API, using UNIX domain socket.
|
||||
*
|
||||
* Copyright (c) 2015-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2015-2024 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
|
||||
@@ -29,6 +29,8 @@
|
||||
#include "client.h"
|
||||
#include "log.h"
|
||||
|
||||
#define REQUEST_TIMEOUT 15000
|
||||
|
||||
static int sd = -1;
|
||||
|
||||
int client_connect(void)
|
||||
@@ -85,7 +87,7 @@ int client_request(struct init_request *rq, ssize_t len)
|
||||
|
||||
pfd.fd = sd;
|
||||
pfd.events = POLLOUT;
|
||||
if (poll(&pfd, 1, 2000) <= 0) {
|
||||
if (poll(&pfd, 1, REQUEST_TIMEOUT) <= 0) {
|
||||
warn("Timed out waiting for Finit, errno %d", errno);
|
||||
return -1;
|
||||
}
|
||||
@@ -107,7 +109,7 @@ int client_request(struct init_request *rq, ssize_t len)
|
||||
|
||||
pfd.fd = sd;
|
||||
pfd.events = POLLIN | POLLERR | POLLHUP;
|
||||
if ((rc = poll(&pfd, 1, 2000)) <= 0) {
|
||||
if ((rc = poll(&pfd, 1, REQUEST_TIMEOUT)) <= 0) {
|
||||
if (rc) {
|
||||
if (errno == EINTR) /* shutdown/reboot */
|
||||
return -1;
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* External client API, using UNIX domain socket.
|
||||
*
|
||||
* Copyright (c) 2015-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2015-2024 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
|
||||
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
# With the daemon mode ('mdev -df') we no longer need the hotplug helper
|
||||
echo "" > /proc/sys/kernel/hotplug
|
||||
|
||||
# Wait for 'mdev -df' to set up its event queue.
|
||||
sleep 1
|
||||
|
||||
# Trigger 'add' event for all devices and subsystems to load all modules
|
||||
# and any firmware needed by the hardware.
|
||||
find /sys/devices -name uevent -print | while IFS='' read X; do echo add > $X; done
|
||||
+18
-6
@@ -35,6 +35,7 @@
|
||||
#include "cond.h"
|
||||
#include "pid.h"
|
||||
#include "service.h"
|
||||
#include "sm.h"
|
||||
|
||||
struct cond_boot {
|
||||
TAILQ_ENTRY(cond_boot) link;
|
||||
@@ -214,7 +215,10 @@ static int do_delete(const char *fpath, const struct stat *sb, int tflag, struct
|
||||
err(1, "Failed removing condition %s", fpath);
|
||||
|
||||
cond = ptr + strlen(COND_BASE) + 1;
|
||||
cond_update(cond);
|
||||
if (sm_is_in_teardown(&sm))
|
||||
cond_clear_noupdate(cond);
|
||||
else
|
||||
cond_update(cond);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -222,8 +226,16 @@ static int do_delete(const char *fpath, const struct stat *sb, int tflag, struct
|
||||
static void cond_delpath(const char *path)
|
||||
{
|
||||
nftw(path, do_delete, 20, FTW_DEPTH);
|
||||
if (remove(path) && errno != ENOENT)
|
||||
err(1, "Failed removing condition path %s", path);
|
||||
if (remove(path)) {
|
||||
switch (errno) {
|
||||
case ENOENT: /* Ignore */
|
||||
case ENOTEMPTY: /* Only at shutdown and for directories */
|
||||
break;
|
||||
default:
|
||||
err(1, "Failed removing condition path %s", path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int cond_set_path(const char *path, enum cond_state next)
|
||||
@@ -276,7 +288,7 @@ int cond_update(const char *name)
|
||||
svc_t *svc, *iter = NULL;
|
||||
int affects = 0;
|
||||
|
||||
dbg("%s", name);
|
||||
// dbg("%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;
|
||||
@@ -309,7 +321,7 @@ int cond_set_noupdate(const char *name)
|
||||
|
||||
void cond_set(const char *name)
|
||||
{
|
||||
dbg("%s", name);
|
||||
// dbg("%s", name);
|
||||
if (cond_set_noupdate(name))
|
||||
return;
|
||||
|
||||
@@ -360,7 +372,7 @@ int cond_clear_noupdate(const char *name)
|
||||
|
||||
void cond_clear(const char *name)
|
||||
{
|
||||
dbg("%s", name);
|
||||
// dbg("%s", name);
|
||||
if (cond_clear_noupdate(name))
|
||||
return;
|
||||
|
||||
|
||||
+263
-34
@@ -1,6 +1,6 @@
|
||||
/* Parser for /etc/finit.conf and /etc/finit.d/<SVC>.conf
|
||||
*
|
||||
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2024 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
|
||||
@@ -62,8 +62,29 @@ static TAILQ_HEAD(, env_entry) env_list = TAILQ_HEAD_INITIALIZER(env_list);
|
||||
struct rlimit initial_rlimit[RLIMIT_NLIMITS];
|
||||
struct rlimit global_rlimit[RLIMIT_NLIMITS];
|
||||
|
||||
/*
|
||||
* --enable-fastboot => fsck_mode: NULL => no fsck by default
|
||||
* --enable-fsckfix => fsck_mode: "-f" + fsck_repair: "y"
|
||||
*/
|
||||
#ifdef FSCK_FIX
|
||||
# ifdef FAST_BOOT
|
||||
char *fsck_mode = NULL;
|
||||
# else
|
||||
char *fsck_mode = "-f";
|
||||
# endif
|
||||
char *fsck_repair = "-y";
|
||||
#else
|
||||
# ifdef FAST_BOOT
|
||||
char *fsck_mode = NULL;
|
||||
# else
|
||||
char *fsck_mode = "";
|
||||
# endif
|
||||
char *fsck_repair = "-p";
|
||||
#endif
|
||||
|
||||
char *runparts = NULL;
|
||||
int runparts_progress;
|
||||
int runparts_sysv;
|
||||
|
||||
char cgroup_current[16]; /* cgroup.NAME sets current cgroup for a set of services */
|
||||
|
||||
@@ -246,10 +267,12 @@ static void parse_arg(char *arg)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef RESCUE_MODE
|
||||
if (string_compare(arg, "rescue") || string_compare(arg, "recover")) {
|
||||
rescue = 1;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (string_compare(arg, "single") || string_compare(arg, "S")) {
|
||||
single = 1;
|
||||
@@ -325,8 +348,11 @@ static void parse_kernel_loglevel(void)
|
||||
*/
|
||||
void conf_parse_cmdline(int argc, char *argv[])
|
||||
{
|
||||
const char *ptr;
|
||||
|
||||
/* Set up defaults */
|
||||
fstab = strdup(FINIT_FSTAB);
|
||||
if ((ptr = FINIT_FSTAB))
|
||||
fstab = strdup(ptr);
|
||||
finit_conf = strdup(FINIT_CONF);
|
||||
finit_rcsd = strdup(FINIT_RCSD);
|
||||
path = getenv("PATH");
|
||||
@@ -391,6 +417,79 @@ void conf_saverc(void)
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called at bootstrap to log execution order (for debug)
|
||||
*/
|
||||
void conf_save_exec_order(svc_t *svc, char *cmdline, int result)
|
||||
{
|
||||
const char *fn = _PATH_VARRUN "finit/exec.order";
|
||||
const char *ststr = !result ? "[ OK ]" : "[FAIL]";
|
||||
static char *prepared = NULL;
|
||||
int first = !fexist(fn);
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen(fn, "a+");
|
||||
if (!fp) {
|
||||
err(1, "failed writing to %s", fn);
|
||||
return;
|
||||
}
|
||||
|
||||
if (first) {
|
||||
fprintf(fp, "# Execution order of run/task/services at bootstrap\n");
|
||||
fprintf(fp, "# ST TYPE COMMAND LINE (DESC)\n");
|
||||
}
|
||||
|
||||
if (result == -1) {
|
||||
int len;
|
||||
|
||||
len = snprintf(NULL, 0, " %-7s %-64s (%s)", svc_typestr(svc), cmdline, svc->desc);
|
||||
if (len > 0) {
|
||||
if (prepared)
|
||||
free(prepared);
|
||||
prepared = malloc(++len);
|
||||
if (!prepared)
|
||||
goto done;
|
||||
snprintf(prepared, len, " %-7s %-64s (%s)", svc_typestr(svc), cmdline, svc->desc);
|
||||
}
|
||||
} else {
|
||||
if (prepared) {
|
||||
memcpy(prepared, ststr, strlen(ststr));
|
||||
fprintf(fp, "%s\n", prepared);
|
||||
free(prepared);
|
||||
prepared = NULL;
|
||||
} else {
|
||||
fprintf(fp, "%s %-7s %-64s (%s)\n", ststr, svc_typestr(svc), cmdline, svc->desc);
|
||||
}
|
||||
}
|
||||
done:
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called by plugins and similar that dynamically generate system services
|
||||
*/
|
||||
void conf_save_service(int type, char *cfg, char *file)
|
||||
{
|
||||
char fn[256];
|
||||
svc_t foo;
|
||||
FILE *fp;
|
||||
|
||||
mkpath(FINIT_RUNPATH_, 0755);
|
||||
snprintf(fn, sizeof(fn), "%s/%s", FINIT_RUNPATH_, file);
|
||||
if (fexist(fn))
|
||||
warnx("File %s already exists, overwriting.", fn);
|
||||
fp = fopen(fn, "w");
|
||||
if (!fp) {
|
||||
err(1, "Failed creating %s", fn);
|
||||
return;
|
||||
}
|
||||
|
||||
foo.type = type;
|
||||
fprintf(fp, "# Generated by finit:%s()\n", __func__);
|
||||
fprintf(fp, "%s %s\n", svc_typestr(&foo), cfg);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
@@ -449,6 +548,23 @@ static void parse_env(char *line)
|
||||
*end-- = 0;
|
||||
}
|
||||
|
||||
/* strip any leading 'set ' */
|
||||
end = key;
|
||||
if (!strncmp(key, "set", 3))
|
||||
end += 3;
|
||||
|
||||
/* check key, no spaces allowed */
|
||||
while (*end && isspace(*end))
|
||||
end++;
|
||||
key = end;
|
||||
while (*end && !isspace(*end))
|
||||
end++;
|
||||
if (*end != 0) {
|
||||
warnx("'%s=%s': not a valid identifier", key, val);
|
||||
return; /* invalid key */
|
||||
}
|
||||
|
||||
dbg("Global env '%s'='%s'", key, val);
|
||||
setenv(key, val, 1);
|
||||
|
||||
node = malloc(sizeof(*node));
|
||||
@@ -560,11 +676,22 @@ void conf_parse_cond(svc_t *svc, char *cond)
|
||||
return;
|
||||
}
|
||||
|
||||
/* First character must be '!' if SIGHUP is not supported. */
|
||||
/*
|
||||
* First character must be '!' if:
|
||||
* - service: SIGHUP is not supported
|
||||
* - run/task: Do not block bootstrap
|
||||
*/
|
||||
ptr = cond;
|
||||
if (ptr[i] == '!') {
|
||||
svc->sighup = 0;
|
||||
ptr++;
|
||||
|
||||
if (svc_is_runtask(svc)) {
|
||||
/* see service_runtask_clean() */
|
||||
svc->sighup = 1;
|
||||
svc->once = 1;
|
||||
} else {
|
||||
svc->sighup = 0;
|
||||
}
|
||||
}
|
||||
|
||||
while (ptr[i] != '>' && ptr[i] != 0)
|
||||
@@ -776,6 +903,15 @@ static int parse_static(char *line, int is_rcsd)
|
||||
|
||||
if (BOOTSTRAP && MATCH_CMD(line, "runparts ", x)) {
|
||||
if (runparts) free(runparts);
|
||||
runparts_progress = runparts_sysv = 0;
|
||||
while (x) {
|
||||
if (MATCH_CMD(x, "progress", x))
|
||||
runparts_progress = 1;
|
||||
else if (MATCH_CMD(x, "sysv", x))
|
||||
runparts_sysv = 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
runparts = strdup(strip_line(x));
|
||||
return 0;
|
||||
}
|
||||
@@ -842,6 +978,18 @@ static int parse_static(char *line, int is_rcsd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Before Finit 5 the default readiness notification is PID.
|
||||
* This default can be changed by setting 'readiness none' in
|
||||
* the file /etc/finit.conf, only read once at bootstrap.
|
||||
*/
|
||||
if (BOOTSTRAP && MATCH_CMD(line, "readiness ", x)) {
|
||||
char *token = strip_line(x);
|
||||
|
||||
if (!strcmp(token, "none"))
|
||||
readiness = SVC_NOTIFY_NONE;
|
||||
}
|
||||
|
||||
if (MATCH_CMD(line, "reboot-delay ", x)) {
|
||||
syncsec = strtonum(strip_line(x), 0, 60, NULL);
|
||||
return 0;
|
||||
@@ -862,7 +1010,7 @@ static int parse_static(char *line, int is_rcsd)
|
||||
|
||||
service_interval = val * 1000; /* to milliseconds */
|
||||
if (disabled)
|
||||
service_init();
|
||||
service_init(NULL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1083,6 +1231,14 @@ int conf_reload(void)
|
||||
*/
|
||||
memcpy(global_rlimit, initial_rlimit, sizeof(global_rlimit));
|
||||
|
||||
/*
|
||||
* When built with --disable-rescue mode many other 'if (rescue)'
|
||||
* code paths are #ifdeffed out. This one, and the ones in the
|
||||
* plugins, are not because a hook or plugin can still trigger
|
||||
* the alternative rescue.conf instead of finit.conf. This for
|
||||
* very advanced use-cases where files on /etc are generated at
|
||||
* bootstrap, including users and passwords, from other sources.
|
||||
*/
|
||||
if (rescue) {
|
||||
int rc;
|
||||
char line[80] = "tty [12345789] rescue";
|
||||
@@ -1112,22 +1268,53 @@ int conf_reload(void)
|
||||
* but are now regular files that can be overridden by files in
|
||||
* /etc/finit.d -- similar to how tmfiles.d(5) work. E.g., add
|
||||
* an override .conf, or an ignore by symlinking to /dev/null
|
||||
*
|
||||
* The .conf files (and run/task/service stanzas) are parsed and
|
||||
* started in order. Each directory is sorted alphanumerically
|
||||
* and then the result is appended to the overall order:
|
||||
*
|
||||
* /lib/finit/system/10-hotplug.conf
|
||||
* /lib/finit/system/90-testserv.conf
|
||||
* /run/finit/system/dbus.conf
|
||||
* /run/finit/system/tty.conf
|
||||
* /etc/finit.d/10-abc.conf
|
||||
* /etc/finit.d/20-abc.conf
|
||||
* /etc/finit.d/enabled/1-aaa.conf
|
||||
* /etc/finit.d/enabled/1-abc.conf
|
||||
* /etc/finit.d/enabled/2-aaa.conf
|
||||
*/
|
||||
glob_append(&gl, 0, "%s/*.conf", finit_rcsd);
|
||||
glob_append(&gl, 1, "%s/*.conf", FINIT_SYSPATH);
|
||||
glob_append(&gl, 0, "%s/*.conf", FINIT_SYSPATH_);
|
||||
glob_append(&gl, 1, "%s/*.conf", FINIT_RUNPATH_);
|
||||
glob_append(&gl, 1, "%s/*.conf", finit_rcsd);
|
||||
glob_append(&gl, 1, "%s/enabled/*.conf", finit_rcsd);
|
||||
|
||||
if (bootstrap) {
|
||||
const char *fn = _PATH_VARRUN "finit/conf.order";
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen(fn, "w");
|
||||
if (!fp) {
|
||||
err(1, "failed creating %s", fn);
|
||||
} else {
|
||||
fprintf(fp, "# Evaluation & execution order of .conf files\n");
|
||||
for (i = 0; i < gl.gl_pathc; i++)
|
||||
fprintf(fp, "%s\n", gl.gl_pathv[i]);
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < gl.gl_pathc; i++) {
|
||||
char *path = gl.gl_pathv[i];
|
||||
char *rp = NULL;
|
||||
struct stat st;
|
||||
size_t j, len;
|
||||
|
||||
/* check for FINIT_SYSPATH overrides */
|
||||
/* check for FINIT_SYSPATH_ or FINIT_RUNPATH_ overrides */
|
||||
for (j = i + 1; j < gl.gl_pathc; j++) {
|
||||
if (strncmp(path, FINIT_SYSPATH, strlen(FINIT_SYSPATH)))
|
||||
if (strncmp(path, FINIT_SYSPATH_, strlen(FINIT_SYSPATH_)) &&
|
||||
strncmp(path, FINIT_RUNPATH_, strlen(FINIT_RUNPATH_)))
|
||||
continue;
|
||||
if (strcmp(basename(path), basename(gl.gl_pathv[j])))
|
||||
if (strcmp(basenm(path), basenm(gl.gl_pathv[j])))
|
||||
continue;
|
||||
path = NULL; /* replacement later in list, skip this */
|
||||
break;
|
||||
@@ -1185,6 +1372,9 @@ done:
|
||||
/* Drop record of all .conf changes */
|
||||
drop_changes();
|
||||
|
||||
if (bootstrap)
|
||||
wdog = svc_find("watchdog", "finit");
|
||||
|
||||
/* Override configured runlevel, user said 'S' on /proc/cmdline */
|
||||
if (BOOTSTRAP && single)
|
||||
cfglevel = 1;
|
||||
@@ -1235,19 +1425,29 @@ static int conf_change_act(char *dir, char *name, uint32_t mask)
|
||||
struct conf_change *node;
|
||||
char *rp = NULL;
|
||||
|
||||
paste(fn, sizeof(fn), dir, name);
|
||||
/* Check for actual printable characters, sometimes STX */
|
||||
if (name[0] && name[0] >= ' ')
|
||||
paste(fn, sizeof(fn), dir, name);
|
||||
else
|
||||
strlcpy(fn, dir, sizeof(fn));
|
||||
dbg("path: %s mask: %08x", fn, mask);
|
||||
|
||||
/* Handle disabling/removal of service */
|
||||
rp = realpath(fn, NULL);
|
||||
if (!rp) {
|
||||
if (errno != ENOENT)
|
||||
goto fail;
|
||||
if (strchr(name, '@')) {
|
||||
/* Skip realpath for templates */
|
||||
rp = strdup(fn);
|
||||
if (!rp)
|
||||
goto fail;
|
||||
} else {
|
||||
/* Handle disabling/removal of service */
|
||||
rp = realpath(fn, NULL);
|
||||
if (!rp) {
|
||||
if (errno != ENOENT)
|
||||
goto fail;
|
||||
rp = strdup(fn);
|
||||
}
|
||||
}
|
||||
|
||||
if (!rp)
|
||||
goto fail;
|
||||
|
||||
node = conf_find(rp);
|
||||
if (node) {
|
||||
dbg("event already registered for %s ...", name);
|
||||
@@ -1266,7 +1466,7 @@ static int conf_change_act(char *dir, char *name, uint32_t mask)
|
||||
dbg("event registered for %s, mask 0x%x", rp, mask);
|
||||
return 0;
|
||||
fail:
|
||||
warn("failed registering %s event", fn);
|
||||
warn("failed registering %s event mask %08x", fn, mask);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1286,7 +1486,11 @@ int conf_changed(char *file)
|
||||
if (!file)
|
||||
return 0;
|
||||
|
||||
rp = realpath(file, NULL);
|
||||
if (strchr(file, '@'))
|
||||
rp = strdup(file);
|
||||
else
|
||||
rp = realpath(file, NULL);
|
||||
|
||||
if (!rp)
|
||||
return 0;
|
||||
|
||||
@@ -1329,10 +1533,8 @@ static int conf_iwatch_read(int fd)
|
||||
if (!iwp)
|
||||
continue;
|
||||
|
||||
if (conf_change_act(iwp->path, ev->name, ev->mask)) {
|
||||
err(1, " Out of memory");
|
||||
if (conf_change_act(iwp->path, ev->name, ev->mask))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1340,6 +1542,11 @@ static int conf_iwatch_read(int fd)
|
||||
|
||||
static void conf_cb(uev_t *w, void *arg, int events)
|
||||
{
|
||||
if (UEV_ERROR == events) {
|
||||
dbg("%s(): iwatch socket %d invalid.", __func__, w->fd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (conf_iwatch_read(w->fd)) {
|
||||
err(1, "invalid inotify event");
|
||||
return;
|
||||
@@ -1372,25 +1579,26 @@ int conf_monitor(void)
|
||||
* have or not have symlinks in place. We need to monitor for
|
||||
* changes to either symlink or target.
|
||||
*/
|
||||
rc += iwatch_add(&iw_conf, finit_rcsd, IN_ONLYDIR);
|
||||
rc |= iwatch_add(&iw_conf, finit_rcsd, IN_ONLYDIR);
|
||||
snprintf(path, sizeof(path), "%s/available/", finit_rcsd);
|
||||
rc += iwatch_add(&iw_conf, path, IN_ONLYDIR | IN_DONT_FOLLOW);
|
||||
rc |= iwatch_add(&iw_conf, path, IN_ONLYDIR | IN_DONT_FOLLOW);
|
||||
snprintf(path, sizeof(path), "%s/enabled/", finit_rcsd);
|
||||
rc += iwatch_add(&iw_conf, path, IN_ONLYDIR | IN_DONT_FOLLOW);
|
||||
rc += iwatch_add(&iw_conf, finit_conf, 0);
|
||||
rc |= iwatch_add(&iw_conf, path, IN_ONLYDIR | IN_DONT_FOLLOW);
|
||||
rc |= iwatch_add(&iw_conf, finit_conf, 0);
|
||||
|
||||
/*
|
||||
* Systems with /etc/default, /etc/conf.d, or similar, can also
|
||||
* monitor changes in env files sourced by .conf files (above)
|
||||
* define your own with --with-sysconfig=/path/to/envfiles
|
||||
*/
|
||||
rc += iwatch_add(&iw_conf, "/etc/default/", IN_ONLYDIR);
|
||||
rc += iwatch_add(&iw_conf, "/etc/conf.d/", IN_ONLYDIR);
|
||||
rc |= iwatch_add(&iw_conf, "/etc/default/", IN_ONLYDIR);
|
||||
rc |= iwatch_add(&iw_conf, "/etc/conf.d/", IN_ONLYDIR);
|
||||
#ifdef FINIT_SYSCONFIG
|
||||
rc += iwatch_add(&iw_conf, FINIT_SYSCONFIG, IN_ONLYDIR);
|
||||
rc |= iwatch_add(&iw_conf, FINIT_SYSCONFIG, IN_ONLYDIR);
|
||||
#endif
|
||||
rc |= conf_reload();
|
||||
|
||||
return rc + conf_reload();
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1420,15 +1628,16 @@ int conf_init(uev_ctx_t *ctx)
|
||||
*/
|
||||
#ifdef WDT_DEVNODE
|
||||
if (whichp(FINIT_EXECPATH_ "/watchdogd") && fexist(WDT_DEVNODE)) {
|
||||
service_register(SVC_TYPE_SERVICE, "[S0123456789] cgroup.init name:watchdog :finit " FINIT_EXECPATH_ "/watchdogd -- Finit watchdog daemon", global_rlimit, NULL);
|
||||
wdog = svc_find("watchdog", "finit");
|
||||
conf_save_service(SVC_TYPE_SERVICE, "[S0123456789] cgroup.init notify:none name:watchdog :finit "
|
||||
FINIT_EXECPATH_ "/watchdogd -- Finit watchdog daemon", "watchdogd.conf");
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Start kernel event daemon as soon as possible, if enabled
|
||||
*/
|
||||
if (whichp(FINIT_EXECPATH_ "/keventd"))
|
||||
service_register(SVC_TYPE_SERVICE, "[S0123456789] cgroup.init " FINIT_EXECPATH_ "/keventd -- Finit kernel event daemon", global_rlimit, NULL);
|
||||
conf_save_service(SVC_TYPE_SERVICE, "[S12345789] cgroup.init notify:none "
|
||||
FINIT_EXECPATH_ "/keventd -- Finit kernel event daemon", "keventd.conf");
|
||||
|
||||
dbg("Allow plugins to register early runlevel 1 run/task/services ...");
|
||||
plugin_run_hooks(HOOK_SVC_PLUGIN);
|
||||
@@ -1447,6 +1656,26 @@ int conf_init(uev_ctx_t *ctx)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Background startup scripts in the runparts directory, if any.
|
||||
*/
|
||||
if (runparts && fisdir(runparts) && !rescue) {
|
||||
char conf[sizeof(_PATH_RUNPARTS) + strlen(runparts) + 100];
|
||||
char args[10] = { 0 };
|
||||
|
||||
if (debug)
|
||||
strlcat(args, "-d ", sizeof(args));
|
||||
if (runparts_progress)
|
||||
strlcat(args, "-p ", sizeof(args));
|
||||
if (runparts_sysv)
|
||||
strlcat(args, "-s ", sizeof(args));
|
||||
|
||||
snprintf(conf, sizeof(conf), "[S] <int/bootstrap> notify:none log:console %s %s %s"
|
||||
" -- Calling runparts %s in the background",
|
||||
_PATH_RUNPARTS, args, runparts, runparts);
|
||||
conf_save_service(SVC_TYPE_TASK, conf, "runparts.conf");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -1,6 +1,6 @@
|
||||
/* Parser for /etc/finit.conf and /etc/finit.d/<SVC>.conf
|
||||
*
|
||||
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2024 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
|
||||
@@ -44,6 +44,8 @@ int conf_monitor (void);
|
||||
|
||||
void conf_reset_env (void);
|
||||
void conf_saverc (void);
|
||||
void conf_save_exec_order (svc_t *svc, char *cmdline, int result);
|
||||
void conf_save_service (int type, char *cfg, char *file);
|
||||
void conf_parse_cmdline (int argc, char *argv[]);
|
||||
int conf_parse_runlevels (char *runlevels);
|
||||
void conf_parse_cond (svc_t *svc, char *cond);
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
/* Device node monitor for the Finit condition engine
|
||||
*
|
||||
* Copyright (c) 2022-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2022-2024 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
|
||||
@@ -237,13 +237,13 @@ static void devmon_cb(uev_t *w, void *arg, int events)
|
||||
continue;
|
||||
}
|
||||
|
||||
dbg("Got %s", ev->name);
|
||||
// dbg("Got %s", ev->name);
|
||||
if (ev->mask & (IN_CREATE | IN_DELETE))
|
||||
devmon_update_conds(iwp->path, ev->name, ev->mask);
|
||||
}
|
||||
}
|
||||
|
||||
void devmon_init(void)
|
||||
void devmon_init(uev_ctx_t *ctx)
|
||||
{
|
||||
char dir[MAX_ARG_LEN];
|
||||
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
/* Device node monitor for the Finit condition engine
|
||||
*
|
||||
* Copyright (c) 2022-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2022-2024 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,6 +27,6 @@
|
||||
void devmon_add_cond(const char *cond);
|
||||
void devmon_del_cond(const char *cond);
|
||||
|
||||
void devmon_init(void);
|
||||
void devmon_init(uev_ctx_t *ctx);
|
||||
|
||||
#endif /* FINIT_DEVMON_H_ */
|
||||
|
||||
+37
-114
@@ -1,7 +1,7 @@
|
||||
/* Functions for exec'ing processes
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2024 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,6 @@
|
||||
|
||||
#include "config.h" /* Generated by configure script */
|
||||
|
||||
#include <ctype.h> /* isdigit() */
|
||||
#include <dirent.h>
|
||||
#include <err.h>
|
||||
#include <stdarg.h>
|
||||
#include <sysexits.h>
|
||||
@@ -59,11 +57,11 @@ int complete(char *cmd, int pid)
|
||||
|
||||
if (waitpid(pid, &status, 0) == -1) {
|
||||
if (errno == EINTR)
|
||||
errx(1, "Caught unblocked signal waiting for %s, aborting", cmd);
|
||||
warnx("Caught unblocked signal waiting for %s, aborting", cmd);
|
||||
else if (errno == ECHILD)
|
||||
errx(1, "Caught SIGCHLD waiting for %s, aborting", cmd);
|
||||
warnx("Caught SIGCHLD waiting for %s, aborting", cmd);
|
||||
else
|
||||
errx(1, "Failed starting %s, error %d: %s", cmd, errno, strerror (errno));
|
||||
warnx("Failed starting %s, error %d: %s", cmd, errno, strerror(errno));
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -140,31 +138,32 @@ int run(char *cmd, char *log)
|
||||
|
||||
pid = fork();
|
||||
if (0 == pid) {
|
||||
int rc = EX_OSERR;
|
||||
char *pfx, buf[256];
|
||||
FILE *pp;
|
||||
int rc;
|
||||
|
||||
setsid();
|
||||
sig_unblock();
|
||||
if (!log) {
|
||||
do_redirect();
|
||||
execvp(args[0], args);
|
||||
} else {
|
||||
char *pfx = *log ? ": " : "";
|
||||
FILE *pp;
|
||||
|
||||
pp = popen(cmd, "r");
|
||||
if (pp) {
|
||||
char buf[256];
|
||||
|
||||
while (fgets(buf, sizeof(buf), pp)) {
|
||||
chomp(buf);
|
||||
logit(LOG_NOTICE, "%s%s%s", log, pfx, buf);
|
||||
}
|
||||
|
||||
rc = pclose(pp);
|
||||
}
|
||||
_exit(EX_OSERR);
|
||||
}
|
||||
|
||||
_exit(rc);
|
||||
pp = popen(cmd, "r");
|
||||
if (!pp)
|
||||
_exit(EX_OSERR);
|
||||
|
||||
pfx = *log ? ": " : "";
|
||||
while (fgets(buf, sizeof(buf), pp)) {
|
||||
chomp(buf);
|
||||
logit(LOG_NOTICE, "%s%s%s", log, pfx, buf);
|
||||
}
|
||||
|
||||
rc = pclose(pp);
|
||||
if (rc == -1)
|
||||
_exit(EX_OSERR);
|
||||
_exit(WEXITSTATUS(rc));
|
||||
} else if (-1 == pid) {
|
||||
err(1, "%s", !log ? args[0] : cmd);
|
||||
if (backup)
|
||||
@@ -186,7 +185,7 @@ int run(char *cmd, char *log)
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
dbg("Process '%s' terminated by signal %d", cmd, WTERMSIG(status));
|
||||
if (!result)
|
||||
result = 1; /* Must alert callee that the command did complete successfully.
|
||||
result = 1; /* Must alert callee the command did not complete successfully.
|
||||
* This is necessary since not all programs trap signals and
|
||||
* change their return code accordingly. --Jocke */
|
||||
}
|
||||
@@ -200,7 +199,6 @@ int run(char *cmd, char *log)
|
||||
int run_interactive(char *cmd, char *fmt, ...)
|
||||
{
|
||||
int status, oldout = 1, olderr = 2;
|
||||
char line[LINE_SIZE];
|
||||
FILE *fp;
|
||||
|
||||
if (!cmd) {
|
||||
@@ -245,6 +243,7 @@ int run_interactive(char *cmd, char *fmt, ...)
|
||||
|
||||
/* Dump any results of cmd on stderr after we've printed [ OK ] or [FAIL] */
|
||||
if (fp && !debug) {
|
||||
char line[LINE_SIZE];
|
||||
size_t len, written;
|
||||
|
||||
rewind(fp);
|
||||
@@ -272,7 +271,7 @@ int exec_runtask(char *cmd, char *args[])
|
||||
size_t i;
|
||||
|
||||
strlcat(buf, cmd, sizeof(buf));
|
||||
for (i = 1; args[i]; i++) {
|
||||
for (i = 1; args && args[i]; i++) {
|
||||
strlcat(buf, " ", sizeof(buf));
|
||||
strlcat(buf, args[i], sizeof(buf));
|
||||
}
|
||||
@@ -282,7 +281,7 @@ int exec_runtask(char *cmd, char *args[])
|
||||
return execvp(_PATH_BSHELL, argv);
|
||||
}
|
||||
|
||||
static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit rlimit[])
|
||||
static void prepare_tty(char *tty, speed_t speed, const char *procname, struct rlimit rlimit[])
|
||||
{
|
||||
char name[80];
|
||||
int fd, dummy;
|
||||
@@ -352,7 +351,7 @@ static int activate_console(int noclear, int nowait)
|
||||
dprint(STDERR_FILENO, clr, strlen(clr));
|
||||
dprint(STDERR_FILENO, msg, strlen(msg));
|
||||
while ((rc = read(STDIN_FILENO, &ch, 1)) > 0 && ch != '\r' && ch != '\n')
|
||||
continue;
|
||||
;
|
||||
|
||||
/* On any error (likely EINTR), we avoid starting getty */
|
||||
if (rc == -1)
|
||||
@@ -443,96 +442,20 @@ pid_t run_sh(char *tty, int noclear, int nowait, struct rlimit rlimit[])
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void run_env(const char *env[])
|
||||
pid_t run_bg(char *cmd, char *args[])
|
||||
{
|
||||
size_t i = 0;
|
||||
pid_t pid;
|
||||
|
||||
if (!env)
|
||||
return;
|
||||
if (access(cmd, X_OK))
|
||||
return 0;
|
||||
|
||||
while (env[i]) {
|
||||
size_t j = i + 1;
|
||||
print(-1, "Calling %s in the background", cmd);
|
||||
pid = fork();
|
||||
if (!pid)
|
||||
_exit(exec_runtask(cmd, args));
|
||||
print_result(pid == -1);
|
||||
|
||||
if (!env[j])
|
||||
break;
|
||||
|
||||
setenv(env[i], env[j], 1);
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
int run_parts(char *dir, char *cmd, const char *env[], int progress)
|
||||
{
|
||||
struct dirent **e;
|
||||
int i, num;
|
||||
|
||||
num = scandir(dir, &e, NULL, alphasort);
|
||||
if (num < 0) {
|
||||
dbg("No files found in %s, skipping ...", dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
const char *name = e[i]->d_name;
|
||||
char path[strlen(dir) + strlen(name) + 2];
|
||||
struct stat st;
|
||||
char *argv[4] = {
|
||||
"sh",
|
||||
"-c",
|
||||
path,
|
||||
NULL
|
||||
};
|
||||
pid_t pid = 0;
|
||||
int status;
|
||||
|
||||
paste(path, sizeof(path), dir, name);
|
||||
if (stat(path, &st)) {
|
||||
dbg("Failed stat(%s): %s", path, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!S_ISEXEC(st.st_mode) || S_ISDIR(st.st_mode)) {
|
||||
if (strcmp(name, ".") && strcmp(name, ".."))
|
||||
dbg("Skipping %s ...", path);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If the callee didn't supply a run_parts() argument */
|
||||
if (!cmd) {
|
||||
/* Check if S<NUM>service or K<NUM>service notation is used */
|
||||
// dbg("Checking if %s is a sysvinit startstop script ...", name);
|
||||
if (name[0] == 'S' && isdigit(name[1]))
|
||||
strlcat(path, " start", sizeof(path));
|
||||
else if (name[0] == 'K' && isdigit(name[1]))
|
||||
strlcat(path, " stop", sizeof(path));
|
||||
} else {
|
||||
strlcat(path, cmd, sizeof(path));
|
||||
}
|
||||
|
||||
if (progress)
|
||||
print_desc("Calling ", path);
|
||||
pid = fork();
|
||||
if (!pid) {
|
||||
sig_unblock();
|
||||
run_env(env);
|
||||
|
||||
return execvp(_PATH_BSHELL, argv);
|
||||
}
|
||||
|
||||
status = complete(path, pid);
|
||||
if (WIFEXITED(status))
|
||||
warnx("%s exited with status %d", path, WEXITSTATUS(status));
|
||||
else if (WIFSIGNALED(status))
|
||||
warnx("%s terminated by signad %d", path, WTERMSIG(status));
|
||||
if (progress)
|
||||
print_result(WEXITSTATUS(status));
|
||||
}
|
||||
|
||||
while (num--)
|
||||
free(e[num]);
|
||||
free(e);
|
||||
|
||||
return 0;
|
||||
return pid;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+50
-145
@@ -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-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2024 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
|
||||
@@ -58,7 +58,6 @@
|
||||
#include "tty.h"
|
||||
#include "util.h"
|
||||
#include "utmp-api.h"
|
||||
#include "schedule.h"
|
||||
|
||||
int runlevel = INIT_LEVEL; /* Bootstrap 'S' */
|
||||
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
|
||||
@@ -70,13 +69,13 @@ 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 */
|
||||
int syncsec = 0; /* reboot delay */
|
||||
int readiness = SVC_NOTIFY_PID;
|
||||
char *finit_conf= NULL;
|
||||
char *finit_rcsd= NULL;
|
||||
char *fstab = NULL;
|
||||
char *sdown = NULL;
|
||||
char *network = NULL;
|
||||
char *hostname = NULL;
|
||||
char *runparts = NULL;
|
||||
char *osheading = NULL;
|
||||
|
||||
uev_ctx_t *ctx = NULL; /* Main loop context */
|
||||
@@ -88,14 +87,22 @@ svc_t *wdog = NULL; /* No watchdog by default */
|
||||
*/
|
||||
static void banner(void)
|
||||
{
|
||||
#ifndef KERNEL_LOGGING
|
||||
/*
|
||||
* Silence kernel logs, assuming users have sysklogd or
|
||||
* similar enabled to start emptying /dev/kmsg, but for
|
||||
* our progress we want to own the console.
|
||||
* similar enabled to start emptying /dev/kmsg.
|
||||
*
|
||||
* Instead of using `configure --disable-kernel-logging`, we
|
||||
* recommend adjusting the kernel log level in the kernel's
|
||||
* menuconfig, or using sysctl kernel.printk, or setting the
|
||||
* desired log level, on the kernel cmdline, e.g. 'quiet'.
|
||||
*
|
||||
* By default KERNEL_LOGGING is enabled so you can see any
|
||||
* warnings/errors or higher on your system console.
|
||||
*/
|
||||
if (!debug && !kerndebug)
|
||||
klogctl(6, NULL, 0);
|
||||
|
||||
#endif
|
||||
/*
|
||||
* First level hooks, if you want to run here, you're
|
||||
* pretty much on your own. Nothing's up yet ...
|
||||
@@ -206,7 +213,7 @@ static int fsck(int pass)
|
||||
|
||||
fp = setmntent(fstab, "r");
|
||||
if (!fp) {
|
||||
err(1, "Failed opening fstab: %s", fstab);
|
||||
logit(LOG_CONSOLE | LOG_ALERT, "Failed opening fstab: %s", fstab);
|
||||
sulogin(1);
|
||||
}
|
||||
dbg("Opened %s, pass %d", fstab, pass);
|
||||
@@ -256,11 +263,7 @@ static int fsck(int pass)
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef FSCK_FIX
|
||||
snprintf(cmd, sizeof(cmd), "fsck -yf %s", dev);
|
||||
#else
|
||||
snprintf(cmd, sizeof(cmd), "fsck %s %s %s", fsck_mode, fsck_repair, dev);
|
||||
#endif
|
||||
dbg("Running pass %d fsck command %s", pass, cmd);
|
||||
fsck_rc = run_interactive(cmd, "Checking filesystem %s", dev);
|
||||
/*
|
||||
@@ -269,10 +272,15 @@ static int fsck(int pass)
|
||||
* 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);
|
||||
if (hasmntopt(mnt,"nofail")) {
|
||||
logit(LOG_CONSOLE | LOG_WARNING, "Ignoring failed fsck %s because of nofail option", dev);
|
||||
fsck_rc = 0;
|
||||
} else {
|
||||
logit(LOG_CONSOLE | LOG_ALERT, "Failed fsck %s, attempting sulogin ...", dev);
|
||||
sulogin(1);
|
||||
}
|
||||
}
|
||||
rc += fsck_rc;
|
||||
rc |= fsck_rc;
|
||||
}
|
||||
|
||||
endmntent(fp);
|
||||
@@ -283,7 +291,6 @@ static int fsck(int pass)
|
||||
static int fsck_all(void)
|
||||
{
|
||||
int rc = 0;
|
||||
#ifndef FAST_BOOT
|
||||
int pass;
|
||||
|
||||
if (!fsck_mode)
|
||||
@@ -294,7 +301,7 @@ static int fsck_all(void)
|
||||
if (rc)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -361,6 +368,8 @@ static void fs_remount_root(int fsckerr)
|
||||
*/
|
||||
static void fs_finalize(void)
|
||||
{
|
||||
int flags = MS_NOEXEC | MS_NOSUID;
|
||||
|
||||
/*
|
||||
* Some systems rely on us to both create /dev/shm and, to mount
|
||||
* a tmpfs there. Any system with dbus needs shared memory, so
|
||||
@@ -368,8 +377,8 @@ static void fs_finalize(void)
|
||||
* the /etc/fstab file already.
|
||||
*/
|
||||
if (!fismnt("/dev/shm")) {
|
||||
makedir("/dev/shm", 0777);
|
||||
fs_mount("shm", "/dev/shm", "tmpfs", 0, "mode=0777");
|
||||
makedir("/dev/shm", 1777);
|
||||
fs_mount("shm", "/dev/shm", "tmpfs", flags | MS_NODEV, "mode=1777");
|
||||
}
|
||||
|
||||
/* Modern systems use /dev/pts */
|
||||
@@ -387,7 +396,13 @@ static void fs_finalize(void)
|
||||
snprintf(opts, sizeof(opts), "gid=%d,mode=%d,ptmxmode=0666", gid, mode);
|
||||
|
||||
makedir("/dev/pts", 0755);
|
||||
fs_mount("devpts", "/dev/pts", "devpts", MS_NOSUID | MS_NOEXEC, opts);
|
||||
fs_mount("devpts", "/dev/pts", "devpts", flags, opts);
|
||||
}
|
||||
|
||||
/* Needed on systems like Alpine Linux */
|
||||
if (!fismnt("/dev/mqueue")) {
|
||||
makedir("/dev/mqueue", 1777);
|
||||
fs_mount("mqueue", "/dev/mqueue", "tmpfs", flags | MS_NODEV, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -399,7 +414,7 @@ static void fs_finalize(void)
|
||||
* To override any of this behavior, add entries to /etc/fstab
|
||||
* for /run (and optionally /run/lock).
|
||||
*/
|
||||
if (fisdir("/run") && !fismnt("/run")) {
|
||||
if (fisdir("/run") && !fismnt("/run") && !fistmpfs("/run")) {
|
||||
fs_mount("tmpfs", "/run", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME, "mode=0755,size=10%");
|
||||
|
||||
/* This prevents user DoS of /run by filling /run/lock at the expense of another tmpfs, max 5MiB */
|
||||
@@ -408,7 +423,7 @@ static void fs_finalize(void)
|
||||
}
|
||||
|
||||
/* Modern systems use tmpfs for /tmp */
|
||||
if (!fismnt("/tmp"))
|
||||
if (!fismnt("/tmp") && !fistmpfs("/tmp"))
|
||||
fs_mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_NODEV, "mode=1777");
|
||||
}
|
||||
|
||||
@@ -521,113 +536,6 @@ static void fs_init(void)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Handle bootstrap transition to configured runlevel, start TTYs
|
||||
*
|
||||
* This is the final stage of bootstrap. It changes to the default
|
||||
* (configured) runlevel, calls all external start scripts and final
|
||||
* bootstrap hooks before bringing up TTYs.
|
||||
*
|
||||
* We must ensure that all declared `task [S]` and `run [S]` jobs in
|
||||
* finit.conf, or *.conf in finit.d/, run to completion before we
|
||||
* finalize the bootstrap process by calling this function.
|
||||
*/
|
||||
static void finalize(void *unused)
|
||||
{
|
||||
/* Clean up bootstrap-only tasks/services that never started */
|
||||
dbg("Clean up all bootstrap-only tasks/services ...");
|
||||
svc_prune_bootstrap();
|
||||
|
||||
/* All services/tasks/etc. in configure runlevel have started */
|
||||
dbg("Running svc up hooks ...");
|
||||
plugin_run_hooks(HOOK_SVC_UP);
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
|
||||
/* Convenient SysV compat for when you just don't care ... */
|
||||
if (!access(FINIT_RC_LOCAL, X_OK) && !rescue)
|
||||
run_interactive(FINIT_RC_LOCAL, "Calling %s", FINIT_RC_LOCAL);
|
||||
|
||||
/* Hooks that should run at the very end */
|
||||
dbg("Calling all system up hooks ...");
|
||||
plugin_run_hooks(HOOK_SYSTEM_UP);
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
|
||||
/* Disable progress output at normal runtime */
|
||||
enable_progress(0);
|
||||
|
||||
/* System bootrapped, launch TTYs et al */
|
||||
bootstrap = 0;
|
||||
service_step_all(SVC_TYPE_RESPAWN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Start cranking the big state machine
|
||||
*/
|
||||
static void crank_worker(void *unused)
|
||||
{
|
||||
/*
|
||||
* Initialize state machine and start all bootstrap tasks
|
||||
* NOTE: no network available!
|
||||
*/
|
||||
sm_init(&sm);
|
||||
sm_step(&sm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for system bootstrap to complete, all SVC_TYPE_RUNTASK must be
|
||||
* allowed to complete their work in [S], or timeout, before we switch
|
||||
* to the configured runlevel and call finalize(), should not take more
|
||||
* than 120 sec.
|
||||
*/
|
||||
static void bootstrap_worker(void *work)
|
||||
{
|
||||
static struct wq final = {
|
||||
.cb = finalize,
|
||||
.delay = 10
|
||||
};
|
||||
static int cnt = 120 * 10; /* We run with 100ms period */
|
||||
int level = cfglevel;
|
||||
|
||||
dbg("Step all services ...");
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
|
||||
if (cnt-- > 0 && !service_completed()) {
|
||||
dbg("Not all bootstrap run/tasks have completed yet ... %d", cnt);
|
||||
schedule_work(work);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cnt > 0)
|
||||
dbg("All run/task have completed, resuming bootstrap.");
|
||||
else
|
||||
dbg("Timeout, resuming bootstrap.");
|
||||
|
||||
dbg("Starting runlevel change finalize ...");
|
||||
schedule_work(&final);
|
||||
|
||||
/*
|
||||
* Run startup scripts in the runparts directory, if any.
|
||||
*/
|
||||
if (runparts && fisdir(runparts) && !rescue)
|
||||
run_parts(runparts, NULL, NULL, 1);
|
||||
|
||||
|
||||
dbg("Flushing pending .conf file events ...");
|
||||
conf_flush_events();
|
||||
|
||||
/*
|
||||
* Start all tasks/services in the configured runlevel, or jump
|
||||
* into the runlevel selected from the command line.
|
||||
*/
|
||||
if (cmdlevel) {
|
||||
dbg("Runlevel %d requested from command line, starting all services ...", cmdlevel);
|
||||
level = cmdlevel;
|
||||
} else
|
||||
dbg("Change to default runlevel(%d), starting all services ...", cfglevel);
|
||||
|
||||
service_runlevel(level);
|
||||
}
|
||||
|
||||
static int version(int rc)
|
||||
{
|
||||
puts(PACKAGE_STRING);
|
||||
@@ -658,7 +566,7 @@ static int usage(int rc)
|
||||
" 2-9 Change runlevel\n"
|
||||
" q, Q Reload /etc/finit.conf and/or any *.conf in /etc/finit.d/\n"
|
||||
" if modified, same as initctl reload or SIGHUP to PID 1\n"
|
||||
" 1, s, S Enter system rescue mode, runlevel 1\n"
|
||||
" 1, s, S Enter single user mode, no networking, runlevel 1\n"
|
||||
"\n", prognm);
|
||||
|
||||
return rc;
|
||||
@@ -708,14 +616,6 @@ static int telinit(int argc, char *argv[])
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct wq crank_work = {
|
||||
.cb = crank_worker,
|
||||
.delay = 10
|
||||
};
|
||||
struct wq bootstrap_work = {
|
||||
.cb = bootstrap_worker,
|
||||
.delay = 100
|
||||
};
|
||||
uev_ctx_t loop;
|
||||
|
||||
/* user calling telinit or init */
|
||||
@@ -765,8 +665,10 @@ int main(int argc, char *argv[])
|
||||
/*
|
||||
* In case of emergency.
|
||||
*/
|
||||
#ifdef RESCUE_MODE
|
||||
if (rescue)
|
||||
rescue = sulogin(0);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Load plugins early, the first hook is in banner(), so we
|
||||
@@ -815,11 +717,15 @@ int main(int argc, char *argv[])
|
||||
cond_set_oneshot(plugin_hook_str(HOOK_BANNER));
|
||||
cond_set_oneshot(plugin_hook_str(HOOK_ROOTFS_UP));
|
||||
|
||||
/* Some bootstrap tasks may need to know if we're in a container. */
|
||||
if (in_container())
|
||||
cond_set_oneshot("int/container");
|
||||
|
||||
/*
|
||||
* Initialize .conf system and load static /etc/finit.conf then
|
||||
* tell the world what we used.
|
||||
*/
|
||||
devmon_init();
|
||||
devmon_init(&loop);
|
||||
conf_init(&loop);
|
||||
conf_saverc();
|
||||
|
||||
@@ -832,16 +738,15 @@ int main(int argc, char *argv[])
|
||||
dbg("Starting initctl API responder ...");
|
||||
api_init(&loop);
|
||||
|
||||
dbg("Starting the big state machine ...");
|
||||
schedule_work(&crank_work);
|
||||
|
||||
dbg("Starting bootstrap finalize timer ...");
|
||||
schedule_work(&bootstrap_work);
|
||||
dbg("Starting service interval monitor ...");
|
||||
service_init(&loop);
|
||||
|
||||
/*
|
||||
* Background service tasks
|
||||
* Initialize state machine and start all bootstrap tasks
|
||||
* NOTE: no network available!
|
||||
*/
|
||||
service_init();
|
||||
sm_init(&sm);
|
||||
sm_step(&sm);
|
||||
|
||||
/*
|
||||
* Enter main loop to monitor /dev/initctl and services
|
||||
|
||||
+4
-2
@@ -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-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2024 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
|
||||
@@ -56,10 +56,11 @@
|
||||
|
||||
/* To use these, include config.h, or define FINIT_EXECPATH_ */
|
||||
#define _PATH_LOGIT FINIT_EXECPATH_ "/logit"
|
||||
#define _PATH_RUNPARTS FINIT_EXECPATH_ "/runparts"
|
||||
#define _PATH_SULOGIN FINIT_EXECPATH_ "/sulogin"
|
||||
#define _PATH_GETTY FINIT_EXECPATH_ "/getty"
|
||||
|
||||
#define CMD_SIZE 256
|
||||
#define CMD_SIZE 1024
|
||||
#define LINE_SIZE 1024
|
||||
#define BUF_SIZE 4096
|
||||
|
||||
@@ -120,6 +121,7 @@ extern int single;
|
||||
extern int bootstrap;
|
||||
extern int kerndebug;
|
||||
extern int syncsec;
|
||||
extern int readiness;
|
||||
extern char *fstab;
|
||||
extern char *sdown;
|
||||
extern char *network;
|
||||
|
||||
+5
-2
@@ -1,6 +1,6 @@
|
||||
/* Initialize and serve a login terminal
|
||||
*
|
||||
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2016-2024 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
|
||||
@@ -121,6 +121,9 @@ static int osrel(struct osrel *rel)
|
||||
snprintf(rel->version, sizeof(rel->version), "(%s)", codename);
|
||||
}
|
||||
|
||||
if (rel->id[0] && !strcmp(rel->id, "alpine"))
|
||||
return 1; /* compat mode for \r et al. */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -369,7 +372,7 @@ restart:
|
||||
|
||||
static int usage(int rc)
|
||||
{
|
||||
warnx("usage: getty [-h?] tty [speed [term]]");
|
||||
warnx("usage: getty [-h?p] tty [speed [term]]");
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
+16
-11
@@ -1,7 +1,7 @@
|
||||
/* Misc. utility functions for finit and its plugins
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2024 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
|
||||
@@ -87,6 +87,9 @@ void console_init(void)
|
||||
/* Enable line wrap, if disabled previously, e.g., qemu */
|
||||
dprint(STDOUT_FILENO, "\033[?7h", 5);
|
||||
|
||||
/* Reset atttributes, background and foreground color */
|
||||
dprint(STDOUT_FILENO, "\033[49m\033[39m\e[2J", 14);
|
||||
|
||||
log_init();
|
||||
}
|
||||
|
||||
@@ -522,9 +525,10 @@ void networking(int updown)
|
||||
|
||||
pid = fork();
|
||||
if (pid == 0) {
|
||||
int rc = EX_OSERR;
|
||||
const char *cmd;
|
||||
char buf[256];
|
||||
FILE *pp;
|
||||
int rc;
|
||||
|
||||
setsid();
|
||||
sig_unblock();
|
||||
@@ -539,16 +543,16 @@ void networking(int updown)
|
||||
cmd = "ifdown -a -f 2>&1";
|
||||
|
||||
pp = popen(cmd, "r");
|
||||
if (pp) {
|
||||
char buf[256];
|
||||
if (!pp)
|
||||
_exit(EX_OSERR);
|
||||
|
||||
while (fgets(buf, sizeof(buf), pp))
|
||||
logit(LOG_NOTICE, "network: %s", chomp(buf));
|
||||
while (fgets(buf, sizeof(buf), pp))
|
||||
logit(LOG_NOTICE, "network: %s", chomp(buf));
|
||||
|
||||
rc = pclose(pp);
|
||||
}
|
||||
|
||||
_exit(rc);
|
||||
rc = pclose(pp);
|
||||
if (rc == -1)
|
||||
_exit(EX_OSERR);
|
||||
_exit(WEXITSTATUS(rc));
|
||||
}
|
||||
cgroup_service("network", pid, NULL);
|
||||
print(pid > 0 ? 0 : 1, "%s network interfaces ...",
|
||||
@@ -581,7 +585,8 @@ int in_container(void)
|
||||
"lxc",
|
||||
"docker",
|
||||
"kubepod",
|
||||
"unshare"
|
||||
"unshare",
|
||||
"systemd-nspawn"
|
||||
};
|
||||
const char *files[] = {
|
||||
"/run/.containerenv",
|
||||
|
||||
+5
-3
@@ -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-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2024 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
|
||||
@@ -88,7 +88,8 @@ int run_interactive (char *cmd, char *fmt, ...) __attribute__ ((format (prin
|
||||
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[]);
|
||||
int run_parts (char *dir, char *cmd, const char *env[], int progress);
|
||||
pid_t run_bg (char *cmd, char *args[]);
|
||||
int run_parts (char *dir, char *cmd, const char *env[], int progress, int sysv);
|
||||
|
||||
/*
|
||||
* Defaults to user "root" and group "wheel" (root) if:
|
||||
@@ -140,6 +141,7 @@ static inline int ln(const char *target, const char *linkpath)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int dprint(int fd, const char *s, size_t len)
|
||||
{
|
||||
size_t loop = 3;
|
||||
@@ -158,7 +160,7 @@ static inline int dprint(int fd, const char *s, size_t len)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline char *fgetval(char *line, const char *key, char *sep)
|
||||
static inline char *fgetval(const char *line, const char *key, char *sep)
|
||||
{
|
||||
char *ptr, *str, *copy;
|
||||
size_t len;
|
||||
|
||||
+11
-4
@@ -1,6 +1,6 @@
|
||||
/* New client tool, replaces old /dev/initctl API and telinit tool
|
||||
*
|
||||
* Copyright (c) 2015-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2015-2024 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
|
||||
@@ -209,19 +209,26 @@ static int do_runlevel(char *arg)
|
||||
if (!arg) {
|
||||
int prevlevel = 0;
|
||||
int currlevel;
|
||||
char prev;
|
||||
char prev, curr;
|
||||
|
||||
currlevel = runlevel_get(&prevlevel);
|
||||
if (255 == currlevel) {
|
||||
switch (currlevel) {
|
||||
case 255:
|
||||
printf("unknown\n");
|
||||
return 0;
|
||||
case INIT_LEVEL:
|
||||
curr = 'S';
|
||||
break;
|
||||
default:
|
||||
curr = currlevel + '0';
|
||||
break;
|
||||
}
|
||||
|
||||
prev = prevlevel + '0';
|
||||
if (prev <= '0' || prev > '9')
|
||||
prev = 'N';
|
||||
|
||||
printf("%c %d\n", prev , currlevel);
|
||||
printf("%c %c\n", prev , curr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* New client tool, replaces old /dev/initctl API and telinit tool
|
||||
*
|
||||
* Copyright (c) 2015-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2015-2024 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
-1
@@ -1,7 +1,7 @@
|
||||
/* inotify watcher for files or directories
|
||||
*
|
||||
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
|
||||
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2016-2024 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
|
||||
@@ -96,6 +96,12 @@ int iwatch_add1(struct iwatch *iw, char *file, uint32_t mask)
|
||||
if (!initialized)
|
||||
return -1;
|
||||
|
||||
iwp = iwatch_find_by_path(iw, file);
|
||||
if (iwp) {
|
||||
dbg("skipping, %s already registered", file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!fexist(file)) {
|
||||
dbg("skipping %s: no such file or directory", file);
|
||||
return 0;
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/* inotify watcher for files or directories
|
||||
*
|
||||
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
|
||||
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2016-2024 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 @@
|
||||
/* Listens to kernel events like AC power status and manages sys/ conditions
|
||||
*
|
||||
* Copyright (c) 2021-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2021-2024 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,6 +1,6 @@
|
||||
/* Finit daemon log functions
|
||||
*
|
||||
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2024 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,8 +42,6 @@ static int loglevel = LOG_INFO;
|
||||
|
||||
void log_init(void)
|
||||
{
|
||||
ttinit();
|
||||
|
||||
if (debug)
|
||||
loglevel = LOG_DEBUG;
|
||||
else
|
||||
@@ -53,13 +51,6 @@ void log_init(void)
|
||||
/* If we enabled terse mode at boot, restore to previous setting at shutdown */
|
||||
void log_exit(void)
|
||||
{
|
||||
/*
|
||||
* Unless in debug mode at shutdown, Reinitialize screen,
|
||||
* terminal may have been resized at runtime
|
||||
*/
|
||||
if (!debug)
|
||||
ttinit();
|
||||
|
||||
enable_progress(1);
|
||||
}
|
||||
|
||||
@@ -148,7 +139,7 @@ void logit(int prio, const char *fmt, ...)
|
||||
goto done;
|
||||
}
|
||||
|
||||
fprintf(fp, "<%d>finit[1]:", LOG_DAEMON | prio);
|
||||
fprintf(fp, "<%d>finit[1]: ", LOG_DAEMON | prio);
|
||||
vfprintf(fp, fmt, ap);
|
||||
fclose(fp);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Finit daemon log functions
|
||||
*
|
||||
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2024 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
|
||||
@@ -47,6 +47,7 @@ static __attribute__ ((format (printf, 1, 2))) inline void dbg(char *fmt, ...)
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fputs("\n", stderr);
|
||||
va_end(ap);
|
||||
}
|
||||
#define info(fmt, args...) warnx(fmt, ##args)
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2018-2024 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,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2018-2024 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
|
||||
|
||||
+8
-6
@@ -1,6 +1,6 @@
|
||||
/* Handle MD arrays
|
||||
*
|
||||
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2016-2024 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,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "helpers.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
static glob_t *get_arrays(void)
|
||||
@@ -48,17 +49,18 @@ static glob_t *get_arrays(void)
|
||||
*/
|
||||
void mdadm_wait(void)
|
||||
{
|
||||
size_t i;
|
||||
glob_t *gl;
|
||||
char cmd[160];
|
||||
|
||||
/* Setup kernel specific settings, e.g. allow broadcast ping, etc. */
|
||||
gl = get_arrays();
|
||||
if (gl) {
|
||||
for (i = 0; i < gl->gl_pathc; i++) {
|
||||
char *array;
|
||||
size_t i;
|
||||
|
||||
array = basename(gl->gl_pathv[i]);
|
||||
for (i = 0; i < gl->gl_pathc; i++) {
|
||||
const char *array;
|
||||
char cmd[160];
|
||||
|
||||
array = basenm(gl->gl_pathv[i]);
|
||||
snprintf(cmd, sizeof(cmd), "mdadm --wait-clean /dev/%s >/dev/null", array);
|
||||
run_interactive(cmd, "Marking MD array %s as clean", array);
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* Mount and unmount helpers
|
||||
*
|
||||
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2016-2024 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,7 +1,7 @@
|
||||
/* PID and PID file helpers
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2024 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,7 +1,7 @@
|
||||
/* PID and PID file helpers
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2024 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
|
||||
|
||||
+15
-11
@@ -1,6 +1,6 @@
|
||||
/* Plugin based services architecture for finit
|
||||
*
|
||||
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2024 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,6 +43,7 @@
|
||||
#include "private.h"
|
||||
#include "service.h"
|
||||
#include "sig.h"
|
||||
#include "util.h"
|
||||
|
||||
#define is_io_plugin(p) ((p)->io.cb && (p)->io.fd > 0)
|
||||
#define SEARCH_PLUGIN(str) \
|
||||
@@ -77,23 +78,26 @@ static char *trim_ext(char *name)
|
||||
|
||||
int plugin_register(plugin_t *plugin)
|
||||
{
|
||||
const char *nm;
|
||||
|
||||
if (!plugin) {
|
||||
errno = EINVAL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Setup default name if none is provided */
|
||||
if (!plugin->name) {
|
||||
nm = plugin->name;
|
||||
if (!nm) {
|
||||
#ifndef ENABLE_STATIC
|
||||
Dl_info info;
|
||||
|
||||
if (dladdr(plugin, &info) && info.dli_fname)
|
||||
plugin->name = basename(info.dli_fname);
|
||||
nm = basenm(info.dli_fname);
|
||||
#endif
|
||||
if (!plugin->name)
|
||||
plugin->name = "unknown";
|
||||
if (!nm)
|
||||
nm = "unknown";
|
||||
}
|
||||
plugin->name = trim_ext(strdup(plugin->name));
|
||||
plugin->name = trim_ext(strdup(nm));
|
||||
|
||||
/* Already registered? */
|
||||
if (plugin_find(plugin->name)) {
|
||||
@@ -230,7 +234,7 @@ void plugin_script_run(hook_point_t no)
|
||||
} else
|
||||
env[2] = NULL;
|
||||
|
||||
run_parts(path, NULL, env, 0);
|
||||
run_parts(path, NULL, env, 0, 0);
|
||||
}
|
||||
#else
|
||||
void plugin_script_run(hook_point_t no)
|
||||
@@ -253,7 +257,7 @@ void plugin_run_hook(hook_point_t no, void *arg)
|
||||
|
||||
PLUGIN_ITERATOR(p, tmp) {
|
||||
if (p->hook[no].cb) {
|
||||
dbg("Calling %s hook n:o %d (arg: %p) ...", basename(p->name), no, arg ?: "NIL");
|
||||
dbg("Calling %s hook n:o %d (arg: %p) ...", basenm(p->name), no, arg ?: "NIL");
|
||||
p->hook[no].cb(arg ? arg : p->hook[no].arg);
|
||||
}
|
||||
}
|
||||
@@ -288,7 +292,7 @@ static void generic_io_cb(uev_t *w, void *arg, int events)
|
||||
/* Stop watcher, callback may close descriptor on us ... */
|
||||
uev_io_stop(w);
|
||||
|
||||
dbg("Calling I/O %s from runloop...", basename(p->name));
|
||||
// dbg("Calling I/O %s from runloop...", basename(p->name));
|
||||
p->io.cb(p->io.arg, w->fd, events);
|
||||
|
||||
/* Update fd, may be changed by plugin callback, e.g., if FIFO */
|
||||
@@ -301,9 +305,9 @@ int plugin_io_init(plugin_t *p)
|
||||
if (!is_io_plugin(p))
|
||||
return 0;
|
||||
|
||||
dbg("Initializing plugin %s for I/O", basename(p->name));
|
||||
dbg("Initializing plugin %s for I/O", basenm(p->name));
|
||||
if (uev_io_init(ctx, &p->watcher, generic_io_cb, p, p->io.fd, p->io.flags)) {
|
||||
warn("Failed setting up I/O plugin %s", basename(p->name));
|
||||
warn("Failed setting up I/O plugin %s", basenm(p->name));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* Plugin based services architecture for finit
|
||||
*
|
||||
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2012-2024 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,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-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2024 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 @@
|
||||
/* reboot, halt, poweroff, shutdown, suspend for finit
|
||||
*
|
||||
* Copyright (c) 2009-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2009-2024 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
|
||||
|
||||
+242
@@ -0,0 +1,242 @@
|
||||
#include <ctype.h> /* isdigit() */
|
||||
#include <dirent.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <paths.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/conio.h>
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/conio.h>
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
#include "sig.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef __FINIT__
|
||||
#include "helpers.h"
|
||||
#else
|
||||
#include <sys/prctl.h>
|
||||
|
||||
const char *active_msg = NULL;
|
||||
int interactive = 1;
|
||||
int debug;
|
||||
|
||||
static void print_desc(const char *prefix, const char *msg)
|
||||
{
|
||||
if (interactive)
|
||||
fprintf(stderr, "\e[1m[\e[0m\e[1;33m ⋯ \e[0m\e[1m]\e[0m %s %s", prefix, msg);
|
||||
else
|
||||
fprintf(stderr, "%s %s ...\n", prefix, msg);
|
||||
active_msg = msg;
|
||||
}
|
||||
static void print_result(int rc)
|
||||
{
|
||||
if (interactive) {
|
||||
if (rc)
|
||||
fputs("\r\e[1m[\e[0m\e[1;31mFAIL\e[0m\e[1m]\e[0m\n", stderr);
|
||||
else
|
||||
fputs("\r\e[1m[\e[0m\e[1;32m OK \e[0m\e[1m]\e[0m\n", stderr);
|
||||
} else
|
||||
fprintf(stderr, "[%s] %s\n", rc ? "FAIL" : " OK ", active_msg ?: "");
|
||||
}
|
||||
|
||||
void sig_unblock(void)
|
||||
{
|
||||
struct sigaction sa;
|
||||
sigset_t nmask;
|
||||
int i;
|
||||
|
||||
sigemptyset(&nmask);
|
||||
sigaddset(&nmask, SIGHUP);
|
||||
sigaddset(&nmask, SIGCHLD);
|
||||
sigaddset(&nmask, SIGINT);
|
||||
sigaddset(&nmask, SIGPWR);
|
||||
sigaddset(&nmask, SIGSTOP);
|
||||
sigaddset(&nmask, SIGTSTP);
|
||||
sigaddset(&nmask, SIGCONT);
|
||||
sigaddset(&nmask, SIGTERM);
|
||||
sigaddset(&nmask, SIGUSR1);
|
||||
sigaddset(&nmask, SIGUSR2);
|
||||
sigprocmask(SIG_UNBLOCK, &nmask, NULL);
|
||||
|
||||
/* Reset signal handlers that were set by the parent process */
|
||||
for (i = 1; i < NSIG; i++)
|
||||
DFLSIG(sa, i, 0);
|
||||
}
|
||||
#endif /* __FINIT__ */
|
||||
|
||||
static void run_env(const char *env[])
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
if (!env)
|
||||
return;
|
||||
|
||||
while (env[i]) {
|
||||
size_t j = i + 1;
|
||||
|
||||
if (!env[j])
|
||||
break;
|
||||
|
||||
setenv(env[i], env[j], 1);
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
int run_parts(char *dir, char *cmd, const char *env[], int progress, int sysv)
|
||||
{
|
||||
size_t cmdlen = cmd ? strlen(cmd) : strlen("start");
|
||||
struct dirent **d;
|
||||
int i, num;
|
||||
int rc = 0;
|
||||
|
||||
num = scandir(dir, &d, NULL, alphasort);
|
||||
if (num < 0) {
|
||||
dbg("No files found in %s, skipping ...", dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
char path[strlen(dir) + strlen(d[i]->d_name) + 3 + cmdlen];
|
||||
const char *name = d[i]->d_name;
|
||||
char *argv[4] = {
|
||||
"sh",
|
||||
"-c",
|
||||
path,
|
||||
NULL
|
||||
};
|
||||
struct stat st;
|
||||
int result = 0;
|
||||
pid_t pid = 0;
|
||||
int status;
|
||||
|
||||
/* skip backup files */
|
||||
if (name[strlen(name) - 1] == '~')
|
||||
continue;
|
||||
|
||||
/* cannot rely on d_type, not supported on all filesystems */
|
||||
paste(path, sizeof(path), dir, name);
|
||||
if (stat(path, &st)) {
|
||||
warn("failed stat(%s)", path);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* skip non-executable files and directories */
|
||||
if (!S_ISEXEC(st.st_mode) || S_ISDIR(st.st_mode)) {
|
||||
dbg("skipping %s not an executable or is a directory", path);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sysv && name[0] != 'S' && name[0] != 'K') {
|
||||
dbg("S-only flag set, skipping non-SysV script: %s", name);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If the callee didn't supply a run_parts() argument */
|
||||
if (!cmd) {
|
||||
/* Check if S<NUM>service or K<NUM>service notation is used */
|
||||
if (name[0] == 'S' && isdigit(name[1]))
|
||||
strlcat(path, " start", sizeof(path));
|
||||
else if (name[0] == 'K' && isdigit(name[1]))
|
||||
strlcat(path, " stop", sizeof(path));
|
||||
} else {
|
||||
strlcat(path, " ", sizeof(path));
|
||||
strlcat(path, cmd, sizeof(path));
|
||||
}
|
||||
|
||||
if (progress)
|
||||
print_desc("Calling", path);
|
||||
|
||||
pid = fork();
|
||||
if (!pid) {
|
||||
sig_unblock();
|
||||
run_env(env);
|
||||
|
||||
_exit(execvp(_PATH_BSHELL, argv));
|
||||
}
|
||||
|
||||
if (waitpid(pid, &status, 0) == -1) {
|
||||
warnx("failed starting %s, error %d: %s", path, errno, strerror(errno));
|
||||
result = 1;
|
||||
} else {
|
||||
if (WIFEXITED(status)) {
|
||||
result = WEXITSTATUS(status);
|
||||
dbg("%s exited with status %d", path, result);
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
warnx("%s terminated by signal %d", path, WTERMSIG(status));
|
||||
result = 1;
|
||||
} else
|
||||
result = 1;
|
||||
}
|
||||
|
||||
if (progress)
|
||||
print_result(result);
|
||||
rc += result;
|
||||
}
|
||||
|
||||
while (num--)
|
||||
free(d[num]);
|
||||
free(d);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifndef __FINIT__
|
||||
static int usage(int rc)
|
||||
{
|
||||
warnx("usage: runparts [-dhps?] DIRECTORY");
|
||||
return rc;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int rc, c, progress = 0, sysv = 0;
|
||||
char *dir;
|
||||
|
||||
while ((c = getopt(argc, argv, "bdh?ps")) != EOF) {
|
||||
switch(c) {
|
||||
case 'b': /* batch mode */
|
||||
interactive = 0;
|
||||
break;
|
||||
case 'd':
|
||||
debug = 1;
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
return usage(0);
|
||||
case 'p':
|
||||
progress = 1;
|
||||
break;
|
||||
case 's':
|
||||
sysv = 1;
|
||||
break;
|
||||
default:
|
||||
return usage(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind >= argc)
|
||||
return usage(1);
|
||||
|
||||
dir = argv[optind];
|
||||
if (!fisdir(dir))
|
||||
return usage(1);
|
||||
|
||||
prctl(PR_SET_CHILD_SUBREAPER, 1);
|
||||
|
||||
rc = run_parts(dir, NULL, NULL, progress, sysv);
|
||||
if (rc == -1)
|
||||
err(1, "failed run-parts %s", dir);
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif /* __FINIT__ */
|
||||
+3
-1
@@ -1,6 +1,6 @@
|
||||
/* Work queue helper functions
|
||||
*
|
||||
* Copyright (c) 2018-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2018-2024 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 "config.h"
|
||||
#include "finit.h"
|
||||
#include "log.h"
|
||||
#include "schedule.h"
|
||||
|
||||
#define SC_INIT 0x494E4954 /* "INIT", see ascii(7) */
|
||||
@@ -35,6 +36,7 @@ static void cb(uev_t *w, void *arg, int events)
|
||||
struct wq *work = (struct wq *)arg;
|
||||
|
||||
if (UEV_ERROR == events) {
|
||||
dbg("%s(): spurious problem with schedule work timer, restarting.", __func__);
|
||||
uev_timer_start(w);
|
||||
return;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* Work queue helper functions
|
||||
*
|
||||
* Copyright (c) 2018-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2018-2024 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
|
||||
|
||||
+61
-28
@@ -1,6 +1,6 @@
|
||||
/* List and enable/disable service configurations
|
||||
*
|
||||
* Copyright (c) 2017-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2017-2024 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,6 +41,10 @@ static int is_builtin(char *arg)
|
||||
{
|
||||
svc_t *svc;
|
||||
|
||||
/* skip check, we may be in non-responsive bootstrap */
|
||||
if (iforce)
|
||||
return 0;
|
||||
|
||||
svc = client_svc_find(arg);
|
||||
if (!svc)
|
||||
return 0;
|
||||
@@ -218,20 +222,13 @@ int serv_list(char *arg)
|
||||
* If the resulting file doesn't exist, and creat is not set, *or*
|
||||
* the base directory doesn't exist, we return NULL.
|
||||
.*/
|
||||
static char *conf(char *path, size_t len, char *name, int creat)
|
||||
static char *conf(char *path, size_t len, char *name, int creat, int template)
|
||||
{
|
||||
char corr[40];
|
||||
|
||||
if (!name || !name[0] || !strcmp(name, "finit") || !strcmp(name, "finit.conf")) {
|
||||
strlcpy(path, finit_conf, len);
|
||||
return path;
|
||||
}
|
||||
|
||||
if (!strstr(name, ".conf")) {
|
||||
snprintf(corr, sizeof(corr), "%s.conf", name);
|
||||
name = corr;
|
||||
}
|
||||
|
||||
if (!fisdir(finit_rcsd))
|
||||
return NULL;
|
||||
|
||||
@@ -239,14 +236,25 @@ static char *conf(char *path, size_t len, char *name, int creat)
|
||||
if (!fisdir(path)) {
|
||||
if (creat && mkdir(path, 0755) && errno != EEXIST)
|
||||
return NULL;
|
||||
else
|
||||
paste(path, len, finit_rcsd, name);
|
||||
paste(path, len, finit_rcsd, name);
|
||||
} else
|
||||
strlcat(path, name, len);
|
||||
|
||||
if (suffix(path, len, ".conf"))
|
||||
return NULL;
|
||||
|
||||
/* fall back to static service unless edit/create */
|
||||
if (!creat && !fexist(path))
|
||||
paste(path, len, finit_rcsd, name);
|
||||
if (!creat && !fexist(path)) {
|
||||
char *at = strchr(path, '@');
|
||||
|
||||
if (template && at)
|
||||
*++at = 0;
|
||||
else
|
||||
paste(path, len, finit_rcsd, name);
|
||||
|
||||
if (suffix(path, len, ".conf"))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
@@ -262,6 +270,11 @@ int serv_enable(char *arg)
|
||||
return serv_list("available");
|
||||
}
|
||||
|
||||
if (arg[0] == '/') {
|
||||
WARNX("absolute paths not supported, this command manages %s/available/", finit_rcsd);
|
||||
return serv_list("available");
|
||||
}
|
||||
|
||||
len = strlen(arg);
|
||||
serv = alloca(len + 6);
|
||||
if (!serv)
|
||||
@@ -322,14 +335,19 @@ int do_disable(char *arg, int check)
|
||||
return serv_list("enabled");
|
||||
}
|
||||
|
||||
len = strlen(arg);
|
||||
serv = alloca(len + 6);
|
||||
if (arg[0] == '/') {
|
||||
WARNX("absolute paths not supported, this command manages %s/enabled/", finit_rcsd);
|
||||
return serv_list("available");
|
||||
}
|
||||
|
||||
len = strlen(arg) + 7;
|
||||
serv = alloca(len);
|
||||
if (!serv)
|
||||
ERR(71, "failed allocating stack");
|
||||
|
||||
strlcpy(serv, arg, len + 6);
|
||||
if (len < 6 || strcmp(&serv[len - 5], ".conf"))
|
||||
strlcat(serv, ".conf", len + 6);
|
||||
strlcpy(serv, arg, len);
|
||||
if (suffix(serv, len, ".conf"))
|
||||
ERR(71, "failed composing service name (%s)", serv);
|
||||
|
||||
if (chdir(finit_rcsd))
|
||||
ERR(72, "failed cd %s", finit_rcsd);
|
||||
@@ -360,20 +378,30 @@ int serv_touch(char *arg)
|
||||
return serv_list("enabled");
|
||||
}
|
||||
|
||||
fn = conf(path, sizeof(path), arg, 0);
|
||||
/* 1. Try /etc/finit.d/enabled/$arg.conf to handle template@.conf */
|
||||
paste(path, sizeof(path), finit_rcsd, "enabled/");
|
||||
strlcat(path, arg, sizeof(path));
|
||||
if (!suffix(path, sizeof(path), ".conf") && fexist(path)) {
|
||||
fn = path;
|
||||
goto touchit;
|
||||
}
|
||||
|
||||
/* 2. Try /etc/finit.d/available/$arg.conf and other combos (legacy) */
|
||||
fn = conf(path, sizeof(path), arg, 0, 0);
|
||||
if (!fexist(fn)) {
|
||||
if (!strstr(arg, "finit.conf"))
|
||||
ERRX(72, "%s not available.", arg);
|
||||
ERRX(noerr ? 0 : 72, "%s not available.", arg);
|
||||
if (is_builtin(arg))
|
||||
ERRX(4, "%s is a built-in service.", arg);
|
||||
ERRX(noerr ? 0 : 4, "%s is a built-in service.", arg);
|
||||
|
||||
strlcpy(path, finit_conf, sizeof(path));
|
||||
fn = path;
|
||||
}
|
||||
|
||||
touchit:
|
||||
/* libite:touch() follows symlinks */
|
||||
if (utimensat(AT_FDCWD, fn, NULL, AT_SYMLINK_NOFOLLOW))
|
||||
ERR(71, "failed marking %s for reload", fn);
|
||||
ERR(noerr ? 0 : 71, "failed marking %s for reload", fn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -383,13 +411,18 @@ int serv_show(char *arg)
|
||||
char path[256];
|
||||
char *fn;
|
||||
|
||||
fn = conf(path, sizeof(path), arg, 0);
|
||||
fn = conf(path, sizeof(path), arg, 0, 0);
|
||||
if (!fexist(fn)) {
|
||||
if (is_builtin(arg))
|
||||
ERRX(4, "%s is a built-in service.", arg);
|
||||
|
||||
WARNX("Cannot find %s", arg);
|
||||
return 1;
|
||||
fn = conf(path, sizeof(path), arg, 0, 1);
|
||||
if (!fn || !fexist(fn)) {
|
||||
WARNX("Cannot find %s", arg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return systemf("cat %s | sed 's/%%i/system/g'", fn);
|
||||
}
|
||||
|
||||
return systemf("cat %s", fn);
|
||||
@@ -420,7 +453,7 @@ static int do_edit(char *arg, int creat)
|
||||
char path[256];
|
||||
char *fn;
|
||||
|
||||
fn = conf(path, sizeof(path), arg, creat);
|
||||
fn = conf(path, sizeof(path), arg, creat, 0);
|
||||
if (!fexist(fn)) {
|
||||
if (is_builtin(arg))
|
||||
ERRX(4, "%s is a built-in service.", arg);
|
||||
@@ -474,7 +507,7 @@ int serv_creat(char *arg)
|
||||
return do_edit(arg, 1);
|
||||
|
||||
/* Open fn for writing from pipe */
|
||||
fn = conf(buf, sizeof(buf), arg, 1);
|
||||
fn = conf(buf, sizeof(buf), arg, 1, 0);
|
||||
if (!fn)
|
||||
ERR(73, "failed creating conf %s", arg);
|
||||
|
||||
@@ -503,7 +536,7 @@ int serv_delete(char *arg)
|
||||
return serv_list("available");
|
||||
}
|
||||
|
||||
fn = conf(buf, sizeof(buf), arg, 0);
|
||||
fn = conf(buf, sizeof(buf), arg, 0, 0);
|
||||
if (!fn) {
|
||||
if (is_builtin(arg))
|
||||
ERRX(4, "%s is a built-in service.", arg);
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* List and enable/disable service configurations
|
||||
*
|
||||
* Copyright (c) 2017-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2017-2024 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
|
||||
|
||||
+458
-180
File diff suppressed because it is too large
Load Diff
+4
-4
@@ -1,7 +1,7 @@
|
||||
/* Finit service monitor, task starter and generic API for managing svc_t
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2024 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,17 +42,17 @@ int service_timeout_after (svc_t *svc, int timeout, void (*cb)(svc_t *svc
|
||||
int service_timeout_cancel (svc_t *svc);
|
||||
|
||||
void service_forked (svc_t *svc);
|
||||
void service_ready (svc_t *svc);
|
||||
void service_ready (svc_t *svc, int ready);
|
||||
|
||||
int service_stop (svc_t *svc);
|
||||
int service_step (svc_t *svc);
|
||||
void service_step_all (int types);
|
||||
void service_worker (void *unused);
|
||||
|
||||
int service_completed (void);
|
||||
int service_completed (svc_t **svc);
|
||||
void service_notify_reconf (void);
|
||||
|
||||
void service_init (void);
|
||||
void service_init (uev_ctx_t *ctx);
|
||||
|
||||
#endif /* FINIT_SERVICE_H_ */
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Signal management - Be conservative with what finit responds to!
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2024 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
|
||||
@@ -232,6 +232,8 @@ void do_iterate_proc(int (*cb)(int, void *), void *data)
|
||||
dbg("Skipping %s ...", file);
|
||||
else if (file[0] == '@')
|
||||
dbg("Skipping %s ...", &file[1]);
|
||||
else if (strstr(file, "initctl"))
|
||||
dbg("Skipping %s ...", file);
|
||||
else
|
||||
if (cb(pid, data)) {
|
||||
dbg("PID %d is still alive (%s)", pid, file);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Signal management - Be conservative with what finit responds to!
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2024 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
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "conf.h"
|
||||
#include "helpers.h"
|
||||
#include "private.h"
|
||||
#include "schedule.h"
|
||||
#include "service.h"
|
||||
#include "sig.h"
|
||||
#include "tty.h"
|
||||
@@ -43,12 +44,61 @@ sm_t sm;
|
||||
#define FINIT_NOLOGIN_PATH _PATH_NOLOGIN /* Stop user logging in. */
|
||||
#endif
|
||||
|
||||
void sm_init(sm_t *sm)
|
||||
/*
|
||||
* Wait for system bootstrap to complete, all SVC_TYPE_RUNTASK must be
|
||||
* allowed to complete their work in [S], or timeout, before we switch
|
||||
* to the configured runlevel and call finalize(), should not take more
|
||||
* than 120 sec.
|
||||
*/
|
||||
static void sm_check_bootstrap(void *work)
|
||||
{
|
||||
sm->state = SM_BOOTSTRAP_STATE;
|
||||
sm->newlevel = -1;
|
||||
sm->reload = 0;
|
||||
sm->in_teardown = 0;
|
||||
static int timeout = 120;
|
||||
int bootstrap_done;
|
||||
int level = cfglevel;
|
||||
svc_t *svc = NULL;
|
||||
|
||||
dbg("Step all services ...");
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
|
||||
bootstrap_done = service_completed(&svc);
|
||||
if (timeout-- > 0 && !bootstrap_done) {
|
||||
dbg("Not all bootstrap run/tasks have completed yet ... %d", timeout);
|
||||
schedule_work(work);
|
||||
return;
|
||||
}
|
||||
|
||||
if (timeout > 0) {
|
||||
dbg("All run/task have completed, resuming bootstrap.");
|
||||
} else {
|
||||
dbg("Timeout, resuming bootstrap.");
|
||||
if (svc)
|
||||
print(2, "Timeout waiting for %s to run, resuming bootstrap", svc_ident(svc, NULL, 0));
|
||||
else
|
||||
print(2, "Timeout waiting for unknown run/task, resuming bootstrap");
|
||||
}
|
||||
|
||||
dbg("Flushing pending .conf file events ...");
|
||||
conf_flush_events();
|
||||
|
||||
/*
|
||||
* Start all tasks/services in the configured runlevel, or jump
|
||||
* into the runlevel selected from the command line.
|
||||
*/
|
||||
if (cmdlevel) {
|
||||
dbg("Runlevel %d requested from command line, starting all services ...", cmdlevel);
|
||||
level = cmdlevel;
|
||||
} else
|
||||
dbg("Change to default runlevel(%d), starting all services ...", cfglevel);
|
||||
|
||||
service_runlevel(level);
|
||||
|
||||
/* Clean up bootstrap-only tasks/services that never started */
|
||||
dbg("Clean up all bootstrap-only tasks/services ...");
|
||||
svc_prune_bootstrap();
|
||||
|
||||
/* All services/tasks/etc. in configure runlevel have started */
|
||||
dbg("Running svc up hooks ...");
|
||||
plugin_run_hooks(HOOK_SVC_UP);
|
||||
}
|
||||
|
||||
static char *sm_status(sm_state_t state)
|
||||
@@ -57,6 +107,9 @@ static char *sm_status(sm_state_t state)
|
||||
case SM_BOOTSTRAP_STATE:
|
||||
return "bootstrap";
|
||||
|
||||
case SM_BOOTSTRAP_WAIT_STATE:
|
||||
return "bootstrap/wait";
|
||||
|
||||
case SM_RUNNING_STATE:
|
||||
return "running";
|
||||
|
||||
@@ -66,15 +119,20 @@ static char *sm_status(sm_state_t state)
|
||||
case SM_RUNLEVEL_WAIT_STATE:
|
||||
return "runlevel/wait";
|
||||
|
||||
case SM_RUNLEVEL_CLEAN_STATE:
|
||||
return "runlevel/clean";
|
||||
|
||||
case SM_RELOAD_CHANGE_STATE:
|
||||
return "reload/change";
|
||||
|
||||
case SM_RELOAD_WAIT_STATE:
|
||||
return "reload/wait";
|
||||
|
||||
default:
|
||||
return "unknown";
|
||||
case SM_RELOAD_CLEAN_STATE:
|
||||
return "reload/clean";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
static char sm_runlevel(int lvl)
|
||||
@@ -100,14 +158,36 @@ static void nologin(void)
|
||||
erase(FINIT_NOLOGIN_PATH);
|
||||
}
|
||||
|
||||
void sm_init(sm_t *sm)
|
||||
{
|
||||
static struct wq work = {
|
||||
.cb = sm_check_bootstrap,
|
||||
.delay = 1000
|
||||
};
|
||||
|
||||
sm->state = SM_BOOTSTRAP_STATE;
|
||||
sm->newlevel = -1;
|
||||
sm->reload = 0;
|
||||
sm->in_teardown = 0;
|
||||
|
||||
dbg("Starting bootstrap finalize timer ...");
|
||||
schedule_work(&work);
|
||||
}
|
||||
|
||||
void sm_set_runlevel(sm_t *sm, int newlevel)
|
||||
{
|
||||
sm->newlevel = newlevel;
|
||||
|
||||
dbg("Flushing pending .conf file events ...");
|
||||
conf_flush_events();
|
||||
}
|
||||
|
||||
void sm_set_reload(sm_t *sm)
|
||||
{
|
||||
sm->reload = 1;
|
||||
|
||||
dbg("Flushing pending .conf file events ...");
|
||||
conf_flush_events();
|
||||
}
|
||||
|
||||
int sm_is_in_teardown(sm_t *sm)
|
||||
@@ -117,8 +197,8 @@ int sm_is_in_teardown(sm_t *sm)
|
||||
|
||||
void sm_step(sm_t *sm)
|
||||
{
|
||||
svc_t *svc;
|
||||
sm_state_t old_state;
|
||||
svc_t *svc;
|
||||
|
||||
restart:
|
||||
old_state = sm->state;
|
||||
@@ -129,11 +209,50 @@ restart:
|
||||
switch (sm->state) {
|
||||
case SM_BOOTSTRAP_STATE:
|
||||
dbg("Bootstrapping all services in runlevel S from %s", finit_conf);
|
||||
service_step_all(SVC_TYPE_RUNTASK | SVC_TYPE_SERVICE);
|
||||
service_step_all(SVC_TYPE_RUNTASK | SVC_TYPE_SERVICE | SVC_TYPE_SYSV);
|
||||
|
||||
sm->state = SM_BOOTSTRAP_WAIT_STATE;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Handle bootstrap transition to configured runlevel, start TTYs
|
||||
*
|
||||
* This is the final stage of bootstrap. It changes to the default
|
||||
* (configured) runlevel, calls all external start scripts and final
|
||||
* bootstrap hooks before bringing up TTYs.
|
||||
*
|
||||
* We must ensure that all declared `task [S]` and `run [S]` jobs in
|
||||
* finit.conf, or *.conf in finit.d/, run to completion before we
|
||||
* finalize the bootstrap process by calling this function.
|
||||
*/
|
||||
case SM_BOOTSTRAP_WAIT_STATE:
|
||||
/* We come here from bootstrap, runlevel change and conf reload */
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
|
||||
/* Allow runparts to start */
|
||||
cond_set_oneshot("int/bootstrap");
|
||||
|
||||
if (sm->newlevel == -1)
|
||||
break;
|
||||
|
||||
/* Hooks that should run at the very end */
|
||||
dbg("Calling all system up hooks ...");
|
||||
plugin_run_hooks(HOOK_SYSTEM_UP);
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
|
||||
/* Disable progress output at normal runtime */
|
||||
enable_progress(0);
|
||||
|
||||
/* System bootrapped, launch TTYs et al */
|
||||
bootstrap = 0;
|
||||
service_step_all(SVC_TYPE_RESPAWN);
|
||||
sm->state = SM_RUNNING_STATE;
|
||||
break;
|
||||
|
||||
case SM_RUNNING_STATE:
|
||||
/* We come here from bootstrap, runlevel change and conf reload */
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
|
||||
/* runlevel changed? */
|
||||
if (sm->newlevel >= 0 && sm->newlevel <= 9) {
|
||||
if (runlevel == sm->newlevel) {
|
||||
@@ -143,6 +262,7 @@ restart:
|
||||
sm->state = SM_RUNLEVEL_CHANGE_STATE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* reload ? */
|
||||
if (sm->reload) {
|
||||
sm->reload = 0;
|
||||
@@ -207,20 +327,39 @@ restart:
|
||||
sm->in_teardown = 0;
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
|
||||
sm->state = SM_RUNLEVEL_CLEAN_STATE;
|
||||
break;
|
||||
|
||||
case SM_RUNLEVEL_CLEAN_STATE:
|
||||
/*
|
||||
* Wait for post:script or cleanup:script to be collected,
|
||||
* which moves the svc to HALTED or DEAD state. We will
|
||||
* be called by the service_monitor() on collect.
|
||||
*/
|
||||
svc = svc_clean_completed();
|
||||
if (svc) {
|
||||
dbg("Waiting to collect post/cleanup script for %s, cmd %s(%d) ...",
|
||||
svc_ident(svc, NULL, 0), svc->cmd, svc->pid);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Cleanup stale services */
|
||||
svc_clean_dynamic(service_unregister);
|
||||
|
||||
#ifdef FINIT_RC_LOCAL
|
||||
/* Compat SysV init */
|
||||
if (prevlevel == INIT_LEVEL && !rescue)
|
||||
run_bg(FINIT_RC_LOCAL, NULL);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* "I've seen things you people wouldn't believe. Attack ships on fire off
|
||||
* the shoulder of Orion. I watched C-beams glitter in the dark near the
|
||||
* Tannhäuser Gate. All those .. moments .. will be lost in time, like
|
||||
* tears ... in ... rain."
|
||||
*/
|
||||
if (runlevel == 0 || runlevel == 6) {
|
||||
if (runlevel == 0 || runlevel == 6)
|
||||
do_shutdown(halt);
|
||||
sm->state = SM_RUNNING_STATE;
|
||||
break;
|
||||
}
|
||||
|
||||
sm->state = SM_RUNNING_STATE;
|
||||
break;
|
||||
@@ -257,6 +396,22 @@ restart:
|
||||
dbg("Starting services after reconf ...");
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
|
||||
sm->state = SM_RELOAD_CLEAN_STATE;
|
||||
break;
|
||||
|
||||
case SM_RELOAD_CLEAN_STATE:
|
||||
/*
|
||||
* Wait for post:script or cleanup:script to be collected,
|
||||
* which moves the svc to HALTED or DEAD state. We will
|
||||
* be called by the service_monitor() on collect.
|
||||
*/
|
||||
svc = svc_clean_completed();
|
||||
if (svc) {
|
||||
dbg("Waiting to collect post/cleanup script for %s, cmd %s(%d) ...",
|
||||
svc_ident(svc, NULL, 0), svc->cmd, svc->pid);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Cleanup stale services */
|
||||
svc_clean_dynamic(service_unregister);
|
||||
|
||||
@@ -266,9 +421,7 @@ restart:
|
||||
dbg("Update configuration generation of unmodified non-native services ...");
|
||||
service_notify_reconf();
|
||||
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
dbg("Reconfiguration done");
|
||||
|
||||
sm->state = SM_RUNNING_STATE;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -26,11 +26,14 @@
|
||||
|
||||
typedef enum {
|
||||
SM_BOOTSTRAP_STATE = 0, /* Init state, bootstrap services */
|
||||
SM_BOOTSTRAP_WAIT_STATE, /* Waiting for bootstrap to complete */
|
||||
SM_RUNNING_STATE, /* Normal state, services running */
|
||||
SM_RUNLEVEL_CHANGE_STATE, /* A runlevel change has occurred */
|
||||
SM_RUNLEVEL_WAIT_STATE, /* Waiting for all stopped runlevel processes to be halted */
|
||||
SM_RUNLEVEL_WAIT_STATE, /* Waiting for all stopped processes to halt */
|
||||
SM_RUNLEVEL_CLEAN_STATE, /* Wait for post:scripts and cleanup:scripts */
|
||||
SM_RELOAD_CHANGE_STATE, /* A reload event has occurred */
|
||||
SM_RELOAD_WAIT_STATE, /* Waiting for all stopped reload processes to be halted */
|
||||
SM_RELOAD_WAIT_STATE, /* Waiting for all stopped processes to halt */
|
||||
SM_RELOAD_CLEAN_STATE, /* Wait for post:scripts and cleanup:scripts */
|
||||
} sm_state_t;
|
||||
|
||||
typedef struct sm {
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* Reset terminal line settings (stty sane)
|
||||
*
|
||||
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2016-2024 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
|
||||
|
||||
+10
-4
@@ -1,6 +1,6 @@
|
||||
/* poor man's sulogin, may be statically linked
|
||||
*
|
||||
* Copyright (c) 2021-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2021-2024 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"
|
||||
|
||||
#include <crypt.h>
|
||||
#include <err.h>
|
||||
#include <paths.h>
|
||||
@@ -32,6 +34,10 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#ifndef SULOGIN_USER
|
||||
#define SULOGIN_USER "root"
|
||||
#endif
|
||||
|
||||
/* getpwnam() cannot be used when statically linked */
|
||||
static int get_passwd(struct passwd *pw)
|
||||
{
|
||||
@@ -44,13 +50,13 @@ static int get_passwd(struct passwd *pw)
|
||||
return 1;
|
||||
|
||||
while ((tmp = fgets(buf, sizeof(buf), fp))) {
|
||||
if (!strstr(buf, ":0:0:"))
|
||||
continue; /* not uid 0 */
|
||||
|
||||
ptr = strsep(&tmp, ":");
|
||||
if (!ptr)
|
||||
break;
|
||||
|
||||
pw->pw_name = strdup(ptr);
|
||||
if (!pw->pw_name || strcmp(pw->pw_name, SULOGIN_USER))
|
||||
continue;
|
||||
|
||||
ptr = strsep(&tmp, ":");
|
||||
if (!ptr)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Low-level service primitives and generic API for managing svc_t structures
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2024 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
|
||||
@@ -348,6 +348,43 @@ svc_t *svc_stop_completed(void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* svc_clean_completed - Have post: and cleanup: scripts finished?
|
||||
*
|
||||
* Called late in runlevel and reload transitions to check if all post: and
|
||||
* cleanup:scripts have completed. A removed service should end up in the
|
||||
* DEAD state, while a service with a post:script ends up in HALTED.
|
||||
*
|
||||
* Returns:
|
||||
* %NULL if post: and cleanup: scripts have run, otherwise a pointer to
|
||||
* the first found svc_t waiting for post: or cleanup:script.
|
||||
*/
|
||||
svc_t *svc_clean_completed(void)
|
||||
{
|
||||
svc_t *svc, *iter = NULL;
|
||||
|
||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||
if (svc_enabled(svc))
|
||||
continue;
|
||||
|
||||
if (svc_is_runtask(svc) && svc->state == SVC_DONE_STATE)
|
||||
continue;
|
||||
|
||||
if (svc_is_removed(svc)) {
|
||||
if (svc->state == SVC_DEAD_STATE)
|
||||
continue; /* any cleanup:script done */
|
||||
} else {
|
||||
if (svc->state == SVC_HALTED_STATE)
|
||||
continue; /* any post:script done */
|
||||
}
|
||||
|
||||
return svc;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* svc_find - Find a service object by its full path name
|
||||
* @name: Full path name, e.g., /sbin/syslogd
|
||||
@@ -580,7 +617,7 @@ void svc_clean_dynamic(void (*cb)(svc_t *))
|
||||
svc_t *svc, *iter = NULL;
|
||||
|
||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||
if (svc->removed && cb)
|
||||
if (svc_is_removed(svc) && cb)
|
||||
cb(svc);
|
||||
}
|
||||
}
|
||||
@@ -634,17 +671,30 @@ int svc_enabled(svc_t *svc)
|
||||
if (!svc)
|
||||
return 0;
|
||||
|
||||
if (!svc_in_runlevel(svc, runlevel))
|
||||
if (!svc_in_runlevel(svc, runlevel)) {
|
||||
// dbg("Not in runlevel");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (svc_is_removed(svc) || svc_is_blocked(svc))
|
||||
if (svc_is_removed(svc) || svc_is_blocked(svc)) {
|
||||
// dbg("removed (%d) / blocked (%d)", svc->removed, svc->block);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (svc_is_missing(svc))
|
||||
if (svc_is_missing(svc)) {
|
||||
// dbg("missing");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (svc_is_tty(svc) && bootstrap)
|
||||
if (!svc_ifthen(0, NULL, svc->ifstmt, svc->nowarn)) {
|
||||
// dbg("ifthen:%s>", svc->ifstmt[0] ? svc->ifstmt : "<");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (svc_is_tty(svc) && bootstrap) {
|
||||
// dbg("is tty in bootstrap");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -688,14 +738,17 @@ int svc_conflicts(svc_t *svc)
|
||||
|
||||
/**
|
||||
* svc_ifthen - Check if: statement in declaration
|
||||
* @is_conf: Set when called by service_mark_unavail()
|
||||
* @ident: svc_t identififcation (name:id)
|
||||
* @stmt: if: statement from .conf file
|
||||
* @quiet: If non-zero, do not warn in syslog
|
||||
*
|
||||
* Returns:
|
||||
* %TRUE(1) yes, use this svc_t, %FALSE(0) prune
|
||||
*/
|
||||
int svc_ifthen(const char *ident, char *stmt)
|
||||
int svc_ifthen(int is_conf, const char *ident, char *stmt, int quiet)
|
||||
{
|
||||
char stmts[MAX_IDENT_LEN];
|
||||
int not = 0;
|
||||
svc_t *svc;
|
||||
|
||||
@@ -707,40 +760,51 @@ int svc_ifthen(const char *ident, char *stmt)
|
||||
char *ptr = ++stmt;
|
||||
int i = 0;
|
||||
|
||||
if (stmt[0] == '!') {
|
||||
stmt++;
|
||||
not++;
|
||||
}
|
||||
if (is_conf)
|
||||
return 1;
|
||||
|
||||
while (ptr[i] != '>' && ptr[i] != 0)
|
||||
i++;
|
||||
ptr[i] = 0;
|
||||
|
||||
cond = cond_get(stmt);
|
||||
if (not && cond == COND_ON) {
|
||||
logit(LOG_NOTICE, "skipping %s, cond %s is on.", ident, stmt);
|
||||
return 0;
|
||||
}
|
||||
if (!not && cond == COND_OFF) {
|
||||
logit(LOG_NOTICE, "skipping %s, cond %s is off.", ident, stmt);
|
||||
return 0;
|
||||
strlcpy(stmts, stmt, sizeof(stmts));
|
||||
for (stmt = strtok(stmts, ","); stmt; stmt = strtok(NULL, ","), not = 0) {
|
||||
if (stmt[0] == '!') {
|
||||
stmt++;
|
||||
not++;
|
||||
}
|
||||
|
||||
cond = cond_get(stmt);
|
||||
if (not && cond == COND_ON)
|
||||
return 0;
|
||||
if (!not && cond == COND_OFF)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (stmt[0] == '!') {
|
||||
stmt++;
|
||||
not++;
|
||||
}
|
||||
if (!is_conf)
|
||||
return 1;
|
||||
|
||||
svc = svc_find_by_str(stmt);
|
||||
if (not && svc) {
|
||||
logit(LOG_NOTICE, "skipping %s, %s already loaded.", ident, svc_ident(svc, NULL, 0));
|
||||
return 0;
|
||||
}
|
||||
if (!not && !svc) {
|
||||
logit(LOG_NOTICE, "skipping %s, %s not available.", ident, stmt);
|
||||
return 0;
|
||||
strlcpy(stmts, stmt, sizeof(stmts));
|
||||
for (stmt = strtok(stmts, ","); stmt; stmt = strtok(NULL, ","), not = 0) {
|
||||
if (stmt[0] == '!') {
|
||||
stmt++;
|
||||
not++;
|
||||
}
|
||||
|
||||
svc = svc_find_by_str(stmt);
|
||||
if (not && svc) {
|
||||
if (!quiet)
|
||||
logit(LOG_NOTICE, "skipping %s, %s already loaded.", ident, svc_ident(svc, NULL, 0));
|
||||
return 0;
|
||||
}
|
||||
if (!not && !svc) {
|
||||
if (!quiet)
|
||||
logit(LOG_NOTICE, "skipping %s, %s not available.", ident, stmt);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Low-level service primitives and generic API for managing svc_t structures
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2024 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,14 +52,16 @@ typedef enum {
|
||||
} svc_type_t;
|
||||
|
||||
#define SVC_TYPE_ANY (-1)
|
||||
#define SVC_TYPE_RESPAWN (SVC_TYPE_SERVICE | SVC_TYPE_TTY)
|
||||
#define SVC_TYPE_RUNTASK (SVC_TYPE_RUN | SVC_TYPE_TASK | SVC_TYPE_SYSV)
|
||||
#define SVC_TYPE_RESPAWN (SVC_TYPE_SERVICE | SVC_TYPE_SYSV | SVC_TYPE_TTY)
|
||||
#define SVC_TYPE_RUNTASK (SVC_TYPE_RUN | SVC_TYPE_TASK)
|
||||
|
||||
typedef enum {
|
||||
SVC_HALTED_STATE = 0, /* Not allowed in runlevel, or not enabled. */
|
||||
SVC_DONE_STATE, /* Task/Run job has been run */
|
||||
SVC_DEAD_STATE, /* Process is dead and scheduled for removal */
|
||||
SVC_CLEANUP_STATE, /* Running cleanup: script */
|
||||
SVC_TEARDOWN_STATE, /* Running post: script */
|
||||
SVC_STOPPING_STATE, /* Waiting to collect the child process */
|
||||
SVC_CLEANUP_STATE, /* Running post: script */
|
||||
SVC_SETUP_STATE, /* Running pre: script */
|
||||
SVC_PAUSED_STATE, /* Condition is in flux, process SIGSTOPed */
|
||||
SVC_WAITING_STATE, /* Enabled but condition not satisfied */
|
||||
@@ -83,8 +85,17 @@ typedef enum {
|
||||
SVC_ONCRASH_SCRIPT,
|
||||
} svc_oncrash_action_t;
|
||||
|
||||
/* 0: none, 1: systemd, 2: s6 */
|
||||
typedef enum {
|
||||
SVC_NOTIFY_NONE = 0,
|
||||
SVC_NOTIFY_PID,
|
||||
SVC_NOTIFY_SYSTEMD,
|
||||
SVC_NOTIFY_S6,
|
||||
} svc_notify_t;
|
||||
|
||||
#define MAX_ID_LEN 16
|
||||
#define MAX_ARG_LEN 64
|
||||
#define MAX_CMD_LEN 256
|
||||
#define MAX_IDENT_LEN (MAX_ARG_LEN + MAX_ID_LEN + 1)
|
||||
#define MAX_STR_LEN 64
|
||||
#define MAX_COND_LEN (MAX_ARG_LEN * 3)
|
||||
@@ -118,7 +129,7 @@ typedef struct svc {
|
||||
int sighalt; /* Signal to stop process, default: SIGTERM */
|
||||
int killdelay; /* Delay in msec before sending SIGKILL */
|
||||
pid_t oldpid, pid;
|
||||
char pidfile[256];
|
||||
char pidfile[MAX_CMD_LEN];
|
||||
long start_time; /* Start time, as seconds since boot, from sysinfo() */
|
||||
int started; /* Set for run/task/sysv to track if started */
|
||||
int status; /* From waitpid() when process is collected */
|
||||
@@ -181,15 +192,24 @@ typedef struct svc {
|
||||
char group[MAX_USER_LEN];
|
||||
|
||||
/* Command, arguments and service description */
|
||||
char cmd[MAX_ARG_LEN];
|
||||
char args[MAX_NUM_SVC_ARGS][MAX_ARG_LEN];
|
||||
char cmd[MAX_CMD_LEN];
|
||||
char args[MAX_NUM_SVC_ARGS][MAX_CMD_LEN];
|
||||
int args_dirty;
|
||||
char conflict[MAX_ARG_LEN];
|
||||
char desc[MAX_STR_LEN];
|
||||
char env[MAX_ARG_LEN];
|
||||
char pre_script[MAX_ARG_LEN];
|
||||
char post_script[MAX_ARG_LEN];
|
||||
char ready_script[MAX_ARG_LEN];
|
||||
char env[MAX_CMD_LEN];
|
||||
|
||||
char pre_script[MAX_CMD_LEN];
|
||||
int pre_tmo;
|
||||
|
||||
char post_script[MAX_CMD_LEN];
|
||||
int post_tmo;
|
||||
|
||||
char ready_script[MAX_CMD_LEN];
|
||||
int ready_tmo;
|
||||
|
||||
char cleanup_script[MAX_CMD_LEN];
|
||||
int cleanup_tmo;
|
||||
|
||||
/*
|
||||
* Used to forcefully kill services that won't shutdown on
|
||||
@@ -201,7 +221,7 @@ typedef struct svc {
|
||||
/*
|
||||
* Readiness notification socket: systemd, s6
|
||||
*/
|
||||
int notify; /* 0: none, 1: systemd, 2: s6 */
|
||||
svc_notify_t notify;
|
||||
uev_t notify_watcher; /* i/o watcher */
|
||||
|
||||
/* time at svc_del(), used by gc timer */
|
||||
@@ -228,6 +248,7 @@ void svc_foreach (int (*cb)(svc_t *));
|
||||
void svc_foreach_type (int types, int (*cb)(svc_t *));
|
||||
|
||||
svc_t *svc_stop_completed (void);
|
||||
svc_t *svc_clean_completed (void);
|
||||
|
||||
void svc_mark (svc_t *svc);
|
||||
void svc_mark_dynamic (void);
|
||||
@@ -240,7 +261,7 @@ void svc_prune_bootstrap (void);
|
||||
void svc_enable (svc_t *svc);
|
||||
int svc_enabled (svc_t *svc);
|
||||
int svc_conflicts (svc_t *svc);
|
||||
int svc_ifthen (const char *ident, char *ifstm);
|
||||
int svc_ifthen (int is_conf, const char *ident, char *stmt, int quiet);
|
||||
|
||||
int svc_parse_jobstr (char *str, size_t len, void *user_data, int (*found)(svc_t *, void *), int (not_found)(char *, char *, void *));
|
||||
|
||||
@@ -250,6 +271,7 @@ static inline int svc_is_tty (svc_t *svc) { return svc && SVC_TYPE_TTY
|
||||
static inline int svc_is_runtask (svc_t *svc) { return svc && (SVC_TYPE_RUNTASK & svc->type);}
|
||||
static inline int svc_is_forking (svc_t *svc) { return svc && svc->forking; }
|
||||
static inline int svc_is_manual (svc_t *svc) { return svc && svc->manual; }
|
||||
static inline int svc_is_nohup (svc_t *svc) { return svc && (0 == svc->sighup); }
|
||||
|
||||
static inline int svc_in_runlevel (svc_t *svc, int runlevel) { return svc && ISSET(svc->runlevels, runlevel); }
|
||||
static inline int svc_nohup (svc_t *svc) { return svc && (0 == svc->sighup || 0 != svc->args_dirty); }
|
||||
@@ -257,11 +279,13 @@ static inline int svc_has_pidfile (svc_t *svc) { return svc_is_daemon(svc) && s
|
||||
static inline int svc_has_pre (svc_t *svc) { return svc->pre_script[0]; }
|
||||
static inline int svc_has_post (svc_t *svc) { return svc->post_script[0]; }
|
||||
static inline int svc_has_ready (svc_t *svc) { return svc->ready_script[0];}
|
||||
static inline int svc_has_cleanup (svc_t *svc) { return svc->cleanup_script[0]; }
|
||||
|
||||
static inline void svc_starting (svc_t *svc) { if (svc) svc->starting = 1; }
|
||||
static inline void svc_started (svc_t *svc) { if (svc) svc->starting = 0; }
|
||||
static inline int svc_is_starting (svc_t *svc) { return svc && 0 != svc->starting; }
|
||||
static inline int svc_is_running (svc_t *svc) { return svc && svc->state == SVC_RUNNING_STATE; }
|
||||
static inline int svc_is_stopping (svc_t *svc) { return svc && svc->state == SVC_STOPPING_STATE; }
|
||||
|
||||
static inline int svc_is_removed (svc_t *svc) { return svc && svc->removed; }
|
||||
static inline int svc_is_changed (svc_t *svc) { return svc && 0 != svc->dirty; }
|
||||
@@ -376,12 +400,15 @@ static inline char *svc_status(svc_t *svc)
|
||||
return "stopping";
|
||||
}
|
||||
|
||||
case SVC_CLEANUP_STATE:
|
||||
return "cleanup";
|
||||
case SVC_TEARDOWN_STATE:
|
||||
return "teardown";
|
||||
|
||||
case SVC_SETUP_STATE:
|
||||
return "setup";
|
||||
|
||||
case SVC_CLEANUP_STATE:
|
||||
return "cleanup";
|
||||
|
||||
case SVC_PAUSED_STATE:
|
||||
return "paused";
|
||||
|
||||
@@ -394,6 +421,9 @@ static inline char *svc_status(svc_t *svc)
|
||||
case SVC_RUNNING_STATE:
|
||||
return "running";
|
||||
|
||||
case SVC_DEAD_STATE:
|
||||
return "dead";
|
||||
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
+10
-6
@@ -1,6 +1,6 @@
|
||||
/* Limited tmpfiles.d implementation
|
||||
*
|
||||
* Copyright (c) 2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2024 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
|
||||
@@ -78,8 +78,8 @@ static int do_delete(const char *fpath, const struct stat *sb, int tflag, struct
|
||||
if (ftw->level == 0)
|
||||
return 1;
|
||||
|
||||
if (remove(fpath))
|
||||
warn("Failed removing condition %s", fpath);
|
||||
if (remove(fpath) && errno != EBUSY)
|
||||
warn("Failed removing %s", fpath);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -90,7 +90,7 @@ static int rmrf(const char *path)
|
||||
if (!fisdir(path))
|
||||
return 0;
|
||||
|
||||
nftw(path, do_delete, 20, FTW_DEPTH);
|
||||
nftw(path, do_delete, 20, FTW_DEPTH | FTW_PHYS);
|
||||
if (remove(path) && errno != ENOENT)
|
||||
warn("Failed removing path %s", path);
|
||||
|
||||
@@ -434,6 +434,10 @@ static void tmpfiles(char *line)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'X':
|
||||
case 'x':
|
||||
dbg("Unsupported x/X command, ignoring %s, no support for clean at runtime.", path);
|
||||
break;
|
||||
case 'Z':
|
||||
opts = "-R";
|
||||
/* fallthrough */
|
||||
@@ -471,7 +475,7 @@ void tmpfilesd(void)
|
||||
/* in priority order */
|
||||
char *dir[] = {
|
||||
FINIT_TMPFILES "/*.conf",
|
||||
TMPFILES_PATH "/*.conf",
|
||||
TMPFILES_PATH_ "/*.conf",
|
||||
"/usr/lib/tmpfiles.d/*.conf",
|
||||
"/run/tmpfiles.d/*.conf",
|
||||
"/etc/tmpfiles.d/*.conf", /* local admin overrides */
|
||||
@@ -492,7 +496,7 @@ void tmpfilesd(void)
|
||||
|
||||
/* check for overrides */
|
||||
for (j = i + 1; j < gl.gl_pathc; j++) {
|
||||
if (strcmp(basename(fn), basename(gl.gl_pathv[j])))
|
||||
if (strcmp(basenm(fn), basenm(gl.gl_pathv[j])))
|
||||
continue;
|
||||
fn = NULL;
|
||||
break;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user