mirror of
https://github.com/troglobit/finit.git
synced 2026-10-12 10:12:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a32ec5c92 | ||
|
|
081622a085 | ||
|
|
2526431d8e | ||
|
|
47d8a83668 | ||
|
|
f72f3febf9 | ||
|
|
138546d008 | ||
|
|
cee244d151 | ||
|
|
7af4ad5c24 | ||
|
|
c0d3705ed5 | ||
|
|
5cf2b9a283 | ||
|
|
0e898da6e5 | ||
|
|
d9f13a1e50 | ||
|
|
4fbcd1bbad | ||
|
|
b6c5498f43 | ||
|
|
9a6c68c952 | ||
|
|
e8170e1216 | ||
|
|
059a4c8a86 | ||
|
|
0de9db68a3 | ||
|
|
aeff68b598 | ||
|
|
700c32fd73 | ||
|
|
334d4a708a | ||
|
|
4d472273e1 | ||
|
|
13f1359b3a | ||
|
|
2e5b97c8b2 | ||
|
|
9a962c86c8 | ||
|
|
f954a4cb92 | ||
|
|
feb97bc77c | ||
|
|
e00fda5dc3 | ||
|
|
80191f2fd5 | ||
|
|
42ef3d3cf7 | ||
|
|
1f4acb322a | ||
|
|
c3ba15045b | ||
|
|
8f1d1717f8 | ||
|
|
7703d00e82 | ||
|
|
3bb826b22b | ||
|
|
9ee2be121f | ||
|
|
36c6aa73aa | ||
|
|
13dddb6912 | ||
|
|
bdaf3370d4 | ||
|
|
a24077c4af | ||
|
|
414a49d733 | ||
|
|
be9d54561d | ||
|
|
3ce5a2a965 | ||
|
|
1d03e9aa8b | ||
|
|
5340e47e81 | ||
|
|
98bbf4a1e5 | ||
|
|
d70e2f1ed0 | ||
|
|
ecb5949679 | ||
|
|
e55fd19091 | ||
|
|
19c64e323c | ||
|
|
9354221bdd | ||
|
|
1d7048d3ae | ||
|
|
8251d713e0 | ||
|
|
44d0d87ad3 | ||
|
|
571250a9b9 | ||
|
|
91540fd793 | ||
|
|
2566e00ef0 | ||
|
|
1e5ce38928 | ||
|
|
c679b0a93d | ||
|
|
c4dcf568c8 | ||
|
|
b65773d508 | ||
|
|
e75c1792aa | ||
|
|
0be4838e01 | ||
|
|
b71605c819 | ||
|
|
3bb2eb2a8d | ||
|
|
8ce35771c3 | ||
|
|
67e80ea989 | ||
|
|
f4d8ecfb5b | ||
|
|
2eb3ebb404 | ||
|
|
1e1b3564dd | ||
|
|
7af257cccf | ||
|
|
84ddac65e5 | ||
|
|
62d6b56fd3 | ||
|
|
fa71f97dcf | ||
|
|
ed383eaaa6 | ||
|
|
9cb6a54493 | ||
|
|
f796d59f77 | ||
|
|
97ca450966 | ||
|
|
e0c1c08e68 | ||
|
|
c81b722691 | ||
|
|
11da93b759 | ||
|
|
28a90a793d | ||
|
|
56a89db889 | ||
|
|
a613ee908f | ||
|
|
d3f58b5df0 | ||
|
|
af88b10322 | ||
|
|
966ae9fb0d | ||
|
|
a69cef0a11 | ||
|
|
b396a018c5 | ||
|
|
a4af9ba248 | ||
|
|
6942e38413 | ||
|
|
e03bd093b5 | ||
|
|
d6070a0d10 | ||
|
|
bd4efb59ca | ||
|
|
a90cfd4a75 | ||
|
|
ab5a983bf7 | ||
|
|
f7bacf8b1b | ||
|
|
d363501e21 | ||
|
|
4150fdfe59 | ||
|
|
4d2b97e4cc | ||
|
|
21eda9dd1c | ||
|
|
4f7e726a3e | ||
|
|
74fc16b832 | ||
|
|
7393072120 | ||
|
|
96bb3f5c6c | ||
|
|
c23a867485 | ||
|
|
4f8a5a6531 | ||
|
|
48e1a0b17f | ||
|
|
9c727ed08d | ||
|
|
49cd3a441d | ||
|
|
8b9258aa73 | ||
|
|
82c6e4680f | ||
|
|
a67b2ba9a7 | ||
|
|
a96edf0291 | ||
|
|
c26dded49c | ||
|
|
3bd15a53d6 | ||
|
|
f0a888c0d1 | ||
|
|
b6769356b2 | ||
|
|
5a9cafc2fc | ||
|
|
2e36590bbd | ||
|
|
33e504b928 | ||
|
|
6a4f197cc0 | ||
|
|
4894580e8b | ||
|
|
70997fb4c5 | ||
|
|
e9515971ea | ||
|
|
82dfa002ff | ||
|
|
a664fd7192 | ||
|
|
b62ee0ef6d | ||
|
|
0cfd867816 | ||
|
|
934a4db7d5 | ||
|
|
c9fe9afa61 | ||
|
|
320e91653b | ||
|
|
859d215ca4 | ||
|
|
0a94f3f303 | ||
|
|
e83a26b256 | ||
|
|
2508495b8c | ||
|
|
3ef52d9324 | ||
|
|
05b72281e6 | ||
|
|
a47abfdc16 | ||
|
|
2c9265f8c8 | ||
|
|
56cb6f8613 | ||
|
|
3dd56ed8af | ||
|
|
fddeeb683c | ||
|
|
25835b0edf | ||
|
|
27fcfada66 | ||
|
|
2dd5fb0f77 | ||
|
|
63044a4b81 | ||
|
|
4e74f9783a | ||
|
|
c3c662fe64 | ||
|
|
7c2764790c | ||
|
|
732d500cf5 | ||
|
|
4e1ac726ac | ||
|
|
fba58085c6 | ||
|
|
d1ebb255c6 | ||
|
|
a39ee0b44d | ||
|
|
947d91acd5 | ||
|
|
8c206d52e5 | ||
|
|
0f445dc9f4 | ||
|
|
c71b35e61a | ||
|
|
d20308b7d7 | ||
|
|
e4e54a88d9 | ||
|
|
308b7c5197 | ||
|
|
89772bf6c0 | ||
|
|
077002e647 | ||
|
|
988cdf9878 | ||
|
|
97db2078f5 | ||
|
|
02a110e6c2 | ||
|
|
681ef8de6f | ||
|
|
0147e0e64f | ||
|
|
311c6be9aa | ||
|
|
c22d123ab0 | ||
|
|
96b5991355 | ||
|
|
06bd352863 | ||
|
|
a918f7497a | ||
|
|
8bbae3d414 | ||
|
|
bfd1f36fdd | ||
|
|
6fc702a560 | ||
|
|
40dcc5541b | ||
|
|
5b41c6e327 | ||
|
|
4bd81b4d4c | ||
|
|
c29589c2ca | ||
|
|
73b89430e4 | ||
|
|
2a62fa3d85 | ||
|
|
4542fdb5bb | ||
|
|
525aaf1f66 | ||
|
|
910dac5f3a | ||
|
|
2a5c319084 | ||
|
|
612f4fe288 | ||
|
|
c058c05651 | ||
|
|
0de4578e50 | ||
|
|
b9e94e4695 | ||
|
|
9887003b25 | ||
|
|
f6bfbc86e9 | ||
|
|
4c90b51d80 | ||
|
|
48cfbfe5ed | ||
|
|
f98be8540f | ||
|
|
17c69fef3d | ||
|
|
c586204fc1 | ||
|
|
ff5e3219be | ||
|
|
07c52f1566 | ||
|
|
0e04ffd68f | ||
|
|
8b5435908c | ||
|
|
3a74310aa6 | ||
|
|
180859a429 | ||
|
|
1d92819d92 | ||
|
|
cfa871c548 | ||
|
|
685e0a80a4 | ||
|
|
19847d2997 | ||
|
|
7108b0e789 | ||
|
|
7eac0b0341 | ||
|
|
33ec4e7d19 | ||
|
|
1b78f2b364 | ||
|
|
119363ff75 | ||
|
|
f89b508c01 | ||
|
|
dda8c7c3ac | ||
|
|
e2d9aab70d | ||
|
|
3df154b798 | ||
|
|
3d9cbaf040 | ||
|
|
70c2939596 | ||
|
|
d4ee44e27f | ||
|
|
0498326962 | ||
|
|
c84ababbd4 | ||
|
|
67ea42c87b | ||
|
|
a2ab45cad7 | ||
|
|
f3fcca6150 | ||
|
|
2b65d8f1e9 | ||
|
|
7c2abf69c4 | ||
|
|
457c0a246f | ||
|
|
1a439baf68 | ||
|
|
68ce78b3fe | ||
|
|
72e27e99e5 | ||
|
|
a436382886 | ||
|
|
6bbfc7b1f1 | ||
|
|
006dd12b09 | ||
|
|
d3a0631390 | ||
|
|
9046b6fe2b | ||
|
|
f217794773 | ||
|
|
11e02fabb3 | ||
|
|
8b9bb1c7ce | ||
|
|
2a7abf1db0 | ||
|
|
34b8c5a3ba | ||
|
|
8e056422fc | ||
|
|
94e8b185b4 | ||
|
|
996d3960e1 | ||
|
|
3b19734f63 | ||
|
|
64e7c0cd9e | ||
|
|
4d0c88bd7a | ||
|
|
9e8c601507 | ||
|
|
b26104466a | ||
|
|
bd25bf65ce | ||
|
|
edd3b41adf | ||
|
|
28ca3fcc5c | ||
|
|
3b601d0115 | ||
|
|
1ef9a9f128 | ||
|
|
d612a86c3b | ||
|
|
5d3cd05202 | ||
|
|
726f7ba229 | ||
|
|
61dab8bd75 | ||
|
|
a7e81f45c6 | ||
|
|
be4062f019 | ||
|
|
035f06e137 | ||
|
|
2f91ab5eac | ||
|
|
f6b5b0260b | ||
|
|
bb9bd7e0b0 | ||
|
|
287abd5c7c | ||
|
|
d27f114742 | ||
|
|
505c370898 | ||
|
|
f26009ec3e | ||
|
|
8425bc313b | ||
|
|
f4d3cf2835 | ||
|
|
bd5cf7c9eb | ||
|
|
4709394ae6 | ||
|
|
729002ef82 | ||
|
|
58b075dbf2 | ||
|
|
d679840fa3 | ||
|
|
0e70bdbf6a | ||
|
|
d810ac00bc | ||
|
|
5f74adad06 | ||
|
|
585ac51f45 | ||
|
|
ce36797506 | ||
|
|
a61c2ceb79 | ||
|
|
383339dc4a | ||
|
|
36b46ba134 | ||
|
|
a2d0859bf1 | ||
|
|
d5f542dcca | ||
|
|
fb86042cb3 | ||
|
|
359fb8530e | ||
|
|
5dd1a676ac | ||
|
|
278994781b | ||
|
|
c9f1bff419 | ||
|
|
1f9621cf4b | ||
|
|
9458e4e66b | ||
|
|
ff08038bdc | ||
|
|
ce330e8bf1 | ||
|
|
47d837bf6a | ||
|
|
912a281ee2 | ||
|
|
6e863a7872 | ||
|
|
488e6c2adf | ||
|
|
e177b866a9 | ||
|
|
15dcebd0f1 | ||
|
|
af60d8d3ec | ||
|
|
5a32fdb309 | ||
|
|
19f5cb1d01 | ||
|
|
c5bca5f80a | ||
|
|
d22dea74e3 | ||
|
|
dc547317c9 | ||
|
|
6bf5d98569 | ||
|
|
29dea38f50 | ||
|
|
34567dd244 | ||
|
|
a3584c6ca3 | ||
|
|
165d0633f6 | ||
|
|
9f7ba1ba79 | ||
|
|
03c08d3970 | ||
|
|
37e3be9a0d | ||
|
|
10437887fc | ||
|
|
faf1c6233d | ||
|
|
c36960350c | ||
|
|
51ade57723 | ||
|
|
9d79673cea | ||
|
|
762bf5f031 | ||
|
|
abcb3ceb67 | ||
|
|
0ae5071f94 | ||
|
|
e589c5b269 | ||
|
|
12e341fe73 | ||
|
|
9be3c4cb9a | ||
|
|
433f3ce17e | ||
|
|
2c29ede0da | ||
|
|
7cfbca6d74 | ||
|
|
b30621bb3b | ||
|
|
d6f35903d6 | ||
|
|
a61a8015d7 | ||
|
|
e2f070649d | ||
|
|
f08d375c36 | ||
|
|
1c4bad5b73 | ||
|
|
6c874895dc | ||
|
|
ef1a05425d | ||
|
|
fc3bad2160 | ||
|
|
31ac933d64 | ||
|
|
caa398816d | ||
|
|
0d57a507f3 | ||
|
|
96257cc5c7 | ||
|
|
fbcd7d2384 | ||
|
|
d9dbfa23c7 | ||
|
|
91f077bd08 | ||
|
|
5fb4a6ae8f | ||
|
|
e84333662e | ||
|
|
ddb42fda70 | ||
|
|
621eb21b42 | ||
|
|
6cc44a87c9 | ||
|
|
5f908cae49 | ||
|
|
6de67ed107 | ||
|
|
c129f06195 | ||
|
|
d11dc63bc2 | ||
|
|
d904ec1602 | ||
|
|
2a98b2f055 | ||
|
|
6286ede985 | ||
|
|
4a8ca787d3 | ||
|
|
561c88a868 | ||
|
|
f8dfcdf024 | ||
|
|
f50b5a4ac6 | ||
|
|
59525b80e3 | ||
|
|
0ce028add1 | ||
|
|
75c5c85f07 | ||
|
|
ccb84ced2e | ||
|
|
5ef669fb6c | ||
|
|
96ff9c115c | ||
|
|
83aa6abb1c | ||
|
|
9304024841 | ||
|
|
0de5981948 | ||
|
|
c39106906d | ||
|
|
929a6e7aac | ||
|
|
ceb4d04d23 |
@@ -9,9 +9,9 @@ For email questions/requests/alerts there is always the risk of memory
|
|||||||
exhaustion on the part of the maintainer(s).
|
exhaustion on the part of the maintainer(s).
|
||||||
|
|
||||||
If you are unsure of what to do, or how to implement an idea or bugfix,
|
If you are unsure of what to do, or how to implement an idea or bugfix,
|
||||||
open an issue with `"[RFC: Unsure if this is a bug ... ?"`, or similar,
|
open an issue with `"[RFC: Unsure if this is a bug ... ?"`, or use the
|
||||||
so we can discuss it. Talking about the code first is the best way to
|
GitHub discussions forum, so we can discuss it. Talking about the code
|
||||||
get started before submitting a pull request.
|
first is the best way to get started before submitting a pull request.
|
||||||
|
|
||||||
Either way, when sending an email, patch, or pull request, start by
|
Either way, when sending an email, patch, or pull request, start by
|
||||||
stating the version the change is made against, what it does, and why.
|
stating the version the change is made against, what it does, and why.
|
||||||
@@ -73,7 +73,6 @@ It is expected of everyone engaging in the project to, in the words of
|
|||||||
Bill & Ted; [be excellent to each other][conduct].
|
Bill & Ted; [be excellent to each other][conduct].
|
||||||
|
|
||||||
|
|
||||||
[github]: https://github.com/troglobit/finit/
|
|
||||||
[KNF]: https://en.wikipedia.org/wiki/Kernel_Normal_Form
|
[KNF]: https://en.wikipedia.org/wiki/Kernel_Normal_Form
|
||||||
[gitbook]: https://git-scm.com/book/ch5-2.html
|
[gitbook]: https://git-scm.com/book/ch5-2.html
|
||||||
[conduct]: CODE-OF-CONDUCT.md
|
[conduct]: CODE-OF-CONDUCT.md
|
||||||
|
|||||||
+17
-20
@@ -15,7 +15,7 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
# Verify we can build on latest Ubuntu with both gcc and clang
|
# Verify we can build on latest Ubuntu with both gcc and clang
|
||||||
name: ${{ matrix.compiler }}
|
name: ${{ matrix.compiler }}
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
compiler: [gcc, clang]
|
compiler: [gcc, clang]
|
||||||
@@ -27,15 +27,8 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get -y update
|
sudo apt-get -y update
|
||||||
sudo apt-get -y install pkg-config
|
sudo apt-get -y install pkg-config tree jq libuev-dev libite-dev
|
||||||
wget https://github.com/troglobit/libuev/releases/download/v2.3.2/libuev-2.3.2.tar.xz
|
- uses: actions/checkout@v3
|
||||||
wget https://github.com/troglobit/libite/releases/download/v2.5.2/libite-2.5.2.tar.gz
|
|
||||||
tar xf libuev-2.3.2.tar.xz
|
|
||||||
tar xf libite-2.5.2.tar.gz
|
|
||||||
(cd libuev-2.3.2 && ./configure --prefix=/usr && make && sudo make install-strip)
|
|
||||||
(cd libite-2.5.2 && ./configure --prefix=/usr && make && sudo make install-strip)
|
|
||||||
sudo ldconfig
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Static Finit
|
- name: Static Finit
|
||||||
run: |
|
run: |
|
||||||
./autogen.sh
|
./autogen.sh
|
||||||
@@ -43,28 +36,32 @@ jobs:
|
|||||||
make V=1
|
make V=1
|
||||||
- name: Regular Finit
|
- name: Regular Finit
|
||||||
run: |
|
run: |
|
||||||
./configure --prefix= --enable-x11-common-plugin --with-watchdog --with-keventd
|
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
|
||||||
|
--enable-x11-common-plugin --enable-testserv-plugin --with-watchdog \
|
||||||
|
--with-keventd
|
||||||
make clean
|
make clean
|
||||||
make V=1
|
make V=1
|
||||||
- name: Install to ~/tmp and Inspect
|
- name: Install to /tmp
|
||||||
run: |
|
run: |
|
||||||
DESTDIR=/tmp make install-strip
|
DESTDIR=/tmp make install-strip
|
||||||
tree /tmp
|
tree /tmp || true
|
||||||
|
- name: Check dependencies
|
||||||
|
run: |
|
||||||
ldd /tmp/sbin/finit
|
ldd /tmp/sbin/finit
|
||||||
size /tmp/sbin/finit
|
size /tmp/sbin/finit
|
||||||
ldd /tmp/sbin/initctl
|
ldd /tmp/sbin/initctl
|
||||||
size /tmp/sbin/initctl
|
size /tmp/sbin/initctl
|
||||||
ldd /tmp/sbin/reboot
|
ldd /tmp/sbin/reboot
|
||||||
size /tmp/sbin/reboot
|
size /tmp/sbin/reboot
|
||||||
/tmp/sbin/finit -h
|
- name: Verify starting and showing usage text
|
||||||
/tmp/sbin/initctl -h
|
run: |
|
||||||
|
sudo /tmp/sbin/finit -h
|
||||||
|
sudo /tmp/sbin/initctl -h
|
||||||
- name: Run Unit Tests
|
- name: Run Unit Tests
|
||||||
run: |
|
run: |
|
||||||
ver=$(/tmp/sbin/initctl -V | awk '/Finit.*/ {print $2;}')
|
make check || (cat test/test-suite.log; false)
|
||||||
dir=finit-$ver/_build/sub
|
|
||||||
make -j1 distcheck || (cat $dir/test/setup-root.log; cat $dir/test/test-suite.log; false)
|
|
||||||
- name: Upload Test Results
|
- name: Upload Test Results
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: finit-test-${{ matrix.compiler }}
|
name: finit-test-${{ matrix.compiler }}
|
||||||
path: test/*
|
path: test/*.log
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ jobs:
|
|||||||
coverity:
|
coverity:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
id: coverity-toolchain-cache
|
id: coverity-toolchain-cache
|
||||||
with:
|
with:
|
||||||
path: cov-analysis-linux64
|
path: cov-analysis-linux64
|
||||||
@@ -35,12 +35,12 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
sudo apt-get -y update
|
sudo apt-get -y update
|
||||||
sudo apt-get -y install pkg-config
|
sudo apt-get -y install pkg-config
|
||||||
wget https://github.com/troglobit/libuev/releases/download/v2.3.2/libuev-2.3.2.tar.xz
|
wget https://github.com/troglobit/libuev/releases/download/v2.4.0/libuev-2.4.0.tar.xz
|
||||||
wget https://github.com/troglobit/libite/releases/download/v2.3.1/libite-2.3.1.tar.gz
|
wget https://github.com/troglobit/libite/releases/download/v2.5.2/libite-2.5.2.tar.gz
|
||||||
tar xf libuev-2.3.2.tar.xz
|
tar xf libuev-2.4.0.tar.xz
|
||||||
tar xf libite-2.3.1.tar.gz
|
tar xf libite-2.5.2.tar.gz
|
||||||
(cd libuev-2.3.2 && ./configure --prefix=/usr && make && sudo make install-strip)
|
(cd libuev-2.4.0 && ./configure --prefix=/usr && make && sudo make install-strip)
|
||||||
(cd libite-2.3.1 && ./configure --prefix=/usr && make && sudo make install-strip)
|
(cd libite-2.5.2 && ./configure --prefix=/usr && make && sudo make install-strip)
|
||||||
sudo ldconfig
|
sudo ldconfig
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -7,63 +7,34 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
name: Create GitHub release
|
name: Build and upload release tarball
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
outputs:
|
runs-on: ubuntu-latest
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
||||||
release_id: ${{ steps.create_release.outputs.id }}
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
- name: Installing dependencies ...
|
||||||
|
run: |
|
||||||
|
sudo apt-get -y update
|
||||||
|
sudo apt-get -y install pkg-config jq libuev-dev libite-dev
|
||||||
|
- 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: Build release ...
|
||||||
|
run: |
|
||||||
|
make release || (cat test/test-suite.log; false)
|
||||||
|
ls -lF ../
|
||||||
|
mkdir -p artifacts/
|
||||||
|
mv ../*.tar.* artifacts/
|
||||||
- name: Extract ChangeLog entry ...
|
- name: Extract ChangeLog entry ...
|
||||||
# Hack to extract latest entry for body_path below
|
|
||||||
run: |
|
run: |
|
||||||
awk '/-----*/{if (x == 1) exit; x=1;next}x' ChangeLog.md \
|
awk '/-----*/{if (x == 1) exit; x=1;next}x' ChangeLog.md \
|
||||||
|head -n -1 > release.md
|
|head -n -1 > release.md
|
||||||
cat release.md
|
cat release.md
|
||||||
- name: Create release ...
|
- uses: ncipollo/release-action@v1
|
||||||
id: create_release
|
|
||||||
uses: actions/create-release@v1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
with:
|
||||||
tag_name: ${{ github.ref }}
|
name: Finit v${{ github.ref_name }}
|
||||||
release_name: Finit v${{ github.ref }}
|
bodyFile: "release.md"
|
||||||
body_path: release.md
|
artifacts: "artifacts/*"
|
||||||
draft: false
|
|
||||||
prerelease: false
|
|
||||||
tarball:
|
|
||||||
name: Build and upload release tarball
|
|
||||||
needs: release
|
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Installing dependencies
|
|
||||||
run: |
|
|
||||||
sudo apt-get -y update
|
|
||||||
sudo apt-get -y install pkg-config
|
|
||||||
wget https://github.com/troglobit/libuev/releases/download/v2.3.2/libuev-2.3.2.tar.xz
|
|
||||||
wget https://github.com/troglobit/libite/releases/download/v2.3.1/libite-2.3.1.tar.gz
|
|
||||||
tar xf libuev-2.3.2.tar.xz
|
|
||||||
tar xf libite-2.3.1.tar.gz
|
|
||||||
(cd libuev-2.3.2 && ./configure --prefix=/usr && make && sudo make install-strip)
|
|
||||||
(cd libite-2.3.1 && ./configure --prefix=/usr && make && sudo make install-strip)
|
|
||||||
sudo ldconfig
|
|
||||||
- name: Creating Makefiles
|
|
||||||
run: |
|
|
||||||
./autogen.sh
|
|
||||||
./configure --prefix= --enable-x11-common-plugin --with-watchdog --with-keventd
|
|
||||||
- name: Building release
|
|
||||||
run: |
|
|
||||||
make release
|
|
||||||
ls -lF ../
|
|
||||||
mkdir -p artifacts/
|
|
||||||
mv ../*.tar.* artifacts/
|
|
||||||
- name: Uploading release artifacts
|
|
||||||
uses: skx/github-action-publish-binaries@release-0.15
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
releaseId: ${{ needs.release.outputs.release_id }}
|
|
||||||
args: artifacts/*
|
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
name: Weekly Distcheck
|
||||||
|
|
||||||
|
# Verify that `make distcheck` works as intended: all tests pass, and
|
||||||
|
# any new files are distributed in the tarballs
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * 0'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
schedule:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
run: ${{ steps.check.outputs.run }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Check for any commits since last week
|
||||||
|
run: |
|
||||||
|
commits="$(git log --format=%H --since='1 week ago')"
|
||||||
|
if [ -n "$commits" ]; then
|
||||||
|
echo "run=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "run=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
distcheck:
|
||||||
|
needs: schedule
|
||||||
|
if: ${{ needs.schedule.outputs.run == 'true' }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get -y update
|
||||||
|
sudo apt-get -y install pkg-config jq libuev-dev libite-dev
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Base run
|
||||||
|
run: |
|
||||||
|
./autogen.sh
|
||||||
|
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var
|
||||||
|
make -j9 V=1
|
||||||
|
- name: Install to /tmp
|
||||||
|
run: |
|
||||||
|
DESTDIR=/tmp make install-strip
|
||||||
|
- name: Check dist tarball
|
||||||
|
run: |
|
||||||
|
ver=$(/tmp/sbin/initctl -V | awk '/Finit.*/ {print $2;}')
|
||||||
|
dir=finit-$ver/_build/sub
|
||||||
|
make -j1 distcheck || (cat $dir/test/test-suite.log; false)
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# GNU Global .conf file, see /etc/gtags/gtags.conf for details.
|
||||||
|
default:\
|
||||||
|
:tc=default@/etc/gtags/gtags.conf:\
|
||||||
|
:tc=common:
|
||||||
|
|
||||||
|
common:\
|
||||||
|
:skip=tags,TAGS,ID,y.tab.c,y.tab.h,gtags.files,cscope.files,cscope.out,cscope.po.out,cscope.in.out,,{arch}/,autom4te.cache/,*.orig,*.rej,*.bak,*~,#*#,*.swp,*.tmp,*_flymake.*,*_flymake,*.o,*.a,*.so,*.lo,*.zip,*.gz,*.bz2,*.xz,*.lzh,*.Z,*.tgz,*.min.js,*min.css,sysroot/:
|
||||||
+340
-1
@@ -4,6 +4,344 @@ Change Log
|
|||||||
All relevant changes are documented in this file.
|
All relevant changes are documented in this file.
|
||||||
|
|
||||||
|
|
||||||
|
[4.4][UNRELEASED]
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
> **Note 1:** this release contains changes to the `.conf` parser. If you
|
||||||
|
> have .conf file statements with comment character (`#`) in the command
|
||||||
|
> options or description, you must now escape them (`\#`). Issue #186
|
||||||
|
>
|
||||||
|
> **Note 2:** prior to this release, runlevel `S` and `0` were after
|
||||||
|
> boot treated as the same runlevel. This caused `task [06] ...` to
|
||||||
|
> also run at bootstrap instead of just at shutdown and reboot. The
|
||||||
|
> changes made to Finit to separate `S` from `0` require you to update
|
||||||
|
> the allowed runlevels for services that are allowed to continue
|
||||||
|
> running at shutdown. I.e., change `[S123456789]` to `[S0123456789]`
|
||||||
|
> for, e.g., `sysklogd`. Issue #352
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
* Add limited tmpfiles.d(5) support
|
||||||
|
|
||||||
|
This change adds very basic `tmpfiles.d/` support to Finit. Most of
|
||||||
|
the basic types are supported, but not all, so for now, please check
|
||||||
|
the code and examples for details on what is working.
|
||||||
|
|
||||||
|
* If a run/task/service command does not exist, skip registering it
|
||||||
|
|
||||||
|
This changes the semantics of Finit a bit by checking for the command
|
||||||
|
to run when registering it, skipping commands that cannot be found in
|
||||||
|
the absolute path provided in the command, or in `$PATH`
|
||||||
|
|
||||||
|
This change includes a new `nowarn` flag that can be used to prevent
|
||||||
|
Finit from warning for missing commands. See below for an example.
|
||||||
|
|
||||||
|
* Add run/task/service support for `conflict:foo` handling
|
||||||
|
* Add run/task/service support for `if:[!]ident` and `if:<[!]cond>`
|
||||||
|
|
||||||
|
Conditional loading of stanza depending on ident is already loaded (or
|
||||||
|
not), or condition satisfied (or not). E.g., do not run `mdev` if we
|
||||||
|
found and registered `udevd`, or load service only if `<boot/testing>`
|
||||||
|
condition is set.
|
||||||
|
|
||||||
|
The optional leading `!` negates the comparison, if NOT foo then ...
|
||||||
|
|
||||||
|
* Add support for static services in `/lib/finit/system/*.conf`
|
||||||
|
|
||||||
|
Slowly migrating away from hard-coded services in plugins. This way
|
||||||
|
it's possible for the user to both inspect and override as needed.
|
||||||
|
|
||||||
|
* Migrate hotplug plugin to a conditional `/lib/finit/system/hotplug.conf`
|
||||||
|
|
||||||
|
This is the first example of the just minted advanced stanza syntax with
|
||||||
|
`if:`-statements, `conflict:` handling, and `nowarn` flags.
|
||||||
|
|
||||||
|
* Initial support for template services, `foo@.conf`, similar to systemd
|
||||||
|
|
||||||
|
$ initctl show avahi-autoipd@
|
||||||
|
service :%i avahi-autoipd --syslog %i -- ZeroConf for %i
|
||||||
|
|
||||||
|
To enable ZeroConf for, e.g., `eth0`, use
|
||||||
|
|
||||||
|
$ initctl enable avahi-autoipd@eth0.conf
|
||||||
|
|
||||||
|
The enabled symlink will be set up to `avahi-autoipd@.conf` and every
|
||||||
|
instance of `%i` will in the instantiated directive be replaced with
|
||||||
|
`eth0`. Inspect the result with:
|
||||||
|
|
||||||
|
$ initctl status avahi-autoipd:eth0
|
||||||
|
|
||||||
|
* Add `devmon`, a `<dev/foo>` condition provider, issue #185
|
||||||
|
* Support for line continuation character `\` in .conf files, issue #186
|
||||||
|
|
||||||
|
service name:sysklogd [S123456789] \
|
||||||
|
env:-/etc/default/sysklogd \
|
||||||
|
syslogd -F $SYSLOGD_ARGS \
|
||||||
|
-- System log daemon
|
||||||
|
|
||||||
|
* `HOOK_BASEFS_UP` has been moved! External plugins that need to call
|
||||||
|
`service_register()`, please use `HOOK_SVC_PLUGIN` from now on.
|
||||||
|
Apologies for any inconveniences this might cause!
|
||||||
|
* getty: add support for `/etc/os-release` to replace `uname` output
|
||||||
|
This change, which has a fallback to `/usr/lib/os-release`, overrides
|
||||||
|
traditional modifiers with the os-release variant. These values were
|
||||||
|
taken from `uname`, which on Linux systems are pretty useless since
|
||||||
|
they always return the kernel name and version instead of the
|
||||||
|
distro/OS values.
|
||||||
|
|
||||||
|
E.g., \s becomes `PRETTY_NAME` instead of 'Linux' and \v becomes the
|
||||||
|
pretty `VERSION`, while \r becomes `VERSION_ID`.
|
||||||
|
* Support for overriding `/etc/finit.conf` and `/etc/finit.d` issue #235
|
||||||
|
New (kernel) command line option `finit.config=PATH` which can be used
|
||||||
|
to redirect Finit to start up with, e.g., `/etc/factory.conf` instead of
|
||||||
|
`/etc/finit.conf`.
|
||||||
|
|
||||||
|
For the complete experience a new top-level configuration file directive
|
||||||
|
`rcsd PATH` has aslo been added. It in turn can be used by `factory.conf`
|
||||||
|
as follows to override `/etc/finit.d`:
|
||||||
|
|
||||||
|
rcsd /etc/factory.d
|
||||||
|
|
||||||
|
* Support for overriding `/etc/finit.d` from the alternate `finit.conf`
|
||||||
|
with a new `rcsd /path/to/dot.d/` .conf file directive
|
||||||
|
* Support for `fsck_mode=[auto,skip,force]` + `fsck_repair=[preen,no,yes]`
|
||||||
|
* Add `set` keyword for environment variables set in `/etc/finit.conf`
|
||||||
|
* Support `finit.cond=foo` cmdline `<boot/foo>` conditions, issue #250
|
||||||
|
* `initctl` JSON output support for status and conditions, issue #273
|
||||||
|
Example:
|
||||||
|
|
||||||
|
root@infix:~$ initctl status -j resolvconf
|
||||||
|
{
|
||||||
|
"identity": "resolvconf",
|
||||||
|
"description": "Update DNS configuration",
|
||||||
|
"type": "task",
|
||||||
|
"forking": false,
|
||||||
|
"status": "done",
|
||||||
|
"exit": { "code": 0 },
|
||||||
|
"origin": "/etc/finit.d/enabled/sysrepo.conf",
|
||||||
|
"command": "resolvconf -u",
|
||||||
|
"restarts": 0,
|
||||||
|
"pidfile": "none",
|
||||||
|
"pid": 0,
|
||||||
|
"user": "root",
|
||||||
|
"group": "root",
|
||||||
|
"uptime": 0,
|
||||||
|
"runlevels": [ 1, 2, 3, 4, 5, 7, 8, 9 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
The excellent tool `jq` can be used to extract parts of the output for
|
||||||
|
further scripting. E.g. `initctl status -j foo | jq .exit.status`
|
||||||
|
|
||||||
|
* Add JSON support to `initctl ls` command
|
||||||
|
|
||||||
|
This allows for easy access to the *disabled* services:
|
||||||
|
|
||||||
|
root@anarchy:~# initctl ls --json |jq '.available - .enabled'
|
||||||
|
[
|
||||||
|
"chronyd.conf",
|
||||||
|
"dnsmasq.conf",
|
||||||
|
"gdbserver.conf",
|
||||||
|
"inadyn.conf",
|
||||||
|
"inetd.conf",
|
||||||
|
"isisd.conf",
|
||||||
|
"lldpd.conf",
|
||||||
|
"mstpd.conf",
|
||||||
|
"ntpd.conf",
|
||||||
|
"ospf6d.conf",
|
||||||
|
"ospfd.conf",
|
||||||
|
"querierd.conf",
|
||||||
|
"ripd.conf",
|
||||||
|
"ripng.conf",
|
||||||
|
"sshd.conf",
|
||||||
|
"syslogd.conf",
|
||||||
|
"telnetd.conf",
|
||||||
|
"uftpd.conf",
|
||||||
|
"wpa_supplicant.conf",
|
||||||
|
"zebra.conf"
|
||||||
|
]
|
||||||
|
|
||||||
|
* Allow `manual:yes` on sysv/service/run/task stanzas, issue #274
|
||||||
|
* Add support for `oncrash:script` to call the `post:script` action, if
|
||||||
|
defined, for a crashing service. The `EXIT_CODE` variable sent to the
|
||||||
|
script is set to `crashed`. Issue #282
|
||||||
|
* Search for plugins in `/usr` and `/usr/local` as well, issue #284
|
||||||
|
* tty: add support for `passenv` flag to `/bin/login`, issue #286
|
||||||
|
* Add reboot/shutdown/poweroff timeout `-t SEC` to initctl, issue #295
|
||||||
|
* Add support for s6 and systemd readiness notification, issue #299.
|
||||||
|
Service readiness notification to support daemons employing systemd
|
||||||
|
and s6 notification. Complementing the native Finit readiness support
|
||||||
|
using PID files that exist already.
|
||||||
|
|
||||||
|
The two have slightly different ways of implementing readiness:
|
||||||
|
|
||||||
|
- https://www.freedesktop.org/software/systemd/man/sd_notify.html
|
||||||
|
- https://skarnet.org/software/s6/notifywhenup.html
|
||||||
|
|
||||||
|
Finit now provides both a `NOTIFY_SOCKET` environment variable, for
|
||||||
|
systemd, and a way to start s6 daemons with a descriptor argument.
|
||||||
|
|
||||||
|
For details on the syntax, see the `service` documentation.
|
||||||
|
|
||||||
|
This change also renames internal states for run/task/services to
|
||||||
|
avoid any confusion with the introduction of `ready:scripts`:
|
||||||
|
|
||||||
|
- `WAITING -> PAUSED`
|
||||||
|
- `READY -> WAITING`
|
||||||
|
|
||||||
|
A service condition that used, e.g., `<service/foo/ready>` should now
|
||||||
|
instead use `<service/foo/waiting>`
|
||||||
|
|
||||||
|
* Add `ready:script` for services, called when daemon is ready, issue #300
|
||||||
|
* Add support for running scripts at shutdown at two new hook points
|
||||||
|
during the shutdown process, issue #302. See doc/plugins.md for details:
|
||||||
|
|
||||||
|
- `HOOK_SVC_DN`: after all services and non-reserved processes have been
|
||||||
|
killed (and collected)
|
||||||
|
- `HOOK_SYS_DN`: after all file systems have been unmounted, *just prior*
|
||||||
|
to Finit calling `reboot()` to shut down or reboot the system
|
||||||
|
|
||||||
|
* The `modules-load` plugin now default to runlevel `[S]`, in previous
|
||||||
|
releases it was `[2345]`. This breaking change is to align it more
|
||||||
|
with what users mostly want (modules loaded before services start) and
|
||||||
|
can be changed back to the old behavior with a per-file setting:
|
||||||
|
|
||||||
|
set runlevel 2345
|
||||||
|
|
||||||
|
* The `modules-load` plugin now adds silent tasks for modprobe. This to
|
||||||
|
prevent confusing `[ OK ]` boot messages when in fact modprobe failed.
|
||||||
|
* The `modules-load` plugin now support `set modprobe /path/to/modprobe`
|
||||||
|
* The header files `finit/conf.h` and `finit/service.h` are now exported
|
||||||
|
for external plugins
|
||||||
|
* Add support for multiple args to `initctl cond set/clr`, issue #329
|
||||||
|
* Silence confusing `[ OK ]` progress from modules-load plugin, issue #332
|
||||||
|
|
||||||
|
This change drops the confusing status progress output, which was always
|
||||||
|
OK since the actual modprobe operation runs in the background. No need
|
||||||
|
to show status of the "added a task to finit, found modprobe" command.
|
||||||
|
|
||||||
|
* dbus plugin: adapt to other operating systems
|
||||||
|
|
||||||
|
Not all Linux systems are based on Debian, and even if they are inspired
|
||||||
|
by Debian (Buildroot), they do not necessarily use the same defaults.
|
||||||
|
Probes the system at runtime for:
|
||||||
|
|
||||||
|
- dbus user and group
|
||||||
|
- dbus PID file
|
||||||
|
|
||||||
|
If the user/group cannot be found we fall back to `root`, if the PID
|
||||||
|
file cannot be determined we ignore PID file readiness.
|
||||||
|
|
||||||
|
* Improve documentation for runparts and hook scripts. Issue #315, #320
|
||||||
|
* Add `HOOK_NETWORK_DN`, called after change to runlevel 6 or 0, issue #319
|
||||||
|
* Use sysklogd `logger` tool instead of legacy `logit` tool, issue #344
|
||||||
|
|
||||||
|
For log redirection Finit has the legacy `logit` tool. This change
|
||||||
|
allows Finit to use the `sysklogd` project's extended `logger` tool
|
||||||
|
instead, when available. Allowing logging with the process' PID.
|
||||||
|
|
||||||
|
* Add `initctl` aliases: `cat -> show`, `kill -> signal`
|
||||||
|
* Add `initctl -n,--noerr` to return OK(0) if services do not exist, for
|
||||||
|
integration with openresolv and scripts with similar requirements
|
||||||
|
* Add `initctl plugins`, list installed plugins
|
||||||
|
* Add timestamp to log messages in fallback and logging to `stderr`.
|
||||||
|
When there is no log daemon, and we are running in a container, or we
|
||||||
|
cannot log to the kernel ring buffer, then we log to `stderr`. This
|
||||||
|
change improves log output by prefixing each message with a timestamp.
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Fix #254: document limitations in `rc.local` and `runparts` scripts
|
||||||
|
* Fix #269: add compulsory kernel symlinks in `/dev`
|
||||||
|
* Fix #275: `initctl status foo` should list all instances, regression
|
||||||
|
introduced in v4.3
|
||||||
|
* Fix #278: enforce conditions also for running `pre:` scripts
|
||||||
|
* Fix #279: allow `restart:always`, of crashing services. Similar to
|
||||||
|
`respawn` but honors `restart_sec`
|
||||||
|
* Fix #280: allow calling `initctl restart foo` from within foo
|
||||||
|
* Fix #283: too quick timeout at bootstrap of lingering tasks
|
||||||
|
* Fix #285: `initctl restart` should start crashed service
|
||||||
|
* Fix #288: enable built-in `sulogin` in Alpine and Void Linux builds
|
||||||
|
* Fix #293: modprobe plugin: support for coldplugging more devices. It
|
||||||
|
turns out, not all buses in Linux add `modalias` attributes to their
|
||||||
|
devices in sysfs. One notable exception are MDIO buses. The plugin's
|
||||||
|
scan routine would thus not pick them up.
|
||||||
|
* Fix #294: `shutdown --help` mistakenly shuts down system
|
||||||
|
* Fix #310: Always use configured restart delay for crashing services.
|
||||||
|
If no delay is configured, default to an initial 2000 msec for forking
|
||||||
|
daemons and start-stop scripts, and 1 msec for non-forking daemons
|
||||||
|
* Fix #311: document how to combine device tree with conditions
|
||||||
|
* Fix #312: restart services with respawn set, e.g. ttys, immediately
|
||||||
|
* Fix #313: Cancel pending restart timer on stop/start/restart/reload
|
||||||
|
* Fix #314: skip run/task/service restart if conditions are lost
|
||||||
|
* Fix #315: add environment variables to hook scripts
|
||||||
|
|
||||||
|
All hook scripts are called with at least one environment variable
|
||||||
|
set, `FINIT_HOOK_NAME`, useful when reusing the same hook script for
|
||||||
|
multiple hook points. It is set to the string name, also used by the
|
||||||
|
path, e.g., `hook/net/up`
|
||||||
|
|
||||||
|
For all hook points from hook/sys/shutdown and later, `FINIT_SHUTDOWN`
|
||||||
|
is also set, to one of: `halt`, `poweroff`, `reboot`
|
||||||
|
|
||||||
|
* Fix #317: make sure hook scripts don't run twice, also fixes #316
|
||||||
|
* Fix #318: only show `[ OK ] Calling foo` progress for `runparts ...`
|
||||||
|
* Fix #320: the API/IPC socket is closed immediately at shutdown/reboot
|
||||||
|
to protect hook scripts or services calling initctl. There is no way
|
||||||
|
to service these requests safely at that time
|
||||||
|
* Fix #333: consider a service dirty if command line args have changed
|
||||||
|
|
||||||
|
This fixes `initctl reload` correctly restarting all daemons that have
|
||||||
|
new command line arguments.
|
||||||
|
|
||||||
|
Previously command line arguments changes were only acted upon if the
|
||||||
|
service was explicitly reloaded `initctl reload myservice`.
|
||||||
|
|
||||||
|
Found and fixed by Jack Newman
|
||||||
|
|
||||||
|
* Fix #338: ensure shutdown hooks are called properly; `hook/sys/down`
|
||||||
|
and `hook/svc/down` hook scripts, found and fixed by Jack Newman
|
||||||
|
* Fix #339: use absolute path in `/etc/finit.d/enabled/` symlinks, for
|
||||||
|
use-cases when `/etc` is read-only and `/etc/finit.d/enabled ->
|
||||||
|
/mnt/finit.d/enabled`, reported by Jack Newman
|
||||||
|
* Fix #340: Finit ignores deleted/moved `.conf` file sin `/etc/finit.d`
|
||||||
|
* Fix #342: in runlevel S (bootstrap), not all `initctl` commands can be
|
||||||
|
supported, block the following: runlevel, reload, start/stop, restart,
|
||||||
|
reload, halt, poweroff, suspend. Also, prevent `SIGHUP` and `SIGUSR1`
|
||||||
|
signals when in shutdown or reboot
|
||||||
|
* Fix #352: separate runlevel S from runlevel 0
|
||||||
|
* Fix bootmisc plugin: octal permission on `/run/lock` and `/var/lock`
|
||||||
|
|
||||||
|
* Ensure `initctl cond get` support the flux state (exit code 255)
|
||||||
|
* Fix potential socket leak at bootstrap and shutdown
|
||||||
|
* Fix potential NULL pointer deref in kernel command line parser
|
||||||
|
* Fix lingering condition in service after reload of service with new
|
||||||
|
config that has no condition
|
||||||
|
* Fix wrong path to command in service after reload, may have changed
|
||||||
|
* `logit`: fall back to package name if `$LOGNAME` and `$USER` are
|
||||||
|
unset. **Note:** you should probably not use `logit` in your own
|
||||||
|
scripts, it is only meant for internal use by Finit. We recommend
|
||||||
|
using `logger` from the `bsdutils` or `sysklogd` packages instead
|
||||||
|
* Fix issue where `env:`/`pre:`/`post:`/etc. is removed from a service
|
||||||
|
|
||||||
|
The trick is when reloading a service like this:
|
||||||
|
|
||||||
|
service env:/etc/env serv -np -e foo:bar
|
||||||
|
|
||||||
|
into this:
|
||||||
|
|
||||||
|
service pre:/bin/pre.sh serv -np
|
||||||
|
|
||||||
|
In the second the `env:` has been removed and `pre:` added. Prior to
|
||||||
|
this patch, `env:` was kept leading to unintended behavior.
|
||||||
|
* Fix parse/diff of command line args, e.g., `nginx -g 'daemon off;'`
|
||||||
|
|
||||||
|
Starting a service like this works fine:
|
||||||
|
|
||||||
|
service [2345789] env:-/etc/default/nginx nginx -g 'daemon off;'
|
||||||
|
|
||||||
|
However, on `initctl reload` (and no change to .conf files) the arg
|
||||||
|
list was lost while parsing the .conf files. Leading to a false
|
||||||
|
positive 'diff' in args causing nginx to be unnecessarily restarted.
|
||||||
|
|
||||||
|
|
||||||
[4.3][] - 2022-05-15
|
[4.3][] - 2022-05-15
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
@@ -1152,7 +1490,8 @@ Major bug fix release.
|
|||||||
|
|
||||||
* Initial release
|
* Initial release
|
||||||
|
|
||||||
[UNRELEASED]: https://github.com/troglobit/finit/compare/4.2...HEAD
|
[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.3]: https://github.com/troglobit/finit/compare/4.2...4.3
|
||||||
[4.2]: https://github.com/troglobit/finit/compare/4.1...4.2
|
[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.1]: https://github.com/troglobit/finit/compare/4.0...4.1
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||||
Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
|
Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
+4
-2
@@ -1,5 +1,5 @@
|
|||||||
ACLOCAL_AMFLAGS = -I m4
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
SUBDIRS = man plugins src test
|
SUBDIRS = man plugins src system test tmpfiles.d
|
||||||
doc_DATA = README.md LICENSE contrib/finit.conf
|
doc_DATA = README.md LICENSE contrib/finit.conf
|
||||||
EXTRA_DIST = README.md LICENSE ChangeLog.md contrib/finit.conf
|
EXTRA_DIST = README.md LICENSE ChangeLog.md contrib/finit.conf
|
||||||
|
|
||||||
@@ -30,4 +30,6 @@ release: distcheck
|
|||||||
printf "$$file.sha256\t"; cat ../$$file.sha256 | cut -f1 -d' '; \
|
printf "$$file.sha256\t"; cat ../$$file.sha256 | cut -f1 -d' '; \
|
||||||
done
|
done
|
||||||
|
|
||||||
DISTCHECK_CONFIGURE_FLAGS = --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
|
||||||
|
|||||||
@@ -37,7 +37,11 @@ Features include:
|
|||||||
* Process supervision similar to [systemd][]
|
* Process supervision similar to [systemd][]
|
||||||
* Sourcing environment files
|
* Sourcing environment files
|
||||||
* Conditions for network/process/custom dependencies
|
* Conditions for network/process/custom dependencies
|
||||||
|
* Readiness notification; PID files (native) for synchronizing system
|
||||||
|
startup, support for systemd [sd_notify()][], or [s6 style][] too
|
||||||
|
* Limited support for [tmpfiles.d(5)][] (no aging, attributes, or subvolumes)
|
||||||
* Pre/Post script actions
|
* Pre/Post script actions
|
||||||
|
* Rudimentary [templating support](doc/config.md#templating)
|
||||||
* Tooling to enable/disable services
|
* Tooling to enable/disable services
|
||||||
* Built-in getty
|
* Built-in getty
|
||||||
* Built-in watchdog, with support for hand-over to [watchdogd](https://troglobit.com/watchdogd.html)
|
* Built-in watchdog, with support for hand-over to [watchdogd](https://troglobit.com/watchdogd.html)
|
||||||
@@ -52,7 +56,8 @@ Features include:
|
|||||||
|
|
||||||
Focus is on small and embedded systems, although Finit is fully usable
|
Focus is on small and embedded systems, although Finit is fully usable
|
||||||
on server and desktop systems as well. For working examples, see the
|
on server and desktop systems as well. For working examples, see the
|
||||||
[contrib/](contrib/) section with tutorials for:
|
[contrib/](contrib/) section with tutorials for the following Linux
|
||||||
|
distributions:
|
||||||
|
|
||||||
* [Void Linux](contrib/void/),
|
* [Void Linux](contrib/void/),
|
||||||
* [Alpine Linux](contrib/alpine/), and
|
* [Alpine Linux](contrib/alpine/), and
|
||||||
@@ -70,7 +75,14 @@ Example
|
|||||||
This example `/etc/finit.conf` can also be split up in multiple `.conf`
|
This example `/etc/finit.conf` can also be split up in multiple `.conf`
|
||||||
files in `/etc/finit.d`. Available, but not yet enabled, services can
|
files in `/etc/finit.d`. Available, but not yet enabled, services can
|
||||||
be placed in `/etc/finit.d/available` and enabled by an operator using
|
be placed in `/etc/finit.d/available` and enabled by an operator using
|
||||||
the [initctl](#commands--status) tool.
|
the [initctl](#commands--status) tool. See the above mentioned Linux
|
||||||
|
distributions, or [myLinux][].
|
||||||
|
|
||||||
|
> **Note:** as of Finit v4.4, .conf lines can be broken up using the
|
||||||
|
> standard UNIX continuation character (`\`), also trailing comments are
|
||||||
|
> now supported. The latter means you need to escape any hashes used in
|
||||||
|
> directives and descriptions (`\#`). For more on this and examples,
|
||||||
|
> see the [finit.conf(5)][] manual or [doc/config.md](doc/config.md).
|
||||||
|
|
||||||
```ApacheConf
|
```ApacheConf
|
||||||
# Fallback if /etc/hostname is missing
|
# Fallback if /etc/hostname is missing
|
||||||
@@ -233,13 +245,50 @@ networking here. The configured `runlevel NUM` from `/etc/finit.conf`
|
|||||||
is what Finit changes to after bootstrap, unless 'single' (or 'S') is
|
is what Finit changes to after bootstrap, unless 'single' (or 'S') is
|
||||||
given on the kernel cmdline, in which case runlevel 1 is started.
|
given on the kernel cmdline, in which case runlevel 1 is started.
|
||||||
|
|
||||||
All services in runlevel S(0) are started first, followed by the desired
|
All services in runlevel S) are started first, followed by the desired
|
||||||
run-time runlevel. Run tasks in runlevel S can be started in sequence
|
run-time runlevel. Run tasks in runlevel S can be started in sequence
|
||||||
by using `run [S] cmd`. Changing runlevels at runtime is done like any
|
by using `run [S] cmd`. Changing runlevels at runtime is done like any
|
||||||
other init, e.g. <kbd>init 4</kbd>, but also using the more advanced
|
other init, e.g. <kbd>init 4</kbd>, but also using the more advanced
|
||||||
`intictl` tool.
|
`intictl` tool.
|
||||||
|
|
||||||
|
|
||||||
|
**Conditions**
|
||||||
|
|
||||||
|
As mentioned previously, Finit has an advanced dependency system to
|
||||||
|
handle synchronization, called [conditions](doc/conditions.md). It can
|
||||||
|
be used in many ways; depend on another service, network availability,
|
||||||
|
etc.
|
||||||
|
|
||||||
|
One *really cool* example useful for embedded systems is to run certain
|
||||||
|
scripts if a board has a certain feature encoded in its device tree. At
|
||||||
|
bootstrap we run the following `ident` script:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
#!/bin/sh
|
||||||
|
conddir=/var/run/finit/cond/hw/model
|
||||||
|
dtmodel=/sys/firmware/devicetree/base/model
|
||||||
|
|
||||||
|
if ! test -e $dtmodel; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
model=$(cat $dtmodel | tr "[A-Z] " "[a-z]-")
|
||||||
|
mkdir -p $conddir && ln -s ../../reconf $conddir/$model
|
||||||
|
```
|
||||||
|
|
||||||
|
Provided the device tree node exists, and is a string, we can then use
|
||||||
|
the condition `<hw/model/foo>` when starting other scripts. Here is an
|
||||||
|
example:
|
||||||
|
|
||||||
|
```
|
||||||
|
run [S] /path/to/ident --
|
||||||
|
task [2] <hw/model/foo> /path/to/foo-init -- Initializing Foo board
|
||||||
|
```
|
||||||
|
|
||||||
|
> Notice the trick with an empty description to hide the call to `ident`
|
||||||
|
> in the Finit progress output.
|
||||||
|
|
||||||
|
|
||||||
**Plugins**
|
**Plugins**
|
||||||
|
|
||||||
Plugins can *extend* the functionality of Finit and *hook into* the
|
Plugins can *extend* the functionality of Finit and *hook into* the
|
||||||
@@ -346,6 +395,33 @@ in [doc/plugins.md](doc/plugins.md#hooks), and about the system bootstrap
|
|||||||
in [doc/bootstrap.md](doc/bootstrap.md).
|
in [doc/bootstrap.md](doc/bootstrap.md).
|
||||||
|
|
||||||
|
|
||||||
|
### Limitations
|
||||||
|
|
||||||
|
It is not possible to call Finit via signals or use `initctl` in any
|
||||||
|
runparts or `/etc/rc.local` script. This because Finit is single
|
||||||
|
threaded and is calling these scripts in a blocking fashion at the end
|
||||||
|
of runlevel S, at which point the event loop has not yet been started.
|
||||||
|
|
||||||
|
The event loop is the whole thing which Finit is built around, except
|
||||||
|
for runlevel S, which remains a slow procession through a lot of set up,
|
||||||
|
with a few hooks and blocking call outs to external scripts.
|
||||||
|
|
||||||
|
However, not all `initctl` commands are prohibited, supported commands:
|
||||||
|
are:
|
||||||
|
|
||||||
|
- `inictl cond`: only operate of files in `/run/finit/cond`
|
||||||
|
- `initctl enable/disable`: enabled run/task/service is activated on
|
||||||
|
the runlevel change from S to 2
|
||||||
|
- `initctl touch/show/create/delete/list`: `create`, provided the
|
||||||
|
non-interactive mode is used, again changes take effect in the
|
||||||
|
runlevel change directly after bootstrap
|
||||||
|
- `initctl -f reboot/poweroff/halt`: provided the `-f` flag is used to
|
||||||
|
force direct kernel commands
|
||||||
|
|
||||||
|
**Example:** you can set a `usr/` condition in `/etc/rc.local` and have
|
||||||
|
a service/task in runlevel 2 depend on it to execute.
|
||||||
|
|
||||||
|
|
||||||
Runlevels
|
Runlevels
|
||||||
---------
|
---------
|
||||||
|
|
||||||
@@ -438,6 +514,7 @@ Options:
|
|||||||
-c, --create Create missing paths (and files) as needed
|
-c, --create Create missing paths (and files) as needed
|
||||||
-f, --force Ignore missing files and arguments, never prompt
|
-f, --force Ignore missing files and arguments, never prompt
|
||||||
-h, --help This help text
|
-h, --help This help text
|
||||||
|
-j, --json JSON output in 'status' and 'cond' commands
|
||||||
-1, --once Only one lap in commands like 'top'
|
-1, --once Only one lap in commands like 'top'
|
||||||
-p, --plain Use plain table headings, no ctrl chars
|
-p, --plain Use plain table headings, no ctrl chars
|
||||||
-q, --quiet Silent, only return status of command
|
-q, --quiet Silent, only return status of command
|
||||||
@@ -460,11 +537,11 @@ Commands:
|
|||||||
disable <CONF> Disable .conf in /etc/finit.d/enabled
|
disable <CONF> Disable .conf in /etc/finit.d/enabled
|
||||||
reload Reload *.conf in /etc/finit.d (activate changes)
|
reload Reload *.conf in /etc/finit.d (activate changes)
|
||||||
|
|
||||||
cond set <COND> Set (assert) user-defined condition +usr/COND
|
cond set <COND> Set (assert) user-defined conditions +usr/COND
|
||||||
cond get <COND> Get status of user-defined condition, see $? and -v
|
cond get <COND> Get status of user-defined condition, see $? and -v
|
||||||
cond clear <COND> Clear (deassert) user-defined condition -usr/COND
|
cond clear <COND> Clear (deassert) user-defined conditions -usr/COND
|
||||||
cond status Show condition status, default cond command
|
cond status Show condition status, default cond command
|
||||||
cond dump Dump all conditions and their status
|
cond dump [TYPE] Dump all, or a type of, conditions and their status
|
||||||
|
|
||||||
log [NAME] Show ten last Finit, or NAME, messages from syslog
|
log [NAME] Show ten last Finit, or NAME, messages from syslog
|
||||||
start <NAME>[:ID] Start service by name, with optional ID
|
start <NAME>[:ID] Start service by name, with optional ID
|
||||||
@@ -482,6 +559,8 @@ Commands:
|
|||||||
ps List processes based on cgroups
|
ps List processes based on cgroups
|
||||||
top Show top-like listing based on cgroups
|
top Show top-like listing based on cgroups
|
||||||
|
|
||||||
|
plugins List installed plugins
|
||||||
|
|
||||||
runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot
|
runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot
|
||||||
reboot Reboot system
|
reboot Reboot system
|
||||||
halt Halt system
|
halt Halt system
|
||||||
@@ -507,24 +586,24 @@ scripting and documentation:
|
|||||||
|
|
||||||
```
|
```
|
||||||
alpine:~# initctl -p
|
alpine:~# initctl -p
|
||||||
PID IDENT STATUS RUNLEVELS DESCRIPTION
|
PID IDENT STATUS RUNLEVELS DESCRIPTION
|
||||||
======================================================================
|
======================================================================
|
||||||
1506 acpid running [--2345----] ACPI daemon
|
1506 acpid running [---2345----] ACPI daemon
|
||||||
1509 crond running [--2345----] Cron daemon
|
1509 crond running [---2345----] Cron daemon
|
||||||
1489 dropbear running [--2345----] Dropbear SSH daemon
|
1489 dropbear running [---2345----] Dropbear SSH daemon
|
||||||
1511 klogd running [S12345----] Kernel log daemon
|
1511 klogd running [S-12345----] Kernel log daemon
|
||||||
1512 ntpd running [--2345----] NTP daemon
|
1512 ntpd running [---2345----] NTP daemon
|
||||||
1473 syslogd running [S12345----] Syslog daemon
|
1473 syslogd running [S-12345----] Syslog daemon
|
||||||
|
|
||||||
alpine:~# initctl -pv
|
alpine:~# initctl -pv
|
||||||
PID IDENT STATUS RUNLEVELS COMMAND
|
PID IDENT STATUS RUNLEVELS COMMAND
|
||||||
======================================================================
|
======================================================================
|
||||||
1506 acpid running [--2345----] acpid -f
|
1506 acpid running [---2345----] acpid -f
|
||||||
1509 crond running [--2345----] crond -f -S $CRON_OPTS
|
1509 crond running [---2345----] crond -f -S $CRON_OPTS
|
||||||
1489 dropbear running [--2345----] dropbear -R -F $DROPBEAR_OPTS
|
1489 dropbear running [---2345----] dropbear -R -F $DROPBEAR_OPTS
|
||||||
1511 klogd running [S12345----] klogd -n $KLOGD_OPTS
|
1511 klogd running [S-12345----] klogd -n $KLOGD_OPTS
|
||||||
1512 ntpd running [--2345----] ntpd -n $NTPD_OPTS
|
1512 ntpd running [---2345----] ntpd -n $NTPD_OPTS
|
||||||
1473 syslogd running [S12345----] syslogd -n
|
1473 syslogd running [S-12345----] syslogd -n
|
||||||
```
|
```
|
||||||
|
|
||||||
The environment variables to each of the services above are read from,
|
The environment variables to each of the services above are read from,
|
||||||
@@ -549,7 +628,7 @@ Condition(s):
|
|||||||
User : root
|
User : root
|
||||||
Group : root
|
Group : root
|
||||||
Uptime : 2 hour 46 min 56 sec
|
Uptime : 2 hour 46 min 56 sec
|
||||||
Runlevels : [--2345----]
|
Runlevels : [---2345----]
|
||||||
Memory : 1.2M
|
Memory : 1.2M
|
||||||
CGroup : /system/dropbear cpu 0 [100, max] mem [--.--, max]
|
CGroup : /system/dropbear cpu 0 [100, max] mem [--.--, max]
|
||||||
|- 1485 dropbear -R -F
|
|- 1485 dropbear -R -F
|
||||||
@@ -620,11 +699,15 @@ and proposed extensions.
|
|||||||
[upstart]: https://upstart.ubuntu.com/
|
[upstart]: https://upstart.ubuntu.com/
|
||||||
[systemd]: https://www.freedesktop.org/wiki/Software/systemd/
|
[systemd]: https://www.freedesktop.org/wiki/Software/systemd/
|
||||||
[openrc]: https://www.gentoo.org/proj/en/base/openrc/
|
[openrc]: https://www.gentoo.org/proj/en/base/openrc/
|
||||||
|
[sd_notify()]: https://www.freedesktop.org/software/systemd/man/sd_notify.html
|
||||||
|
[s6 style]: https://skarnet.org/software/s6/notifywhenup.html
|
||||||
[run-parts(8)]: https://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
[run-parts(8)]: https://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
||||||
|
[tmpfiles.d(5)]: https://www.freedesktop.org/software/systemd/man/tmpfiles.d.html
|
||||||
[original finit]: http://helllabs.org/finit/
|
[original finit]: http://helllabs.org/finit/
|
||||||
[EeePC fastinit]: https://web.archive.org/web/20071208212450/http://wiki.eeeuser.com/boot_process:the_boot_process
|
[EeePC fastinit]: https://web.archive.org/web/20071208212450/http://wiki.eeeuser.com/boot_process:the_boot_process
|
||||||
[Claudio Matsuoka]: https://github.com/cmatsuoka
|
[Claudio Matsuoka]: https://github.com/cmatsuoka
|
||||||
[Joachim Wiberg]: https://troglobit.com
|
[Joachim Wiberg]: https://troglobit.com
|
||||||
|
[finit.conf(5)]: https://man.troglobit.com/man5/finit.conf.5.html
|
||||||
[License]: https://en.wikipedia.org/wiki/MIT_License
|
[License]: https://en.wikipedia.org/wiki/MIT_License
|
||||||
[License Badge]: https://img.shields.io/badge/License-MIT-teal.svg
|
[License Badge]: https://img.shields.io/badge/License-MIT-teal.svg
|
||||||
[myLinux]: https://github.com/troglobit/myLinux/
|
[myLinux]: https://github.com/troglobit/myLinux/
|
||||||
|
|||||||
+48
-10
@@ -1,10 +1,10 @@
|
|||||||
AC_INIT(Finit, 4.3, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/projects/finit/)
|
AC_INIT([Finit],[4.4-rc2],[https://github.com/troglobit/finit/issues],[finit],[https://troglobit.com/projects/finit/])
|
||||||
AC_CONFIG_AUX_DIR(aux)
|
AC_CONFIG_AUX_DIR(aux)
|
||||||
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
|
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
|
||||||
AM_SILENT_RULES([yes])
|
AM_SILENT_RULES([yes])
|
||||||
|
|
||||||
AC_CONFIG_SRCDIR([src/finit.c])
|
AC_CONFIG_SRCDIR([src/finit.c])
|
||||||
AC_CONFIG_HEADER([config.h])
|
AC_CONFIG_HEADERS([config.h])
|
||||||
AC_CONFIG_FILES([Makefile
|
AC_CONFIG_FILES([Makefile
|
||||||
contrib/Makefile
|
contrib/Makefile
|
||||||
contrib/alpine/Makefile contrib/alpine/finit.d/Makefile contrib/alpine/finit.d/available/Makefile
|
contrib/alpine/Makefile contrib/alpine/finit.d/Makefile contrib/alpine/finit.d/available/Makefile
|
||||||
@@ -14,8 +14,10 @@ AC_CONFIG_FILES([Makefile
|
|||||||
man/Makefile
|
man/Makefile
|
||||||
plugins/Makefile
|
plugins/Makefile
|
||||||
src/Makefile
|
src/Makefile
|
||||||
|
system/Makefile
|
||||||
|
tmpfiles.d/Makefile
|
||||||
test/test.env test/Makefile
|
test/test.env test/Makefile
|
||||||
test/tenv/Makefile test/common/Makefile])
|
test/lib/Makefile test/src/Makefile])
|
||||||
|
|
||||||
# Older versions of autoconf (<2.58) do not have AC_CONFIG_MACRO_DIR()
|
# Older versions of autoconf (<2.58) do not have AC_CONFIG_MACRO_DIR()
|
||||||
#m4_include([m4/plugin.m4])
|
#m4_include([m4/plugin.m4])
|
||||||
@@ -32,7 +34,6 @@ AC_PROG_INSTALL
|
|||||||
AC_PROG_MKDIR_P
|
AC_PROG_MKDIR_P
|
||||||
|
|
||||||
# Configuration.
|
# Configuration.
|
||||||
AC_HEADER_STDC
|
|
||||||
AC_CHECK_HEADERS([termios.h sys/ioctl.h mntent.h sys/sysmacros.h])
|
AC_CHECK_HEADERS([termios.h sys/ioctl.h mntent.h sys/sysmacros.h])
|
||||||
AC_CHECK_FUNCS([strstr getopt getmntent getmntent_r])
|
AC_CHECK_FUNCS([strstr getopt getmntent getmntent_r])
|
||||||
|
|
||||||
@@ -82,7 +83,9 @@ AC_ARG_ENABLE(contrib,
|
|||||||
enable_contrib=yes])
|
enable_contrib=yes])
|
||||||
|
|
||||||
# Check for extra plugins to enable
|
# Check for extra plugins to enable
|
||||||
enable_all_plugins=auto
|
AC_ARG_ENABLE(all_plugins,
|
||||||
|
AS_HELP_STRING([--enable-all-plugins], [Enable all plugins, default: auto]),
|
||||||
|
enable_all_plugins=$enableval, enable_all_plugins=auto)
|
||||||
AC_PLUGIN([alsa-utils], [no], [Save and restore ALSA sound settings using alsactl])
|
AC_PLUGIN([alsa-utils], [no], [Save and restore ALSA sound settings using alsactl])
|
||||||
AC_PLUGIN([dbus], [no], [Setup and start system message bus, D-Bus])
|
AC_PLUGIN([dbus], [no], [Setup and start system message bus, D-Bus])
|
||||||
AC_PLUGIN([modules-load], [no], [Scans /etc/modules-load.d for modules to load])
|
AC_PLUGIN([modules-load], [no], [Scans /etc/modules-load.d for modules to load])
|
||||||
@@ -95,6 +98,7 @@ AC_PLUGIN([hotplug], [yes], [Setup and start udev or mdev hotplug daemon])
|
|||||||
AC_PLUGIN([rtc], [yes], [Save and restore RTC using hwclock])
|
AC_PLUGIN([rtc], [yes], [Save and restore RTC using hwclock])
|
||||||
AC_PLUGIN([tty], [yes], [Automatically activate new TTYs, e.g. USB-to-serial])
|
AC_PLUGIN([tty], [yes], [Automatically activate new TTYs, e.g. USB-to-serial])
|
||||||
AC_PLUGIN([urandom], [yes], [Setup and save random seed at boot/shutdown])
|
AC_PLUGIN([urandom], [yes], [Setup and save random seed at boot/shutdown])
|
||||||
|
AC_PLUGIN([testserv], [no], [Test plugin to start test serv daemon])
|
||||||
|
|
||||||
# Check for extra arguments or packages
|
# Check for extra arguments or packages
|
||||||
AC_ARG_WITH(fstab,
|
AC_ARG_WITH(fstab,
|
||||||
@@ -151,6 +155,13 @@ AC_ARG_WITH(hook-scripts-path,
|
|||||||
AS_HELP_STRING([--with-hook-scripts-path=DIR], [Base directory for hook scripts, default $libexecdir/finit/hook]),
|
AS_HELP_STRING([--with-hook-scripts-path=DIR], [Base directory for hook scripts, default $libexecdir/finit/hook]),
|
||||||
[hook_scripts_path=$withval], [hook_scripts_path=yes])
|
[hook_scripts_path=$withval], [hook_scripts_path=yes])
|
||||||
|
|
||||||
|
AC_ARG_WITH(plugin-path,
|
||||||
|
AS_HELP_STRING([--with-plugin-path=DIR], [Search path for external plugins, default /usr/lib/finit/plugins:/usr/local/lib/finit/plugins]),
|
||||||
|
[plugin_path=$withval], [plugin_path=yes])
|
||||||
|
|
||||||
|
AC_ARG_WITH(rtc-date,
|
||||||
|
AS_HELP_STRING([--with-rtc-date=DATE], [If RTC date/time is too old, restore to DATE, format "YYYY-MM-DD HH:MM", default "2000-01-01 00:00"]),
|
||||||
|
[rtc_date=$withval], [rtc_date=no])
|
||||||
|
|
||||||
### Enable features ###########################################################################
|
### Enable features ###########################################################################
|
||||||
|
|
||||||
@@ -235,6 +246,10 @@ AS_IF([test "x$with_random_seed" != "xno"], [
|
|||||||
AC_EXPAND_DIR(random_path, "$random_seed")
|
AC_EXPAND_DIR(random_path, "$random_seed")
|
||||||
AC_DEFINE_UNQUOTED(RANDOMSEED, "$random_path", [Improve random at boot by seeding it with sth from before.])])
|
AC_DEFINE_UNQUOTED(RANDOMSEED, "$random_path", [Improve random at boot by seeding it with sth from before.])])
|
||||||
|
|
||||||
|
AS_IF([test "x$rtc_date" != "xno"], [
|
||||||
|
AC_DEFINE(RTC_TIMESTAMP_CUSTOM, "$rtc_date", [Custom RTC restore date, default: 2000-01-01 00:00])], [
|
||||||
|
rtc_date=""])
|
||||||
|
|
||||||
AS_IF([test "x$with_keventd" != "xno"], [with_keventd=yes])
|
AS_IF([test "x$with_keventd" != "xno"], [with_keventd=yes])
|
||||||
|
|
||||||
AS_IF([test "x$with_sulogin" != "xno"], [with_sulogin=yes])
|
AS_IF([test "x$with_sulogin" != "xno"], [with_sulogin=yes])
|
||||||
@@ -246,11 +261,16 @@ AS_IF([test "x$with_watchdog" != "xno"], [
|
|||||||
AC_DEFINE_UNQUOTED(WDT_DEVNODE, "$watchdog", [Built-in watchdog device node])], [
|
AC_DEFINE_UNQUOTED(WDT_DEVNODE, "$watchdog", [Built-in watchdog device node])], [
|
||||||
watchdog=])
|
watchdog=])
|
||||||
|
|
||||||
AS_IF([test "x$enable_hook_scripts_plugin" = "xyes" -a "x$with_hook_scripts_path" != "xno"], [
|
AS_IF([test "x$enable_hook_scripts_plugin" != "xno"], [
|
||||||
AS_IF([test "x$hook_scripts_path" = "xyes"], [hook_scripts_path=$libexecdir/finit/hook])
|
AS_IF([test "x$hook_scripts_path" = "xyes"], [hook_scripts_path=$libexecdir/finit/hook])
|
||||||
AC_EXPAND_DIR(hook_scripts_path, "$hook_scripts_path")
|
AC_EXPAND_DIR(hook_scripts_path, "$hook_scripts_path")
|
||||||
AC_DEFINE_UNQUOTED(PLUGIN_HOOK_SCRIPTS_PATH, "$hook_scripts_path", [Built-in default: $libexecdir/finit])])
|
AC_DEFINE_UNQUOTED(PLUGIN_HOOK_SCRIPTS_PATH, "$hook_scripts_path", [Built-in default: $libexecdir/finit])])
|
||||||
|
|
||||||
|
AS_IF([test "x$with_plugin_path" != "xno"], [
|
||||||
|
AS_IF([test "x$plugin_path" = "xyes"], [plugin_path=/usr/lib/finit/plugins:/usr/local/lib/finit/plugins])
|
||||||
|
AC_EXPAND_DIR(plugin_path, "$plugin_path")
|
||||||
|
AC_DEFINE_UNQUOTED(EXTERNAL_PLUGIN_PATH, "$plugin_path", [Built-in default: /usr/lib/finit/plugins:/usr/local/lib/finit/plugins])])
|
||||||
|
|
||||||
# Control build with automake flags
|
# Control build with automake flags
|
||||||
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
||||||
AM_CONDITIONAL(KEVENTD, [test "x$with_keventd" != "xno"])
|
AM_CONDITIONAL(KEVENTD, [test "x$with_keventd" != "xno"])
|
||||||
@@ -258,25 +278,42 @@ AM_CONDITIONAL(SULOGIN, [test "x$with_sulogin" != "xno"])
|
|||||||
AM_CONDITIONAL(WATCHDOGD, [test "x$with_watchdog" != "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(CONTRIB, [test "x$enable_contrib" = "xyes"])
|
||||||
|
AM_CONDITIONAL(TESTSERV, [test "x$enable_testserv_plugin" = "xyes"])
|
||||||
|
|
||||||
# Override default libdir, used for plugins and rescue.conf
|
# Override default libdir, used for plugins and rescue.conf
|
||||||
pkglibdir=$libdir/finit
|
pkglibdir=$libdir/finit
|
||||||
AC_SUBST(pkglibexecdir)
|
AC_SUBST(pkglibexecdir)
|
||||||
AC_EXPAND_DIR(pkglibexecdir, "$libexecdir/finit")
|
AC_EXPAND_DIR(pkglibexecdir, "$libexecdir/finit")
|
||||||
AC_DEFINE_UNQUOTED(FINIT_LIBPATH_, "$pkglibexecdir", [Finit libexec path])
|
AC_DEFINE_UNQUOTED(FINIT_EXECPATH_, "$pkglibexecdir", [Finit libexec path])
|
||||||
|
|
||||||
AC_EXPAND_DIR(plugin_path, "$libdir/finit/plugins")
|
AC_EXPAND_DIR(plugin_path, "$pkglibdir/plugins")
|
||||||
AC_SUBST(plugin_path)
|
AC_SUBST(plugin_path)
|
||||||
AC_DEFINE_UNQUOTED(PLUGIN_PATH, "$plugin_path", [Finit plugin path])
|
AC_DEFINE_UNQUOTED(PLUGIN_PATH, "$plugin_path", [Finit plugin path])
|
||||||
|
|
||||||
AC_EXPAND_DIR(rescue_conf, "$libdir/finit/rescue.conf")
|
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_EXPAND_DIR(finit_tmpfiles, "$pkglibdir/tmpfiles.d")
|
||||||
|
AC_SUBST(finit_tmpfiles)
|
||||||
|
AC_DEFINE_UNQUOTED(FINIT_TMPFILES, "$finit_tmpfiles", [Finit tmpfiles.d/ .conf path])
|
||||||
|
|
||||||
|
AC_EXPAND_DIR(system_path, "$pkglibdir/system")
|
||||||
|
AC_SUBST(system_path)
|
||||||
|
AC_DEFINE_UNQUOTED(FINIT_SYSPATH, "$system_path", [Static services, previously generated at runtime by plugins])
|
||||||
|
|
||||||
|
AC_EXPAND_DIR(rescue_conf, "$pkglibdir/rescue.conf")
|
||||||
AC_DEFINE_UNQUOTED(RESCUE_CONF, "$rescue_conf", [Finit rescue mode .conf])
|
AC_DEFINE_UNQUOTED(RESCUE_CONF, "$rescue_conf", [Finit rescue mode .conf])
|
||||||
AC_EXPAND_DIR(sample_conf, "$libdir/finit/sample.conf")
|
AC_EXPAND_DIR(sample_conf, "$pkglibdir/sample.conf")
|
||||||
AC_DEFINE_UNQUOTED(SAMPLE_CONF, "$sample_conf", [Finit sameple.conf for initctl create])
|
AC_DEFINE_UNQUOTED(SAMPLE_CONF, "$sample_conf", [Finit sameple.conf for initctl create])
|
||||||
|
|
||||||
AS_IF([test "$heading" = ""], [heading="<DEFAULT>"])
|
AS_IF([test "$heading" = ""], [heading="<DEFAULT>"])
|
||||||
AS_IF([test "$heading" = "no"], [heading="<NONE>"])
|
AS_IF([test "$heading" = "no"], [heading="<NONE>"])
|
||||||
|
|
||||||
|
RTC_DATE=$rtc_date
|
||||||
|
AS_IF([test "$rtc_date" = ""], [RTC_DATE="<DEFAULT>"])
|
||||||
|
AS_IF([test "$rtc_date" = "no"], [RTC_DATE="<DEFAULT>"])
|
||||||
|
|
||||||
# Generate all files
|
# Generate all files
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|
||||||
@@ -301,6 +338,7 @@ cat <<EOF
|
|||||||
Behavior:
|
Behavior:
|
||||||
Boot heading..........: $heading
|
Boot heading..........: $heading
|
||||||
Plugins...............: $plugins
|
Plugins...............: $plugins
|
||||||
|
RTC restore date......: $RTC_DATE
|
||||||
|
|
||||||
Optional features:
|
Optional features:
|
||||||
Install doc/..........: $enable_doc
|
Install doc/..........: $enable_doc
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig ./configure \
|
|||||||
--sysconfdir=/etc --localstatedir=/var \
|
--sysconfdir=/etc --localstatedir=/var \
|
||||||
--enable-dbus-plugin --enable-x11-common-plugin \
|
--enable-dbus-plugin --enable-x11-common-plugin \
|
||||||
--enable-alsa-utils-plugin --with-watchdog \
|
--enable-alsa-utils-plugin --with-watchdog \
|
||||||
--with-keventd
|
--with-keventd --with-sulogin
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "*** Building ..."
|
echo "*** Building ..."
|
||||||
@@ -35,4 +35,3 @@ fi
|
|||||||
echo
|
echo
|
||||||
echo "*** Done"
|
echo "*** Done"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,3 @@ else
|
|||||||
echo "*** Use 'sudo contrib/debian/install.sh' later to install Finit"
|
echo "*** Use 'sudo contrib/debian/install.sh' later to install Finit"
|
||||||
echo
|
echo
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig ./configure \
|
|||||||
--sysconfdir=/etc --localstatedir=/var \
|
--sysconfdir=/etc --localstatedir=/var \
|
||||||
--enable-dbus-plugin --enable-x11-common-plugin \
|
--enable-dbus-plugin --enable-x11-common-plugin \
|
||||||
--enable-alsa-utils-plugin --with-watchdog \
|
--enable-alsa-utils-plugin --with-watchdog \
|
||||||
--with-keventd
|
--with-keventd --with-sulogin
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "*** Building ..."
|
echo "*** Building ..."
|
||||||
@@ -35,4 +35,3 @@ fi
|
|||||||
echo
|
echo
|
||||||
echo "*** Done"
|
echo "*** Done"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -65,7 +65,7 @@ Below are a few of the main switches to configure:
|
|||||||
|
|
||||||
* `--enable-x11-common-plugin`: Enable the optional X Window `x11-common.so` plugin.
|
* `--enable-x11-common-plugin`: Enable the optional X Window `x11-common.so` plugin.
|
||||||
|
|
||||||
* `--with-sulgin`: Enable bundled `sulogin` program. Default is to use the
|
* `--with-sulogin`: Enable bundled `sulogin` program. Default is to use the
|
||||||
system `sulogin(8)`. The sulogin shipped with Finit *allows password-less*
|
system `sulogin(8)`. The sulogin shipped with Finit *allows password-less*
|
||||||
login if the `root` user is disabled or has no password at all.
|
login if the `root` user is disabled or has no password at all.
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,27 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
|
|||||||
* `debug`: Enable kernel debug. Debug messages are printed to the
|
* `debug`: Enable kernel debug. Debug messages are printed to the
|
||||||
console until Finit starts up, unless `loglevel=7` (below) is used.
|
console until Finit starts up, unless `loglevel=7` (below) is used.
|
||||||
|
|
||||||
|
* `finit.cond=foo[,bar[,baz]]`: set `<boot/foo>` condition, optionally
|
||||||
|
multiple conditions can be set using the same option, separated with a
|
||||||
|
comma. Alternatively, multiple `foo.cond=arg` can be given. Each will
|
||||||
|
result in a `<boot/arg>` condition being set to control the rest of the
|
||||||
|
system bootstrap.
|
||||||
|
|
||||||
|
Very useful for selecting different boot modes, e.g. manufacturing test,
|
||||||
|
firmware upgrade, or rescue mode.
|
||||||
|
|
||||||
|
> Note: `<boot/...>` conditions cannot be cleared with `initctl`!
|
||||||
|
|
||||||
|
* `finit.config=/path/to/alternative/finit.conf`: override the
|
||||||
|
compile-time bootstrap config file, default:
|
||||||
|
|
||||||
|
./configure --with-config=/etc/finit.conf
|
||||||
|
|
||||||
|
Useful when starting up in various rescue mode, factory, or
|
||||||
|
production test setups. Use the top-level configuration file
|
||||||
|
directive `rcsd /path/to/finit.d` to override the default
|
||||||
|
rcS.d directory.
|
||||||
|
|
||||||
* `finit.debug[=bool]`: Enable finit debug. This is operated
|
* `finit.debug[=bool]`: Enable finit debug. This is operated
|
||||||
independently of the kernel `debug` setting. New as of Finit v4.
|
independently of the kernel `debug` setting. New as of Finit v4.
|
||||||
|
|
||||||
|
|||||||
+48
-19
@@ -13,9 +13,9 @@ Finit Conditions
|
|||||||
Introduction
|
Introduction
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Conditions are a new addition to Finit, introduced in v3, with the
|
Conditions are a relatively new addition to Finit, introduced in v3,
|
||||||
intention of providing a mechanism for common synchronization problems.
|
with the intention of providing a mechanism for common synchronization
|
||||||
For example:
|
problems. For example:
|
||||||
|
|
||||||
- *"wait for service A to start before starting service B"*, or
|
- *"wait for service A to start before starting service B"*, or
|
||||||
- *"wait for basic network access to be available"*
|
- *"wait for basic network access to be available"*
|
||||||
@@ -35,7 +35,7 @@ service to run.
|
|||||||
In this example the Network monitor daemon `netd` is not started until
|
In this example the Network monitor daemon `netd` is not started until
|
||||||
both the `pid/setupd` *and* `pid/zebra` conditions are satisfied. A
|
both the `pid/setupd` *and* `pid/zebra` conditions are satisfied. A
|
||||||
`pid/` condition is satisfied by the corresponding service's PID file
|
`pid/` condition is satisfied by the corresponding service's PID file
|
||||||
being created.
|
being created, i.e., the service's default readiness notification.
|
||||||
|
|
||||||
**NOTE:** Conditions also stop services when a condition is no longer
|
**NOTE:** Conditions also stop services when a condition is no longer
|
||||||
asserted. I.e., if the Zebra process above stops or restarts, netd
|
asserted. I.e., if the Zebra process above stops or restarts, netd
|
||||||
@@ -46,11 +46,16 @@ Triggering
|
|||||||
----------
|
----------
|
||||||
|
|
||||||
Conditions are mainly triggered (asserted) by built-in plugins, e.g.,
|
Conditions are mainly triggered (asserted) by built-in plugins, e.g.,
|
||||||
`netlink.so` and `pidfile.so`, see below for built-in conditions. Finit
|
|
||||||
also supports user-defined conditions, sometimes referred to as static
|
- `netlink.so`: provides `<net/...>`
|
||||||
or one-shot conditions. They live in the `<usr/...` namespace and are
|
- `pidfile.so`: provides `<pid/...>`
|
||||||
constrained to a flat hierarchy without any sub-directories, unlike the
|
- Cmdline `finit.cond=arg`: provides `<boot/arg>`
|
||||||
pidfile plugin, for instance.
|
|
||||||
|
See below for built-in conditions. Finit also supports user-defined
|
||||||
|
conditions, sometimes referred to as static or one-shot conditions.
|
||||||
|
They live in the `<usr/...>` namespace and are constrained to a flat
|
||||||
|
hierarchy without any sub-directories, unlike the pidfile plugin, for
|
||||||
|
instance.
|
||||||
|
|
||||||
User-defined conditions are controlled using the `initctl cond set` and
|
User-defined conditions are controlled using the `initctl cond set` and
|
||||||
`initctl cond clear` commands:
|
`initctl cond clear` commands:
|
||||||
@@ -87,15 +92,35 @@ Static (one-shot) conditions, like `usr/`, never enter the `flux` state.
|
|||||||
Built-in Conditions
|
Built-in Conditions
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
Finit comes with a set of plugins for conditions: `pidfile`, `netlink`,
|
Finit comes with a set of plugins for conditions:
|
||||||
`sys`, and `usr`. The `pidfile` plugin (recursively) watches `/run/`
|
|
||||||
(recursively) for PID files created by the monitored services, and sets
|
- `devmon` (built-in)
|
||||||
a corresponding condition in the `pid/` namespace. Similarly, the
|
- `netlink`
|
||||||
`netlink` plugin provides basic conditions for when an interface is
|
- `pidfile`
|
||||||
brought up/down and when a default route (gateway) is set, in the `net/`
|
- `sys`
|
||||||
namespace. The `sys` and `usr` plugins monitor are passive condition
|
- `usr`
|
||||||
monitors where the action is provided by `keventd`, signal handlers,
|
|
||||||
and in the case of `usr`, the end-user via the `initctl` tool
|
The `devmon` (built-in) plugin monitors `/dev` and `/dev/dir` for device
|
||||||
|
nodes being created and removed. It is active only when a run, task, or
|
||||||
|
service has declared a `<dev/foo>` or `<dev/dir/bar>` condition.
|
||||||
|
|
||||||
|
The `pidfile` plugin (recursively) watches `/run/` (recursively) for PID
|
||||||
|
files created by the monitored services, and sets a corresponding
|
||||||
|
condition in the `pid/` namespace.
|
||||||
|
|
||||||
|
Similarly, the `netlink` plugin provides basic conditions for when an
|
||||||
|
interface is brought up/down and when a default route (gateway) is set,
|
||||||
|
in the `net/` namespace.
|
||||||
|
|
||||||
|
The `sys` and `usr` plugins monitor are passive condition monitors where
|
||||||
|
the action is provided by `keventd`, signal handlers, and in the case of
|
||||||
|
`usr`, the end-user via the `initctl` tool.
|
||||||
|
|
||||||
|
Additionally, the various states of a run/task/sysv/service can also be
|
||||||
|
used as conditions, the image above shows the state names. The syntax
|
||||||
|
for a `service` type process: `<service/foo/STATE>`. The other types,
|
||||||
|
in particular run/task/sysv, there are the additional states `success`
|
||||||
|
and `failure`.
|
||||||
|
|
||||||
With the example listed above, finit does not start the `/sbin/netd`
|
With the example listed above, finit does not start the `/sbin/netd`
|
||||||
daemon until `setupd` and `zebra` has started *and* created their PID
|
daemon until `setupd` and `zebra` has started *and* created their PID
|
||||||
@@ -114,10 +139,14 @@ Built-in conditions:
|
|||||||
- `net/<IFNAME>/exist`
|
- `net/<IFNAME>/exist`
|
||||||
- `net/<IFNAME>/up`
|
- `net/<IFNAME>/up`
|
||||||
- `net/<IFNAME>/running`
|
- `net/<IFNAME>/running`
|
||||||
|
- `service/<NAME[:ID]>/<STATE>`
|
||||||
|
- `{run, task, sysv}/<NAME[:ID]>/{<STATE>, success, failure}`
|
||||||
- `sys/pwr/ac`
|
- `sys/pwr/ac`
|
||||||
- `sys/pwr/fail`
|
- `sys/pwr/fail`
|
||||||
- `sys/key/ctrlaltdel`
|
- `sys/key/ctrlaltdel`
|
||||||
- `usr/foo`
|
- `usr/foo`
|
||||||
|
- `boot/arg`
|
||||||
|
- `dev/node` and `dev/dir/node`
|
||||||
|
|
||||||
**Note:** `up` means administratively up, the interface flag `IFF_UP`.
|
**Note:** `up` means administratively up, the interface flag `IFF_UP`.
|
||||||
`running` is the `IFF_RUNNING` flag, meaning operatively up. The
|
`running` is the `IFF_RUNNING` flag, meaning operatively up. The
|
||||||
@@ -163,7 +192,7 @@ Debugging
|
|||||||
If a service is not being started as it should, the problem might be
|
If a service is not being started as it should, the problem might be
|
||||||
that one of its conditions is not in the expected state. Use the
|
that one of its conditions is not in the expected state. Use the
|
||||||
command `initctl status` to inspect service status. Services in the
|
command `initctl status` to inspect service status. Services in the
|
||||||
`ready` state are pending a condition.
|
`waiting` state are pending a condition.
|
||||||
|
|
||||||
In that situation, running `initctl cond show` reveals which of the
|
In that situation, running `initctl cond show` reveals which of the
|
||||||
conditions that are not satisfied. Listed as `off` below.
|
conditions that are not satisfied. Listed as `off` below.
|
||||||
|
|||||||
+424
-46
@@ -1,14 +1,21 @@
|
|||||||
Configuration
|
Finit Configuration
|
||||||
=============
|
===================
|
||||||
|
|
||||||
* [Introduction](#introduction)
|
* [Introduction](#introduction)
|
||||||
|
* [Configuration Files](#configuration-files)
|
||||||
|
* [Runlevels](#runlevels)
|
||||||
|
* [Managing Services](#managing-services)
|
||||||
|
* [Environment Variables](#environment-variables)
|
||||||
* [Service Environment](#service-environment)
|
* [Service Environment](#service-environment)
|
||||||
|
* [Service Synchronization](#service-synchronization)
|
||||||
* [Service Wrapper Scripts](#service-wrapper-scripts)
|
* [Service Wrapper Scripts](#service-wrapper-scripts)
|
||||||
|
* [Templating](#templating)
|
||||||
* [Cgroups](#cgroups)
|
* [Cgroups](#cgroups)
|
||||||
* [Configuration File Syntax](#configuration-file-syntax)
|
* [Configuration File Syntax](#configuration-file-syntax)
|
||||||
* [Hostname](#hostname)
|
* [Hostname](#hostname)
|
||||||
* [Kernel Modules](#kernel-modules)
|
* [Kernel Modules](#kernel-modules)
|
||||||
* [Networking](#networking)
|
* [Networking](#networking)
|
||||||
|
* [Alternate rcS.d/](#alternate-rcs-d-)
|
||||||
* [Resource Limits](#resource-limits)
|
* [Resource Limits](#resource-limits)
|
||||||
* [Runlevels](#runlevels)
|
* [Runlevels](#runlevels)
|
||||||
* [One-shot Commands (sequence)](#one-shot-commands--sequence-)
|
* [One-shot Commands (sequence)](#one-shot-commands--sequence-)
|
||||||
@@ -32,29 +39,154 @@ Configuration
|
|||||||
Introduction
|
Introduction
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Finit can be configured using only the original `/etc/finit.conf` file
|
Finit is a process starter and service monitor designed to run as PID 1
|
||||||
or in combination with `/etc/finit.d/*.conf`. Useful for package-based
|
on Linux. It consists of [plugins](plugins.md) and configuration files.
|
||||||
Linux distributions -- each package can provide its own "script" file.
|
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).
|
||||||
|
|
||||||
- `/etc/finit.conf`: main configuration file
|
|
||||||
- `/etc/finit.d/*.conf`: snippets, usually one service per file
|
|
||||||
|
|
||||||
Not all configuration directives are available in `/etc/finit.d/*.conf`
|
### Configuration Files
|
||||||
and some directives are only available at [bootstrap][], runlevel `S`,
|
|
||||||
see the section [Limitations](#limitations) below for details.
|
|
||||||
|
|
||||||
To add a new service, drop a `.conf` file in `/etc/finit.d` and run
|
Originally Finit was configured using a single file, `/etc/finit.conf`.
|
||||||
`initctl reload`. (It is also possible to `SIGHUP` to PID 1, or call
|
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.
|
||||||
|
|
||||||
|
/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
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
> **Note:** the `finit.conf` and `finit.d/` names are only defaults.
|
||||||
|
> They can be changed at compile-time with two `configure` options:
|
||||||
|
> `--with-config=/etc/foo.conf` and `--with-rcsd=/var/foo.d`.
|
||||||
|
>
|
||||||
|
> They can also be overridden from the [kernel command line](cmdline.md)
|
||||||
|
> using: `-- finit.config=/etc/bar.conf` and in that file use the
|
||||||
|
> top-level configuration directive `rcsd /path/to/finit.d`.
|
||||||
|
|
||||||
|
|
||||||
|
### Filesystem Layout
|
||||||
|
|
||||||
|
Finit is most comfortable with a traditional style Linux filesystem
|
||||||
|
layout, as specified in the [FHS][]:
|
||||||
|
|
||||||
|
/.
|
||||||
|
|- bin/
|
||||||
|
|- dev/ # Mounted automatically if devtmpfs is available
|
||||||
|
| |- pts/ # Mounted automatically by Finit if it exists
|
||||||
|
| `- shm/ # Mounted automatically by Finit if it exists
|
||||||
|
|- etc/
|
||||||
|
| |- finit.d/
|
||||||
|
| | |- available/
|
||||||
|
| | `- enabled/
|
||||||
|
| `- finit.conf
|
||||||
|
|- home/
|
||||||
|
|- lib/
|
||||||
|
|- libexec/
|
||||||
|
|- mnt/
|
||||||
|
|- proc/ # Mounted automatically by Finit if it exists
|
||||||
|
|- root/
|
||||||
|
|- run/ # Mounted automatically by Finit if it exists
|
||||||
|
| `- lock/ # Created automatically if Finit mounts /run
|
||||||
|
|- sbin/
|
||||||
|
|- sys/ # Mounted automatically by Finit if it exists
|
||||||
|
|- tmp/ # Mounted automatically by Finit if it exists
|
||||||
|
|- usr/
|
||||||
|
`- var/
|
||||||
|
|- cache/
|
||||||
|
|- db/
|
||||||
|
|- lib/
|
||||||
|
| `- misc/
|
||||||
|
|- lock/
|
||||||
|
|- log/
|
||||||
|
|- run -> ../run
|
||||||
|
|- spool/
|
||||||
|
`- tmp/
|
||||||
|
|
||||||
|
Finit starts (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
|
||||||
|
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.
|
||||||
|
|
||||||
|
With all filesystems mounted, Finit calls `swapon`.
|
||||||
|
|
||||||
|
At shutdown, and after having stopped all services and other lingering
|
||||||
|
processes killed, filesystems are unmounted in the reverse order, and
|
||||||
|
`swapoff` is called.
|
||||||
|
|
||||||
|
[FHS]: https://refspecs.linuxfoundation.org/FHS_3.0/fhs/index.html
|
||||||
|
|
||||||
|
### Runlevels
|
||||||
|
|
||||||
|
- ` S`: bootStrap
|
||||||
|
- ` 1`: Single user mode
|
||||||
|
- `2-5`: traditional multi-user mode
|
||||||
|
- ` 6`: reboot
|
||||||
|
- `7-9`: multi-user mode (extra)
|
||||||
|
- ` 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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
> **Note:** when moving from runlevel S to 2, all run/task/services that
|
||||||
|
> were constrained to runlevel S only are dropped from bookkeeping. So
|
||||||
|
> when reaching the prompt, `initctl` will not show these run/tasks.
|
||||||
|
> This is a safety mechanism to prevent bootstrap-only tasks from
|
||||||
|
> accidentally being run again. E.g., `console-setup.sh` above.
|
||||||
|
|
||||||
|
|
||||||
|
### Managing Services
|
||||||
|
|
||||||
|
Using `initctl disable my-service` the symlink (above) is removed and
|
||||||
|
the service is queued for removal. Several changes can be made to the
|
||||||
|
system, but it is not until `initctl reload` is called that the changes
|
||||||
|
are activated.
|
||||||
|
|
||||||
|
To add a new static service, drop a `.conf` file in `/etc/finit.d/` and
|
||||||
|
run `initctl reload`. (It is also possible to `SIGHUP` PID 1, or call
|
||||||
`finit q`, but that has been deprecated with the `initctl` tool). Finit
|
`finit q`, but that has been deprecated with the `initctl` tool). Finit
|
||||||
monitors all known active `.conf` files, so if you want to force a
|
monitors all known active `.conf` files, so if you want to force a
|
||||||
restart of any service you can touch its corresponding `.conf` file in
|
restart of any service you can touch its corresponding `.conf` file in
|
||||||
`/etc/finit.d` and call `initctl reload`. Finit handle any and all
|
`/etc/finit.d` and call `initctl reload`. Finit handles all conditions
|
||||||
conditions and dependencies between services automatically.
|
and dependencies between services automatically, see below section on
|
||||||
|
[Service Synchronization](#service-synchronization) for more details.
|
||||||
It is also possible to drop `.conf` files in `/etc/finit.d/available/`
|
|
||||||
and use `initctl enable` to enable a service `.conf` file. This may be
|
|
||||||
useful in particular to Linux distributions that may want to install all
|
|
||||||
files for a package and let the user decide when to enable a service.
|
|
||||||
|
|
||||||
On `initctl reload` the following is checked for all services:
|
On `initctl reload` the following is checked for all services:
|
||||||
|
|
||||||
@@ -68,10 +200,6 @@ On `initctl reload` the following is checked for all services:
|
|||||||
For more info on the different states of a service, see the separate
|
For more info on the different states of a service, see the separate
|
||||||
document [Finit Services](service.md).
|
document [Finit Services](service.md).
|
||||||
|
|
||||||
> When running <kbd>make install</kbd> no default `/etc/finit.conf` is
|
|
||||||
> installed since system requirements differ too much. There are some
|
|
||||||
> examples in the `contrib/` directory, which can be used as a base.
|
|
||||||
|
|
||||||
|
|
||||||
### Environment Variables
|
### Environment Variables
|
||||||
|
|
||||||
@@ -80,10 +208,12 @@ and any `*.conf`, was added. It is worth noting that these are global
|
|||||||
and *shared with all* services -- the only way to have service-local
|
and *shared with all* services -- the only way to have service-local
|
||||||
environment is detailed in the next section.
|
environment is detailed in the next section.
|
||||||
|
|
||||||
The syntax for global environment variables is straight forward:
|
The syntax for global environment variables is straight forward. In
|
||||||
|
Finit v4.4 the `set` keyword was added for completeness, but the old
|
||||||
|
syntax (without the `set ` prefix) is still honored:
|
||||||
|
|
||||||
foo=bar
|
set foo=bar
|
||||||
baz="qux"
|
set baz="qux"
|
||||||
|
|
||||||
On reload of .conf files, all tracked environment variables are cleared
|
On reload of .conf files, all tracked environment variables are cleared
|
||||||
so if `foo=bar` is removed from `finit.conf`, or any `finit.d/*.conf`
|
so if `foo=bar` is removed from `finit.conf`, or any `finit.d/*.conf`
|
||||||
@@ -131,6 +261,67 @@ the `ps` command we can see that the process is started with:
|
|||||||
> `-` is used, a missing environment file does *not* block the start.
|
> `-` is used, a missing environment file does *not* block the start.
|
||||||
|
|
||||||
|
|
||||||
|
Service Synchronization
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Finit was created for fast booting systems. Faster than a regular SysV
|
||||||
|
Init based system at the time. Early on the need for a guaranteed start
|
||||||
|
order of services (daemons) arose. I.e., service `A` must be guaranteed
|
||||||
|
to have started (and be ready!) before `B`. The model that was chosen
|
||||||
|
to determine this was very simple: PID files.
|
||||||
|
|
||||||
|
Early on in UNIX daemons were controlled with basic IPC like signals,
|
||||||
|
and the way for a user to know that a daemon was ready to respond to
|
||||||
|
signals (minimally having set up its signal handler), was to tell the
|
||||||
|
user;
|
||||||
|
|
||||||
|
> "Hey, you can send signals to me using the PID in this file:
|
||||||
|
> `/var/run/daemon.pid`".
|
||||||
|
|
||||||
|
Since most systems run fairly unchanged after boot, Finit could rely on
|
||||||
|
the PID file for `A` being created before launching `B`. This method
|
||||||
|
has worked well for a long time, and for systems based on Open Source it
|
||||||
|
was easy to either add PID file support to a daemon without support for
|
||||||
|
it, or fix ordering issues (PID file created before signal handler is
|
||||||
|
set up) in existing daemons.
|
||||||
|
|
||||||
|
However, with the advent of other Init systems (Finit is rather old),
|
||||||
|
most notably systemd and s6, other methods for signaling "readiness"
|
||||||
|
arrived and daemons were adapted to these new schemes to a larger
|
||||||
|
extent.
|
||||||
|
|
||||||
|
As of Finit v4.4 partial support for systemd and s6 is available. The
|
||||||
|
native PID file mode of operation is still default, the other's can be
|
||||||
|
defined per service, like this:
|
||||||
|
|
||||||
|
service notify:systemd foo
|
||||||
|
service notify:s6 bar
|
||||||
|
|
||||||
|
To synchronize two services the following condition can be used:
|
||||||
|
|
||||||
|
service notify:systemd A
|
||||||
|
service <service/A/ready> B
|
||||||
|
|
||||||
|
For details on the syntax and options, see below.
|
||||||
|
|
||||||
|
> **Note:** on `initctl reload` conditions are normally set in "flux",
|
||||||
|
> while figuring out which to stop, start or restart. Services that
|
||||||
|
> need to be restarted have their `ready` condition removed prior to
|
||||||
|
> Finit sending them SIGHUP (if they support that), or stop-starting
|
||||||
|
> them. A daemon is expected to reassert its readiness, e.g. systemd
|
||||||
|
> style daemons to write `READY=1\n`.
|
||||||
|
>
|
||||||
|
> However, the s6 notify mode does not support this because in s6 you
|
||||||
|
> are expected to close your notify descriptor after having written
|
||||||
|
> `\n`. This means s6 style daemons currently must be stop-started.
|
||||||
|
> (Declare the service with `<!>` in its condition statement.)
|
||||||
|
>
|
||||||
|
> For native PID file style readiness notification a daemon is expected
|
||||||
|
> to either create its PID file, if it does not exist yet, or touch it
|
||||||
|
> using `utimensat()` or similar. This triggers both the `<pid/>` and
|
||||||
|
> `<.../ready>` conditions.
|
||||||
|
|
||||||
|
|
||||||
Service Wrapper Scripts
|
Service Wrapper Scripts
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
@@ -163,6 +354,26 @@ example employs a wrapper script in `/etc/start.d`.
|
|||||||
> instead of sending SIGHUP at restart/reload events.
|
> instead of sending SIGHUP at restart/reload events.
|
||||||
|
|
||||||
|
|
||||||
|
Templating
|
||||||
|
----------
|
||||||
|
|
||||||
|
Finit comes with rudimentary support for templating, similar to that of
|
||||||
|
systemd. Best illustrated with an example:
|
||||||
|
|
||||||
|
$ initctl show avahi-autoipd@
|
||||||
|
service :%i avahi-autoipd --syslog %i -- ZeroConf for %i
|
||||||
|
|
||||||
|
To enable ZeroConf for, e.g., eth0, use
|
||||||
|
|
||||||
|
$ initctl enable avahi-autoipd@eth0.conf
|
||||||
|
|
||||||
|
The enabled symlink will be set up to avahi-autoipd@.conf and every in‐
|
||||||
|
stance of %i will in the instantiated directive be replaced with eth0.
|
||||||
|
Inspect the result with:
|
||||||
|
|
||||||
|
$ initctl status avahi-autoipd:eth0
|
||||||
|
|
||||||
|
|
||||||
Cgroups
|
Cgroups
|
||||||
-------
|
-------
|
||||||
|
|
||||||
@@ -227,6 +438,31 @@ Linux kernel, or the name is misspelled.
|
|||||||
Configuration File Syntax
|
Configuration File Syntax
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
|
The file format is line based, empty lines and comments, lines starting
|
||||||
|
with `#`, are ignored. A configuration directive starts with a keyword
|
||||||
|
followed by a space and the rest of the line is treated as the value.
|
||||||
|
|
||||||
|
As of Finit v4.4, configuration directives can be broken up in multiple
|
||||||
|
lines using the continuation character `\`, and trailing comments are
|
||||||
|
also allowed. Example:
|
||||||
|
|
||||||
|
```aconf
|
||||||
|
# Escape \# chars if you want them literal in, e.g., descriptions
|
||||||
|
service name:sysklogd [S123456789] \
|
||||||
|
env:-/etc/default/sysklogd \
|
||||||
|
syslogd -F $SYSLOGD_ARGS \
|
||||||
|
-- System log daemon \# 1 # Comments allowed now
|
||||||
|
```
|
||||||
|
|
||||||
|
The .conf files `/etc/finit.conf` and `/etc/finit.d/*` support the
|
||||||
|
following directives:
|
||||||
|
|
||||||
|
|
||||||
|
> **Note:** not all directives are available in `/etc/finit.d/*.conf`
|
||||||
|
> and some directives are only available at [bootstrap][], runlevel `S`,
|
||||||
|
> see [Limitations](#limitations) below for details.
|
||||||
|
|
||||||
|
|
||||||
### Hostname
|
### Hostname
|
||||||
|
|
||||||
**Syntax:** `host <NAME>`, or `hostname <NAME>`
|
**Syntax:** `host <NAME>`, or `hostname <NAME>`
|
||||||
@@ -270,6 +506,27 @@ 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/
|
||||||
|
|
||||||
|
**Syntax:** `rcsd /path/to/finit.d`
|
||||||
|
|
||||||
|
The Finit rcS.d directory is set at compile time with:
|
||||||
|
|
||||||
|
./configure --with-rcsd=/etc/finit.d
|
||||||
|
|
||||||
|
A system with multiple use-cases may be bootstrapped with different
|
||||||
|
configurations, starting with the kernel command line option:
|
||||||
|
|
||||||
|
-- finit.config=/etc/factory.conf
|
||||||
|
|
||||||
|
This file in turn can use the `rcsd` directive to tell Finit to use
|
||||||
|
another set of .conf files, e.g.:
|
||||||
|
|
||||||
|
rcsd /etc/factory.d
|
||||||
|
|
||||||
|
> **Note:** this directive is only available from the top-level
|
||||||
|
> bootstrap .conf file.
|
||||||
|
|
||||||
### Resource Limits
|
### Resource Limits
|
||||||
|
|
||||||
**Syntax:** `rlimit [hard|soft] RESOURCE <LIMIT|unlimited>`
|
**Syntax:** `rlimit [hard|soft] RESOURCE <LIMIT|unlimited>`
|
||||||
@@ -305,7 +562,10 @@ 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
|
is the runlevel number 0-9, where 6 is reserved for reboot and 0 for
|
||||||
halt.
|
halt.
|
||||||
|
|
||||||
Default: 2
|
It is recommended to keep runlevel 1 as single-user mode, because
|
||||||
|
Finit disables networking in this mode.
|
||||||
|
|
||||||
|
*Default:* 2
|
||||||
|
|
||||||
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||||
|
|
||||||
@@ -419,10 +679,56 @@ modified with an optional `pid:`-argument:
|
|||||||
|
|
||||||
pid[:[/path/to/]filename[.pid]]
|
pid[:[/path/to/]filename[.pid]]
|
||||||
|
|
||||||
For example, by adding `pid:/run/foo.pid` to the service `/sbin/bar`,
|
For example, by adding `pid:/run/bar.pid` to the service `/sbin/bar`,
|
||||||
that PID file will, not only be created and removed automatically, but
|
that PID file will, not only be created and removed automatically, but
|
||||||
also be used by the Finit condition subsystem. So a service/run/task
|
also be used by the Finit condition subsystem. So a service/run/task
|
||||||
can depend on `<pid/bar>`.
|
can depend on `<pid/bar>`, like this foo will not be started until bar
|
||||||
|
has started:
|
||||||
|
|
||||||
|
service pid:/run/bar.pid bar -- Bar Service
|
||||||
|
service <pid/bar> foo -- Foo Service
|
||||||
|
|
||||||
|
Needless to say, it is better if `bar` creates its own PID file when it
|
||||||
|
has completed starting up and is ready for service.
|
||||||
|
|
||||||
|
As an alternative "readiness" notification, Finit supports both systemd
|
||||||
|
and s6 style notification. This can be enabled by using the `notify`
|
||||||
|
option:
|
||||||
|
|
||||||
|
* `notify:systemd` -- tells Finit the service uses the `sd_notify()`
|
||||||
|
API to signal PID 1 when it has completed its startup and is ready
|
||||||
|
to service events. The [sd_notify()][] API expects `NOTIFY_SOCKET`
|
||||||
|
to be set to the socket where the application can send `"READY=1\n"`
|
||||||
|
when it is starting up or has processed a `SIGHUP`.
|
||||||
|
* `notify:s6` -- puts Finit in s6 compatibility mode. Compared to the
|
||||||
|
systemd notification, [s6 expect][] compliant daemons to send `"\n"`
|
||||||
|
and then close their socket. Finit takes care of "hard-wiring" the
|
||||||
|
READY state as long as the application is running, events across any
|
||||||
|
`SIGHUP`. Since s6 can give its applications the descriptor number
|
||||||
|
(must be >3) on then command line, Finit provides the following
|
||||||
|
syntax (`%n` is replaced by Finit with then descriptor number):
|
||||||
|
|
||||||
|
service [S12345789] notify:s6 mdevd -O 4 -D %n
|
||||||
|
|
||||||
|
[sd_notify()]: https://www.freedesktop.org/software/systemd/man/sd_notify.html
|
||||||
|
[s6 expect]: https://skarnet.org/software/s6/notifywhenup.html
|
||||||
|
|
||||||
|
When a service is ready, either by Finit detecting its PID file, or
|
||||||
|
their respective readiness mechanism has been triggered, Finit creates
|
||||||
|
then service's ready condition which other services can depend on:
|
||||||
|
|
||||||
|
$ initctl -v cond get service/mdevd/ready
|
||||||
|
on
|
||||||
|
|
||||||
|
This can be used to synchronize the start of another run/task/service:
|
||||||
|
|
||||||
|
task [S] <service/mdevd/ready> @root:root mdevd-coldplug
|
||||||
|
|
||||||
|
Finit waits for `mdevd` to notify it, before starting `mdevd-coldplug`.
|
||||||
|
Notice how both start in runlevel S, and the coldplug task only runs in
|
||||||
|
S. When the system moves to runlevel 2 (the default), coldplug is no
|
||||||
|
longer part of the running configuration (`initctl show`), this is to
|
||||||
|
ensure that coldplug is not called more than once.
|
||||||
|
|
||||||
> For a detailed description of conditions, and how to debug them,
|
> For a detailed description of conditions, and how to debug them,
|
||||||
> see the [Finit Conditions](conditions.md) document.
|
> see the [Finit Conditions](conditions.md) document.
|
||||||
@@ -439,6 +745,24 @@ optional `name` argument:
|
|||||||
|
|
||||||
name:<service-name>
|
name:<service-name>
|
||||||
|
|
||||||
|
If multiple instances of a service, with the same `name`, exist. Set
|
||||||
|
the identifier `:ID` to prevent Finit from replacing previous instances:
|
||||||
|
|
||||||
|
service :eth1 ssdpd eth1 -- Windows discovery on eth1
|
||||||
|
service :eth2 ssdpd eth2 -- Windows discovery on eth2
|
||||||
|
|
||||||
|
If you have conflicting services and want to prevent them from starting,
|
||||||
|
use the `conflict:` argument:
|
||||||
|
|
||||||
|
service [S12345789] udevd -- Device event management daemon
|
||||||
|
run [S] conflict:udevd mdev -s -- Populating device tree
|
||||||
|
|
||||||
|
Multiple conflicting services can be separated using `,`:
|
||||||
|
|
||||||
|
service :1 abc
|
||||||
|
service :2 abc
|
||||||
|
service conflict:abc:1,abc:2 cde
|
||||||
|
|
||||||
As mentioned previously, services are automatically restarted, this is
|
As mentioned previously, services are automatically restarted, this is
|
||||||
configurable with the following options:
|
configurable with the following options:
|
||||||
|
|
||||||
@@ -450,13 +774,16 @@ configurable with the following options:
|
|||||||
a crashing service, default: 2 seconds for the first five retries,
|
a crashing service, default: 2 seconds for the first five retries,
|
||||||
then back-off to 5 seconds. The maximum of this configured value
|
then back-off to 5 seconds. The maximum of this configured value
|
||||||
and the above (2 and 5) will be used
|
and the above (2 and 5) will be used
|
||||||
|
* `restart:always` -- no upper limit on the number of times Finit
|
||||||
|
tries to restart a crashing service. Same as `restart:-1`
|
||||||
* `norestart` -- dont restart on failures, same as `restart:0`
|
* `norestart` -- dont restart on failures, same as `restart:0`
|
||||||
* `respawn` -- bypasses the `restart` mechanism completely, allows
|
* `respawn` -- bypasses the `restart` mechanism completely, allows
|
||||||
endless restarts. Useful in many use-cases, but not what `service`
|
endless restarts. Useful in many use-cases, but not what `service`
|
||||||
was originally designed for so not the default behavior
|
was originally designed for so not the default behavior
|
||||||
* `oncrash:reboot` -- when all retries have failed, and the service
|
* `oncrash:reboot` -- when all retries have failed, and the service
|
||||||
has *crashed*, if this option is set the system is rebooted.
|
has *crashed*, if this option is set the system is rebooted.
|
||||||
Note, future releases may include other `oncrash:` actions
|
* `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 stopping a service (run/task/sysv/service), either manually or
|
||||||
when moving to another runlevel, Finit starts by sending `SIGTERM`, to
|
when moving to another runlevel, Finit starts by sending `SIGTERM`, to
|
||||||
@@ -482,12 +809,9 @@ with an additional set of environment variables:
|
|||||||
the program, if it exited normally, or the signal name (`HUP`,
|
the program, if it exited normally, or the signal name (`HUP`,
|
||||||
`TERM`, etc.) if it exited due to signal
|
`TERM`, etc.) if it exited due to signal
|
||||||
|
|
||||||
The scripts have a default execution time of 3 seconds before they are
|
These script actions *must terminate*, so they have a default execution
|
||||||
SIGKILLed, this can be adjusted using the above `kill:SEC` syntax.
|
time of 3 seconds before they are SIGKILLed, this can be adjusted using
|
||||||
|
the above `kill:SEC` syntax.
|
||||||
> **Note:** the `pre:script` _must_ be idempotent, because a service
|
|
||||||
> can transition between READY and HALTED states any number
|
|
||||||
> of times before going to RUNNING.
|
|
||||||
|
|
||||||
|
|
||||||
### Run-parts Scripts
|
### Run-parts Scripts
|
||||||
@@ -499,15 +823,48 @@ files, or scripts, in the directory are called, in alphabetic order.
|
|||||||
The scripts in this directory are executed at the very end of runlevel
|
The scripts in this directory are executed at the very end of runlevel
|
||||||
`S`, [bootstrap][].
|
`S`, [bootstrap][].
|
||||||
|
|
||||||
It can be beneficial to use `S01name`, `S02othername`, etc. if there
|
A common use-case for runparts scripts is to create and enable/disable
|
||||||
is a dependency order between the scripts. Symlinks to existing
|
services, which Finit will then apply when changing runlevel from S to
|
||||||
daemons can talso be used, but make sure they daemonize by default.
|
whatever the next runlevel is set to be (default 2). E.g., generate a
|
||||||
|
`/etc/chrony.conf` and `initctl enable chronyd`.
|
||||||
|
|
||||||
Similar to the `/etc/rc.local` shell script, make sure that all your
|
**Limitations:**
|
||||||
services and programs either terminate or start in the background or
|
|
||||||
you will block Finit.
|
|
||||||
|
|
||||||
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
Scripts called from `runparts`, or hook scripts (see below), are limited
|
||||||
|
in what they can do and expect from 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.
|
||||||
|
|
||||||
|
**Recommendations:**
|
||||||
|
|
||||||
|
It can be beneficial to use `01-name`, `02-othername`, etc., to ensure
|
||||||
|
the scripts are started in that order, e.g., if there is a dependency
|
||||||
|
order between scripts. Symlinks to existing daemons can talso be used,
|
||||||
|
but make sure they daemonize (background) themselves properly, otherwise
|
||||||
|
Finit will lock up.
|
||||||
|
|
||||||
|
If `S[0-9]foo` and `K[0-9]bar` style naming is used, the executable will
|
||||||
|
be called with an extra argument, `start` and `stop`, respectively.
|
||||||
|
E.g., `S01foo` will be called as `S01foo start`. Of course, `S01foo`
|
||||||
|
and `K01foo` may be a symlink to to `another/directory/foo`.
|
||||||
|
|
||||||
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
||||||
|
|
||||||
@@ -666,6 +1023,27 @@ Log rotation is controlled using the global `log` setting.
|
|||||||
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
|
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
|
||||||
|
|
||||||
|
|
||||||
|
### Misc Settings
|
||||||
|
|
||||||
|
**Syntax:** `reboot-delay <0-60>`
|
||||||
|
|
||||||
|
Optional delay at reboot (or shutdown or halt) to allow kernel
|
||||||
|
filesystem threads to complete after calling `sync(2)` before
|
||||||
|
rebooting. This applies primarily to filesystems that do not
|
||||||
|
have a reboot notifier implemented. At the point of writing,
|
||||||
|
the only known filesystems affected are: ubifs, jffs2.
|
||||||
|
|
||||||
|
*Default:* 0 (disabled)
|
||||||
|
|
||||||
|
When enabled (non-zero), this delay runs after file systems have been
|
||||||
|
unmounted and the root filesystem has been remounted read-only, and
|
||||||
|
sync(2) has been called, twice.
|
||||||
|
|
||||||
|
> "On Linux, sync is only guaranteed to schedule the dirty blocks for
|
||||||
|
> writing; it can actually take a short time before all the blocks are
|
||||||
|
> finally written.
|
||||||
|
|
||||||
|
|
||||||
Rescue Mode
|
Rescue Mode
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
@@ -739,9 +1117,9 @@ There is, however, nothing preventing you from having all configuration
|
|||||||
settings in `/etc/finit.conf`.
|
settings in `/etc/finit.conf`.
|
||||||
|
|
||||||
> **Note:** The `/etc/finit.d` directory was previously the default
|
> **Note:** The `/etc/finit.d` directory was previously the default
|
||||||
> Finit [runparts](#run-parts-scripts) directory. Finit no
|
> Finit [runparts](#run-parts-scripts) directory. Finit >=v4.0
|
||||||
> longer has a default `runparts`, make sure to update your
|
> no longer has a default `runparts` directory, make sure to
|
||||||
> setup, or the finit configuration, accordingly.
|
> update your setup, or the finit configuration, accordingly.
|
||||||
|
|
||||||
|
|
||||||
Watchdog
|
Watchdog
|
||||||
|
|||||||
+121
-37
@@ -8,7 +8,8 @@ Hooks & Plugins
|
|||||||
* [Shutdown Hooks](#shutdown-hooks)
|
* [Shutdown Hooks](#shutdown-hooks)
|
||||||
|
|
||||||
Finit can be extended to add general functionality in the form of I/O
|
Finit can be extended to add general functionality in the form of I/O
|
||||||
monitors, or hook plugins.
|
monitors, or hook plugins. It is even possible to run scripts at these
|
||||||
|
hook points, see below.
|
||||||
|
|
||||||
The following sections detail existing plugins and hook points. For
|
The following sections detail existing plugins and hook points. For
|
||||||
more information, see the plugins listed below.
|
more information, see the plugins listed below.
|
||||||
@@ -35,13 +36,25 @@ For your convenience a set of *optional* plugins are available:
|
|||||||
_Optional plugin._
|
_Optional plugin._
|
||||||
|
|
||||||
* *hook-scripts.so*: Trigger the execution of scripts from plugin hook
|
* *hook-scripts.so*: Trigger the execution of scripts from plugin hook
|
||||||
points (see [Hooks](#hooks)). Scripts are located in
|
points (see [Hooks](#hooks)). _Optional plugin._
|
||||||
`/libexec/finit/hook` by default, this can be build-time customized
|
|
||||||
by using the `--with-hook-scripts-path=PATH` argument to
|
This plugin is particularly useful for early boot debugging that needs
|
||||||
`configure`. _Optional plugin._
|
to take place before regular services are available.
|
||||||
|
|
||||||
|
For example, say that you want to enable some kernel tracing before
|
||||||
|
modules are loaded. With hook scripts, you can just drop in a shell
|
||||||
|
script in `/libexec/finit/hook/mount/all/` that will poke the right
|
||||||
|
control files in tracefs.
|
||||||
|
|
||||||
|
Scripts are located in `/libexec/finit/hook` by default, this can be
|
||||||
|
customized at build-time using the `--with-hook-scripts-path=PATH`
|
||||||
|
argument to `configure`.
|
||||||
|
|
||||||
* *hotplug.so*: Setup and start either udev or mdev hotplug daemon, if
|
* *hotplug.so*: Setup and start either udev or mdev hotplug daemon, if
|
||||||
available. Enabled by default.
|
available. 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.
|
||||||
|
|
||||||
* *rtc.so*: Restore and save system clock from/to RTC on boot/halt.
|
* *rtc.so*: Restore and save system clock from/to RTC on boot/halt.
|
||||||
Enabled by default.
|
Enabled by default.
|
||||||
@@ -49,20 +62,33 @@ For your convenience a set of *optional* plugins are available:
|
|||||||
* *modules-load.so*: Scans `/etc/modules-load.d/*.conf` for modules to
|
* *modules-load.so*: Scans `/etc/modules-load.d/*.conf` for modules to
|
||||||
load using `modprobe`. Each file can contain multiple lines with the
|
load using `modprobe`. Each file can contain multiple lines with the
|
||||||
name of the module to load. Any line starting with the standard UNIX
|
name of the module to load. Any line starting with the standard UNIX
|
||||||
comment character, `#`, is skipped.
|
comment character, `#`, or `;`, is skipped.
|
||||||
|
|
||||||
Modules are loaded when entering runlevel `[2345]` using the `task`
|
Modules are by default loaded in runlevel `S` using the `task` stanza.
|
||||||
stanza. Each module gets a unique `name:modprobe.foo`, and
|
Each module gets a unique `name:modprobe.foo`, and optional`:ID`. The
|
||||||
optional`:ID`. The `:ID` is a globally incremented index, which can
|
runlevel can be changed per file using:
|
||||||
be disabled per file (anywhere) using the following config line:
|
|
||||||
|
set runlevel 2345
|
||||||
|
|
||||||
|
The `:ID` is a globally incremented index, which can be disabled per
|
||||||
|
file (anywhere) using the following config line:
|
||||||
|
|
||||||
set noindex
|
set noindex
|
||||||
|
|
||||||
|
To change the index used by the plugin:
|
||||||
|
|
||||||
|
set index 1234
|
||||||
|
|
||||||
**Note:** unlike the traditional .conf `module` directive, which load
|
**Note:** unlike the traditional .conf `module` directive, which load
|
||||||
any listed module immediately, this plugin creates standard `taks`
|
any listed module immediately, this plugin creates a background `task`
|
||||||
directives which load the module(s) in the background. As long as
|
which load the module(s) in the background. The program is modprobe,
|
||||||
the `modprobe` program is found in the path, these tasks will always
|
`/sbin/modprobe`, which you can override per .conf file:
|
||||||
return `[ OK ]` at boot. Check the actual status using `initctl`.
|
|
||||||
|
set modprobe /path/to/maybe-a-modprobe-wrapper
|
||||||
|
|
||||||
|
Since these tasks run in the background, they usually return `[ OK ]`
|
||||||
|
at boot, unless the modprobe tool does not exist. Check syslog for
|
||||||
|
warnings and the actual status of the operation using `initctl`.
|
||||||
|
|
||||||
* *netlink.so*: Listens to Linux kernel Netlink events for gateway and
|
* *netlink.so*: Listens to Linux kernel Netlink events for gateway and
|
||||||
interfaces. These events are then sent to the Finit service monitor
|
interfaces. These events are then sent to the Finit service monitor
|
||||||
@@ -91,43 +117,101 @@ state, etc. Available hook points are:
|
|||||||
Hooks
|
Hooks
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
In the below listings, the first label is the hook point for a C plugin,
|
||||||
|
the second is the condition name and hook script path. A hook script is
|
||||||
|
a plain shell script, or program, that does a very small dedicated job
|
||||||
|
at the below hook points.
|
||||||
|
|
||||||
|
See [Run-parts Scripts](config.md#run-parts-scripts) for details on the
|
||||||
|
requirements, possibilities, and *limitations* of hook scripts.
|
||||||
|
|
||||||
|
All hook scripts are called with at least one environment variable set,
|
||||||
|
the hook name, useful when reusing the same hook script for multiple
|
||||||
|
hook points:
|
||||||
|
|
||||||
|
- `FINIT_HOOK_NAME`: set to the second label, e.g., `hook/net/up`
|
||||||
|
- `FINIT_SHUTDOWN`: set for `hook/sys/shutdown` and later to one
|
||||||
|
of `halt`, `poweroff`, or `reboot`.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
$ mkdir -p /libexec/finit/hook/sys/down
|
||||||
|
$ cat <<EOF >/libexec/finit/hook/sys/foo.sh
|
||||||
|
#!/bin/sh
|
||||||
|
echo 'I run just before the reboot() syscall at shutdown/reboot'
|
||||||
|
echo 'I have access to /dev since devtmpfs is exempt from umount'
|
||||||
|
echo "FINIT_HOOK_NAME: $FINIT_HOOK_NAME"
|
||||||
|
if [ -n "$FINIT_SHUTDOWN" ]; then
|
||||||
|
echo "FINIT_SHUTDOWN: $FINIT_SHUTDOWN"
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
EOF
|
||||||
|
$ chmod +x /libexec/finit/hook/sys/foo.sh
|
||||||
|
|
||||||
|
> **Note:** to use hook scripts, even for pre-bootstrap and pre-shutdown
|
||||||
|
> tasks, you must build with `configure --enable-hook-scripts-plugin`.
|
||||||
|
|
||||||
### Bootstrap Hooks
|
### Bootstrap Hooks
|
||||||
|
|
||||||
* `HOOK_BANNER`: The very first point at which a plugin can run.
|
* `HOOK_BANNER`, `hook/sys/banner`: The very first point at which a
|
||||||
Intended to be used as a banner replacement. Essentially this runs
|
plugin can run. Intended to be used as a banner replacement.
|
||||||
just before entering runlevel S. Assume nothing is available, so
|
Essentially this runs just before entering runlevel S. Assume nothing
|
||||||
be prepared to use absolute paths, etc.
|
is available, so be prepared to use absolute paths, etc.
|
||||||
|
|
||||||
* `HOOK_ROOTFS_UP`: When `finit.conf` has been read and `/` has is
|
* `HOOK_ROOTFS_UP`, `hook/mount/root`: When `finit.conf` has been read
|
||||||
mounted — very early
|
and `/` has is mounted — very early
|
||||||
|
|
||||||
* `HOOK_BASEFS_UP`: All of `/etc/fstab` is mounted, swap is available
|
* `HOOK_MOUNT_ERROR`, `hook/mount/error`: executed if `mount -a` fails
|
||||||
and default init signals are setup
|
|
||||||
|
|
||||||
* `HOOK_NETWORK_UP`: System bootstrap, runlevel S, has completed and
|
* `HOOK_MOUNT_POST`, `hook/mount/post`: always executed after `mount -a`
|
||||||
networking is up (`lo` is up and the `network` script has run)
|
|
||||||
|
|
||||||
* `HOOK_SVC_UP`: All services in the active runlevel has been launched
|
* `HOOK_BASEFS_UP`, `hook/mount/all`: All of `/etc/fstab` is mounted,
|
||||||
|
swap is available and default init signals are setup
|
||||||
|
|
||||||
* `HOOK_SYSTEM_UP`: All services *and* everything in `/etc/finit.d`
|
* `HOOK_SVC_PLUGIN`, `hook/svc/plugin`: Called in `conf_init()` right
|
||||||
has been launched
|
before loading `/etc/finit.conf`. For plugins to register any early
|
||||||
|
run/task/services, please do NOT use any earlier hook point. That
|
||||||
|
will cause uninitialized rlimits that lead to unpredictable results
|
||||||
|
when Finit later tries to start the run/task/service.
|
||||||
|
|
||||||
|
* `HOOK_NETWORK_UP`, `hook/net/up`: System bootstrap, runlevel S, has
|
||||||
|
completed and networking is up (`lo` is up and the `network` script
|
||||||
|
has run)
|
||||||
|
|
||||||
|
* `HOOK_SVC_UP`, `hook/svc/up`: All services in the active runlevel have
|
||||||
|
been launched
|
||||||
|
|
||||||
|
* `HOOK_SYSTEM_UP`, `hook/sys/up`: All services *and* everything in
|
||||||
|
`/etc/finit.d` has been launched
|
||||||
|
|
||||||
### Runtime Hooks
|
### Runtime Hooks
|
||||||
|
|
||||||
* `HOOK_SVC_RECONF`: Called when the user has changed something in the
|
* `HOOK_SVC_RECONF`, N/A: Called when the user has changed something in
|
||||||
`/etc/finit.d` directory and issued `SIGHUP`. The hook is called when
|
the `/etc/finit.d` directory and issued `SIGHUP`. The hook is called
|
||||||
all modified/removed services have been stopped. When the hook has
|
when all modified/removed services have been stopped. When the hook
|
||||||
completed, Finit continues to start all modified and new services.
|
has completed, Finit continues to start all modified and new services.
|
||||||
|
|
||||||
* `HOOK_RUNLEVEL_CHANGE`: Called when the user has issued a runlevel
|
* `HOOK_RUNLEVEL_CHANGE`, N/A: Called when the user has issued a
|
||||||
change. The hook is called when services not matching the new
|
runlevel change. The hook is called when services not matching the
|
||||||
runlevel have been been stopped. When the hook has completed, Finit
|
new runlevel have been been stopped. When the hook has completed,
|
||||||
continues to start all services in the new runlevel.
|
Finit continues to start all services in the new runlevel.
|
||||||
|
|
||||||
### Shutdown Hooks
|
### Shutdown Hooks
|
||||||
|
|
||||||
* `HOOK_SHUTDOWN`: Called at shutdown/reboot, right before all
|
* `HOOK_NETWORK_DN`, `hook/net/down`: Called right after having changed
|
||||||
services are sent `SIGTERM`
|
to runlevel 6, or 0, when all services have received their 'stop' signal.
|
||||||
|
|
||||||
|
* `HOOK_SHUTDOWN`, `hook/sys/shutdown`: Called at shutdown/reboot, right
|
||||||
|
before all services are sent `SIGTERM`
|
||||||
|
|
||||||
|
* `HOOK_SVC_DN`, `hook/svc/down`: In shutdown/reboot, all services and
|
||||||
|
non-reserved processes have been killed. **Note:** only hook scripts
|
||||||
|
can run here!
|
||||||
|
|
||||||
|
* `HOOK_SYSTEM_DN`, `hook/sys/down`: In shutdown/reboot, called after
|
||||||
|
all non-reserved file systems have been unmounted, just before Finit
|
||||||
|
tells the kernel to reboot or shut down. **Note:** only hook scripts
|
||||||
|
can run here!
|
||||||
|
|
||||||
Plugins like `tty.so` extend finit by acting on events, they are called
|
Plugins like `tty.so` extend finit by acting on events, they are called
|
||||||
I/O plugins and are called from the finit main loop when `poll()`
|
I/O plugins and are called from the finit main loop when `poll()`
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 138 KiB After Width: | Height: | Size: 230 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 164 KiB |
+19
-23
@@ -1,8 +1,6 @@
|
|||||||
# From https://github.com/collectd/collectd/blob/master/configure.ac
|
# From https://github.com/collectd/collectd/blob/master/configure.ac
|
||||||
# Dependency handling currently unused
|
# Dependency handling currently unused
|
||||||
|
|
||||||
define([toupper], [translit([$1], [a-z], [A-Z])])
|
|
||||||
define([sanitize], [translit([$1], [-], [_])])
|
|
||||||
define([enadis], [ifelse([$1], [yes], [disable], [enable])])
|
define([enadis], [ifelse([$1], [yes], [disable], [enable])])
|
||||||
|
|
||||||
# AC_PLUGIN(name, default, info)
|
# AC_PLUGIN(name, default, info)
|
||||||
@@ -10,27 +8,25 @@ define([enadis], [ifelse([$1], [yes], [disable], [enable])])
|
|||||||
AC_DEFUN([AC_PLUGIN],[
|
AC_DEFUN([AC_PLUGIN],[
|
||||||
m4_divert_once([HELP_ENABLE], [
|
m4_divert_once([HELP_ENABLE], [
|
||||||
Optional Plugins:])
|
Optional Plugins:])
|
||||||
|
define(PLUGGY, m4_translit([$1],[a-z-][A-Z-]))dnl
|
||||||
|
AC_ARG_ENABLE([$1-plugin], AS_HELP_STRING([--enadis($2)-$1-plugin], [$3]), [
|
||||||
|
if test "x$enableval" = "xyes"; then
|
||||||
|
enable_plugin="yes"
|
||||||
|
else
|
||||||
enable_plugin="no"
|
enable_plugin="no"
|
||||||
define(pluggy, sanitize($1))
|
fi], [
|
||||||
define(PLUGGY, toupper(pluggy))
|
if test "x$enable_all_plugins" = "xauto"; then
|
||||||
AC_ARG_ENABLE([$1-plugin], AS_HELP_STRING([--enadis($2)-$1-plugin], [$3]), [
|
if test "x$2" = "xyes"; then
|
||||||
if test "x$enableval" = "xyes"; then
|
enable_plugin="yes"
|
||||||
enable_plugin="yes"
|
|
||||||
else
|
else
|
||||||
enable_plugin="no"
|
enable_plugin="no"
|
||||||
fi], [
|
|
||||||
if test "x$enable_all_plugins" = "xauto"; then
|
|
||||||
if test "x$2" = "xyes"; then
|
|
||||||
enable_plugin="yes"
|
|
||||||
else
|
|
||||||
enable_plugin="no"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
enable_plugin="$enable_all_plugins"
|
|
||||||
fi])
|
|
||||||
if test "x$enable_plugin" = "xyes"; then
|
|
||||||
AC_DEFINE([HAVE_]PLUGGY[_PLUGIN], 1, [Define to 1 if the $1 plugin is enabled.])
|
|
||||||
plugins="$1 $plugins"
|
|
||||||
fi
|
fi
|
||||||
AM_CONDITIONAL([BUILD_]PLUGGY[_PLUGIN], test "x$enable_plugin" = "xyes")
|
else
|
||||||
enable_pluggy="$enable_plugin"])
|
enable_plugin="$enable_all_plugins"
|
||||||
|
fi])
|
||||||
|
if test "x$enable_plugin" = "xyes"; then
|
||||||
|
AC_DEFINE(HAVE_[]m4_translit($1,[-a-z],[_A-Z])_PLUGIN, 1, [Define to 1 if the $1 plugin is enabled.])
|
||||||
|
plugins="$1 $plugins"
|
||||||
|
fi
|
||||||
|
|
||||||
|
AM_CONDITIONAL(BUILD_[]m4_translit($1,[-a-z],[_A-Z])_PLUGIN, test "x$enable_plugin" = "xyes")])
|
||||||
|
|||||||
+89
-2
@@ -2,7 +2,7 @@
|
|||||||
.\" First parameter, NAME, should be all caps
|
.\" First parameter, NAME, should be all caps
|
||||||
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||||
.\" other parameters are allowed: see man(7), man(1)
|
.\" other parameters are allowed: see man(7), man(1)
|
||||||
.Dd June 6, 2021
|
.Dd Apr 22, 2023
|
||||||
.\" Please adjust this date whenever revising the manpage.
|
.\" Please adjust this date whenever revising the manpage.
|
||||||
.Dt FINIT 8 SMM
|
.Dt FINIT 8 SMM
|
||||||
.Os Linux
|
.Os Linux
|
||||||
@@ -12,10 +12,16 @@
|
|||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm /sbin/finit
|
.Nm /sbin/finit
|
||||||
.Op --
|
.Op --
|
||||||
|
.Op debug
|
||||||
|
.Op finit.cond=foo[,bar[,baz]]
|
||||||
|
.Op finit.config=/path/to/alt/finit.conf
|
||||||
.Op finit.debug
|
.Op finit.debug
|
||||||
.Op finit.fstab=/etc/fstab.alt
|
.Op finit.fstab=/etc/fstab.alt
|
||||||
.Op finit.status=<on,off>
|
.Op finit.status=<on,off>
|
||||||
.Op finit.status_style=<classic,modern>
|
.Op finit.status_style=<classic,modern>
|
||||||
|
.Op loglevel=<0-7>
|
||||||
|
.Op panic=SEC
|
||||||
|
.Op quiet
|
||||||
.Op rescue | recover
|
.Op rescue | recover
|
||||||
.Op single | S
|
.Op single | S
|
||||||
.Nm /sbin/telinit
|
.Nm /sbin/telinit
|
||||||
@@ -45,6 +51,15 @@ Sourcing environment files
|
|||||||
.It
|
.It
|
||||||
Conditions for network/process/custom dependencies
|
Conditions for network/process/custom dependencies
|
||||||
.It
|
.It
|
||||||
|
Process readiness notification for synchronizing system startup as well
|
||||||
|
as reconfiguration at runtime. Natively PID files are used, but systemd
|
||||||
|
.Cm sd_notify()
|
||||||
|
and s6 notification is also supported.
|
||||||
|
.It
|
||||||
|
Limited support for
|
||||||
|
.Xr tmpfiles.d 5 ,
|
||||||
|
no aging, attributes, or subvolumes
|
||||||
|
.It
|
||||||
Pre/Post script actions
|
Pre/Post script actions
|
||||||
.It
|
.It
|
||||||
Tooling to enable/disable services
|
Tooling to enable/disable services
|
||||||
@@ -73,6 +88,38 @@ PID 1. For more information on this, and available kernel command line
|
|||||||
options, see
|
options, see
|
||||||
.Xr bootparam 7 .
|
.Xr bootparam 7 .
|
||||||
.Bl -tag -width pid -offset indent
|
.Bl -tag -width pid -offset indent
|
||||||
|
.It Cm debug
|
||||||
|
Enable kernel debug. Debug messages are printed to the console until
|
||||||
|
Finit starts up, unless
|
||||||
|
.Cm loglevel=7
|
||||||
|
(below) is used.
|
||||||
|
.It Cm finit.cond=foo[,bar[,baz]]
|
||||||
|
set
|
||||||
|
.Cm <boot/foo>
|
||||||
|
condition, optionally multiple conditions can be set using the same
|
||||||
|
option, separated with a comma. Alternatively, multiple
|
||||||
|
.Cm foo.cond=arg
|
||||||
|
can be given. Each will result in a
|
||||||
|
.Cm <boot/arg>
|
||||||
|
condition being set to control the rest of the system bootstrap.
|
||||||
|
.Pp
|
||||||
|
Very useful for selecting different boot modes, e.g. manufacturing test,
|
||||||
|
firmware upgrade, or rescue mode.
|
||||||
|
.Pp
|
||||||
|
.Sy Note:
|
||||||
|
.Cm <boot/...>
|
||||||
|
conditions cannot be cleared with
|
||||||
|
.Nm initctl !
|
||||||
|
.It Cm finit.config=/path/to/alternative/finit.conf
|
||||||
|
override the compile-time bootstrap config file, default:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
./configure --with-config=/etc/finit.conf
|
||||||
|
.Ed
|
||||||
|
Useful when starting up in various rescue mode, factory, or
|
||||||
|
production test setups. Use the top-level configuration file
|
||||||
|
directive
|
||||||
|
.Cm rcsd Ar /path/to/finit.d
|
||||||
|
to override the default rcS.d directory.
|
||||||
.It Cm finit.debug
|
.It Cm finit.debug
|
||||||
Enable Finit debug messages on system console and log. Sometimes useful
|
Enable Finit debug messages on system console and log. Sometimes useful
|
||||||
when doing board bringup. Before the system log daemon has started,
|
when doing board bringup. Before the system log daemon has started,
|
||||||
@@ -121,6 +168,33 @@ Control finit boot progress, including banner. This used to be called
|
|||||||
which still works but is deprecated.
|
which still works but is deprecated.
|
||||||
.It Cm finit.status_style=<classic,modern>
|
.It Cm finit.status_style=<classic,modern>
|
||||||
Set Finit boot progress style, when enabled.
|
Set Finit boot progress style, when enabled.
|
||||||
|
.It Cm loglevel=<0-7>
|
||||||
|
set the kernel's log level, which is more granular than
|
||||||
|
.Cm debug .
|
||||||
|
Also, when
|
||||||
|
.Cm loglevel=7 ,
|
||||||
|
Finit will
|
||||||
|
.Em not disable
|
||||||
|
kernel logs to the console. This is very useful when debugging the
|
||||||
|
kernel at system bring-up. Since
|
||||||
|
.Cm loglevel=7
|
||||||
|
is the same as
|
||||||
|
.Cm debug
|
||||||
|
this means you have to use
|
||||||
|
.Cm quiet
|
||||||
|
for a quiet boot, until sysklogd takes over logging of kernel events.
|
||||||
|
.It Cm panic=SEC
|
||||||
|
By default the kernel does not reboot after a kernel panic. This
|
||||||
|
setting will cause a kernel reboot after
|
||||||
|
.Ar SEC
|
||||||
|
seconds.
|
||||||
|
.It Cm quiet
|
||||||
|
Suppress kernel logging to console, except for warnings and errors.
|
||||||
|
Also, see
|
||||||
|
.Cm loglevel
|
||||||
|
and
|
||||||
|
.Cm quiet
|
||||||
|
above.
|
||||||
.It Cm rescue | recover
|
.It Cm rescue | recover
|
||||||
Start rescue/maintenance mode. If your system comes with the bundled
|
Start rescue/maintenance mode. If your system comes with the bundled
|
||||||
.Cm sulogin
|
.Cm sulogin
|
||||||
@@ -139,6 +213,10 @@ the regular runlevel. All services and TTYs in
|
|||||||
will be started, e.g., a
|
will be started, e.g., a
|
||||||
.Cm tty [1] @console nologin
|
.Cm tty [1] @console nologin
|
||||||
configuration presents you with a root console without login.
|
configuration presents you with a root console without login.
|
||||||
|
.Pp
|
||||||
|
.Sy Note:
|
||||||
|
by definition, single user mode does not have networking enabled. This
|
||||||
|
is also true for runlevel 1.
|
||||||
.El
|
.El
|
||||||
.Sh BOOTING
|
.Sh BOOTING
|
||||||
.Pp
|
.Pp
|
||||||
@@ -192,7 +270,7 @@ file removed, service B is also stopped.
|
|||||||
.Pp
|
.Pp
|
||||||
The following condition families are available today:
|
The following condition families are available today:
|
||||||
.Pp
|
.Pp
|
||||||
.Bl -tag -width pid -offset indent
|
.Bl -tag -width service -offset indent
|
||||||
.It Cm net
|
.It Cm net
|
||||||
Linux netlink events, e.g. net/route/default, net/eth0/up, and
|
Linux netlink events, e.g. net/route/default, net/eth0/up, and
|
||||||
net/et0/running
|
net/et0/running
|
||||||
@@ -200,6 +278,14 @@ net/et0/running
|
|||||||
PID files basd on the service declaration
|
PID files basd on the service declaration
|
||||||
.Cm name:id ,
|
.Cm name:id ,
|
||||||
gives the condition pid/name:id
|
gives the condition pid/name:id
|
||||||
|
.It Cm service
|
||||||
|
Tracks run/task/service state stansitions, including readiness. E.g.,
|
||||||
|
.Cm service/foo/ready
|
||||||
|
can be used as a condition for service
|
||||||
|
.Cm bar ,
|
||||||
|
provided
|
||||||
|
.Cm foo
|
||||||
|
properly signals its readiness to Finit.
|
||||||
.It Cm sys
|
.It Cm sys
|
||||||
System conditions, e.g. sys/key/ctrlaltdel and sys/pwr/fail
|
System conditions, e.g. sys/key/ctrlaltdel and sys/pwr/fail
|
||||||
.It Cm usr
|
.It Cm usr
|
||||||
@@ -255,6 +341,7 @@ Runtime files, including the condition subsystem
|
|||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr finit.conf 5
|
.Xr finit.conf 5
|
||||||
.Xr initctl 8
|
.Xr initctl 8
|
||||||
|
.Xr tmpfiles.d 5
|
||||||
.Sh AUTHORS
|
.Sh AUTHORS
|
||||||
.Nm
|
.Nm
|
||||||
was conceived and reverse engineered by Claudio Matsuoka. Since v1.0,
|
was conceived and reverse engineered by Claudio Matsuoka. Since v1.0,
|
||||||
|
|||||||
+112
-21
@@ -2,7 +2,7 @@
|
|||||||
.\" First parameter, NAME, should be all caps
|
.\" First parameter, NAME, should be all caps
|
||||||
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||||
.\" other parameters are allowed: see man(7), man(1)
|
.\" other parameters are allowed: see man(7), man(1)
|
||||||
.Dd Oct 17, 2020
|
.Dd Apr 24, 2023
|
||||||
.Dt FINIT.CONF 5 SMM
|
.Dt FINIT.CONF 5 SMM
|
||||||
.Os Linux
|
.Os Linux
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@@ -47,13 +47,20 @@ Available services
|
|||||||
Enabled services, symlinks from available
|
Enabled services, symlinks from available
|
||||||
.El
|
.El
|
||||||
.Sh FILE FORMAT
|
.Sh FILE FORMAT
|
||||||
Lines starting with `#' are ignored. Note that end-of-line comments are
|
The file format is line based, empty lines and comments, lines starting
|
||||||
NOT supported, comments must be on a line of their own.
|
with `#', are ignored. A configuration directive starts with a keyword
|
||||||
|
followed by a space and the rest of the line is treated as the value.
|
||||||
.Pp
|
.Pp
|
||||||
A configuration stanza must be on a single (long) line and
|
As of Finit v4.4, configuration directives can be broken up in multiple
|
||||||
.Em cannot
|
lines using the continuation character `\\', and trailing comments are
|
||||||
be broken up in multiple lines by use of a backslash as the last
|
also allowed. Example:
|
||||||
character.
|
.Bd -unfilled -offset indent
|
||||||
|
# Escape \\# chars if you want them literal in, e.g., descriptions
|
||||||
|
service name:sysklogd [S123456789] \\
|
||||||
|
env:-/etc/default/sysklogd \\
|
||||||
|
syslogd -F $SYSLOGD_ARGS \\
|
||||||
|
-- System log daemon \\# 1 # Comments allowed now
|
||||||
|
.Ed
|
||||||
.Sh DIRECTIVES
|
.Sh DIRECTIVES
|
||||||
This section lists all supported configuration directives. There also exist
|
This section lists all supported configuration directives. There also exist
|
||||||
deprecated directives, see the Markdown documentation for details on these.
|
deprecated directives, see the Markdown documentation for details on these.
|
||||||
@@ -108,6 +115,10 @@ is the runlevel number 0-9, where 6 is reserved for reboot and 0 for
|
|||||||
halt. All other can be used by operating system administrators.
|
halt. All other can be used by operating system administrators.
|
||||||
Default: 2
|
Default: 2
|
||||||
.Pp
|
.Pp
|
||||||
|
It s recommended to keep runlevel 1 as single-user mode, because
|
||||||
|
.Nm
|
||||||
|
disables networking in this mode.
|
||||||
|
.Pp
|
||||||
.Sy Note:
|
.Sy Note:
|
||||||
only read and executed in runlevel S (bootstrap).
|
only read and executed in runlevel S (bootstrap).
|
||||||
.It Cm run Oo LVLS Oc Ao COND Ac Ar /path/to/cmd ARGS Op -- Optional description
|
.It Cm run Oo LVLS Oc Ao COND Ac Ar /path/to/cmd ARGS Op -- Optional description
|
||||||
@@ -275,6 +286,51 @@ can depend on the
|
|||||||
.Cm <pid/bar>
|
.Cm <pid/bar>
|
||||||
condition.
|
condition.
|
||||||
.Pp
|
.Pp
|
||||||
|
As an alternative "readiness" notification, Finit supports both systemd
|
||||||
|
and s6 style notification. This can be enabled by using the `notify`
|
||||||
|
option:
|
||||||
|
.Bl -tag -width 1n
|
||||||
|
.It Cm notify:systemd
|
||||||
|
tells Finit the service uses the
|
||||||
|
.Cm sd_notify()
|
||||||
|
API to signal PID 1 when it has completed its startup and is ready
|
||||||
|
to service events. This API expects
|
||||||
|
the environment variable
|
||||||
|
.Cm NOTIFY_SOCKET
|
||||||
|
to be set to the socket where the application can send
|
||||||
|
.Cm "READY=1\n"
|
||||||
|
when it is starting up or has processed a
|
||||||
|
.Cm SIGHUP .
|
||||||
|
For details, see:
|
||||||
|
.Pp
|
||||||
|
.Lk https://www.freedesktop.org/software/systemd/man/sd_notify.html
|
||||||
|
.It Cm notify:s6
|
||||||
|
puts Finit in s6 compatibility mode. Compared to the systemd
|
||||||
|
notification, s6 expect compliant daemons to send
|
||||||
|
.Cm "\\n"
|
||||||
|
and then close their socket. For details, see:
|
||||||
|
.Pp
|
||||||
|
.Lk https://skarnet.org/software/s6/notifywhenup.html
|
||||||
|
.Pp
|
||||||
|
Finit takes care of "hard-wiring" the READY state as long as the
|
||||||
|
application is running, events across any `SIGHUP`. Since s6 can give
|
||||||
|
its applications the descriptor number (must be >3) on then command
|
||||||
|
line, Finit provides the following syntax (
|
||||||
|
.Cm %n
|
||||||
|
is replaced by Finit with then descriptor number):
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
service notify:s6 mdevd -C -O 4 -D %n
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
When a service is ready, either by Finit detecting its PID file, or
|
||||||
|
their respective readiness mechanism has been triggered, Finit creates
|
||||||
|
then service's ready condition which other services can depend on:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
$ initctl -v cond get service/mdevd/ready
|
||||||
|
on
|
||||||
|
.Ed
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
If a service should not be automatically started, it can be configured
|
If a service should not be automatically started, it can be configured
|
||||||
as manual with the
|
as manual with the
|
||||||
.Cm manual:yes
|
.Cm manual:yes
|
||||||
@@ -304,6 +360,10 @@ number of seconds before Finit tries to restart
|
|||||||
a crashing service, default: 2 seconds for the first five retries,
|
a crashing service, default: 2 seconds for the first five retries,
|
||||||
then back-off to 5 seconds. The maximum of this configured value
|
then back-off to 5 seconds. The maximum of this configured value
|
||||||
and the above (2 and 5) will be used
|
and the above (2 and 5) will be used
|
||||||
|
.It Cm restart:always
|
||||||
|
no upper limit on the number of times Finit tries to restart a crashing
|
||||||
|
service. Same as
|
||||||
|
.Cm restart:-1
|
||||||
.It Cm norestart
|
.It Cm norestart
|
||||||
dont restart on failures, same as
|
dont restart on failures, same as
|
||||||
.Cm restart:0
|
.Cm restart:0
|
||||||
@@ -318,10 +378,21 @@ was originally designed for so not the default behavior.
|
|||||||
when all retries have failed, and the service
|
when all retries have failed, and the service
|
||||||
has
|
has
|
||||||
.Em crashed ,
|
.Em crashed ,
|
||||||
if this option is set the system is rebooted. Note, future releases
|
if this option is set the system is rebooted.
|
||||||
may include other
|
.It Cm oncrash:script
|
||||||
.Cm oncrash:
|
Similar to
|
||||||
actions.
|
.Cm oncrash:reboot ,
|
||||||
|
but instead of rebooting this action calls the
|
||||||
|
.Cm post:script
|
||||||
|
(see below) to let the operator decide the best course of action. If
|
||||||
|
the post:script option is not set, this is a no-op.
|
||||||
|
.Pp
|
||||||
|
The post:script is called with the same environment variables
|
||||||
|
.Sy except
|
||||||
|
for the
|
||||||
|
.Cm EXIT_CODE
|
||||||
|
variable which is set to
|
||||||
|
.Cm "crashed" .
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
When stopping a service (run/task/sysv/service), either manually or when
|
When stopping a service (run/task/sysv/service), either manually or when
|
||||||
@@ -364,11 +435,13 @@ or any unique identifier specified in the .conf file. The
|
|||||||
.Cm post:script
|
.Cm post:script
|
||||||
is called with an additional set of environment variables:
|
is called with an additional set of environment variables:
|
||||||
.Bl -tag -offset indent -width 1n
|
.Bl -tag -offset indent -width 1n
|
||||||
.It Cm EXIT_CODE=[exited,signal]
|
.It Cm EXIT_CODE=[exited,signal,crashed]
|
||||||
set to one of
|
set to one of
|
||||||
.Cm exited
|
.Cm exited ,
|
||||||
|
.Cm signal ,
|
||||||
or
|
or
|
||||||
.Cm signal
|
.Cm crashed
|
||||||
|
(see above).
|
||||||
.It Cm EXIT_STATUS=[num,SIGNAME]
|
.It Cm EXIT_STATUS=[num,SIGNAME]
|
||||||
set to one of exit status code from the program, if it exited normally,
|
set to one of exit status code from the program, if it exited normally,
|
||||||
or the signal name (HUP, TERM, etc.) if it exited due to signal
|
or the signal name (HUP, TERM, etc.) if it exited due to signal
|
||||||
@@ -378,13 +451,6 @@ The scripts have a default execution time of 3 seconds before they are
|
|||||||
SIGKILLed, this can be adjusted using the
|
SIGKILLed, this can be adjusted using the
|
||||||
.Cm kill:SEC
|
.Cm kill:SEC
|
||||||
modifier syntax.
|
modifier syntax.
|
||||||
.Pp
|
|
||||||
.Sy Note:
|
|
||||||
the
|
|
||||||
.Cm pre:script
|
|
||||||
.Em must
|
|
||||||
be idempotent, because a service can transition between READY and HALTED
|
|
||||||
states any number of times before going to RUNNING.
|
|
||||||
.It Cm runparts Aq DIR
|
.It Cm runparts Aq DIR
|
||||||
Call
|
Call
|
||||||
.Xr run-parts 8
|
.Xr run-parts 8
|
||||||
@@ -753,6 +819,31 @@ the example sets
|
|||||||
to denote that it doesn't support SIGHUP. That way Finit will
|
to denote that it doesn't support SIGHUP. That way Finit will
|
||||||
stop/start the service instead of sending SIGHUP at restart/reload
|
stop/start the service instead of sending SIGHUP at restart/reload
|
||||||
events.
|
events.
|
||||||
|
.Sh TEMPLATING
|
||||||
|
Finit comes with rudimentary support for templating, similar to that of
|
||||||
|
systemd. Best illustrated with an example:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
$ initctl show avahi-autoipd@
|
||||||
|
service :%i avahi-autoipd --syslog %i -- ZeroConf for %i
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
To enable ZeroConf for, e.g.,
|
||||||
|
.Cm eth0 ,
|
||||||
|
use
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
$ initctl enable avahi-autoipd@eth0.conf
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
The enabled symlink will be set up to
|
||||||
|
.Cm avahi-autoipd@.conf
|
||||||
|
and every instance of
|
||||||
|
.Cm %i
|
||||||
|
will in the instantiated directive be replaced with
|
||||||
|
.Cm eth0 .
|
||||||
|
Inspect the result with:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
$ initctl status avahi-autoipd:eth0
|
||||||
|
.Ed
|
||||||
.Sh CGROUPS
|
.Sh CGROUPS
|
||||||
There are three major cgroup configuration directives:
|
There are three major cgroup configuration directives:
|
||||||
.Pp
|
.Pp
|
||||||
|
|||||||
+67
-31
@@ -11,7 +11,7 @@
|
|||||||
.Nd Control tool for Finit
|
.Nd Control tool for Finit
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm /sbin/initctl
|
.Nm /sbin/initctl
|
||||||
.Op Fl bcfhlpqtvV
|
.Op Fl bcfhjlpqtvV
|
||||||
.Op COMMAND
|
.Op COMMAND
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
.Nm
|
.Nm
|
||||||
@@ -33,6 +33,18 @@ command.
|
|||||||
Ignore missing files and arguments, never prompt.
|
Ignore missing files and arguments, never prompt.
|
||||||
.It Fl h, -help
|
.It Fl h, -help
|
||||||
Show built-in help text.
|
Show built-in help text.
|
||||||
|
.It Fl j, -json
|
||||||
|
JSON output in
|
||||||
|
.Ar status
|
||||||
|
and
|
||||||
|
.Ar cond
|
||||||
|
commands.
|
||||||
|
.It Fl n, -noerr
|
||||||
|
When scripting
|
||||||
|
.Nm
|
||||||
|
to stop, start, restart, or signal a task or service, this option can be
|
||||||
|
used to ignore error 69 (no such task or service) and instead return 0
|
||||||
|
(OK).
|
||||||
.It Fl 1, -once
|
.It Fl 1, -once
|
||||||
Only one lap in commands like top.
|
Only one lap in commands like top.
|
||||||
.It Fl p, -plain
|
.It Fl p, -plain
|
||||||
@@ -54,9 +66,9 @@ Toggle
|
|||||||
(daemon) debug to
|
(daemon) debug to
|
||||||
.Pa /dev/console
|
.Pa /dev/console
|
||||||
.It Nm Ar help
|
.It Nm Ar help
|
||||||
Show built-in help text
|
Show built-in help text.
|
||||||
.It Nm Ar version
|
.It Nm Ar version
|
||||||
Show program version
|
Show program version.
|
||||||
.It Nm Ar ls | list
|
.It Nm Ar ls | list
|
||||||
List all
|
List all
|
||||||
.Cm *.conf
|
.Cm *.conf
|
||||||
@@ -115,13 +127,13 @@ Disable
|
|||||||
.Cm .conf
|
.Cm .conf
|
||||||
in
|
in
|
||||||
.Pa /etc/finit.d/enabled ,
|
.Pa /etc/finit.d/enabled ,
|
||||||
i.e., removes symlink
|
i.e., removes symlink.
|
||||||
.It Nm Ar reload
|
.It Nm Ar reload
|
||||||
Reload
|
Reload
|
||||||
.Cm *.conf in
|
.Cm *.conf in
|
||||||
.Pa /etc/finit.d ,
|
.Pa /etc/finit.d ,
|
||||||
i.e., activates changes
|
i.e., activates changes.
|
||||||
.It Nm Ar cond set Ar COND
|
.It Nm Ar cond set Ar COND Op COND ...
|
||||||
Set (assert) user-defined condition,
|
Set (assert) user-defined condition,
|
||||||
.Cm +usr/COND
|
.Cm +usr/COND
|
||||||
.It Nm Ar cond get Ar COND
|
.It Nm Ar cond get Ar COND
|
||||||
@@ -133,36 +145,40 @@ or
|
|||||||
then any condition can be read.
|
then any condition can be read.
|
||||||
.Pp
|
.Pp
|
||||||
The command is geared for scripting, check the exit code to get the
|
The command is geared for scripting, check the exit code to get the
|
||||||
status of the condition, or give
|
status of the condition: 0 - on, 1 - off, 255 - flux. For a more
|
||||||
.Nm
|
verbose output, use the
|
||||||
the
|
|
||||||
.Fl v
|
.Fl v
|
||||||
option for a more verbose output.
|
option.
|
||||||
.It Nm Ar cond clr | clear Ar COND
|
.It Nm Ar cond clr | clear Ar COND Op COND ...
|
||||||
Clear (deassert) user-defined condition,
|
Clear (deassert) user-defined condition,
|
||||||
.Cm -usr/COND
|
.Cm -usr/COND
|
||||||
.It Nm Ar cond status
|
.It Nm Ar cond status
|
||||||
Show condition status, default
|
Show condition status, default
|
||||||
.Cm cond
|
.Cm cond
|
||||||
command.
|
command. Also supports the
|
||||||
.It Nm Ar cond dump
|
.Fl j
|
||||||
Dump all conditions and their status
|
option for detailed JSON output.
|
||||||
|
.It Nm Ar cond dump Op Cm TYPE
|
||||||
|
Dump all, or a given type of, conditions and their status. Also
|
||||||
|
supports the
|
||||||
|
.Fl j
|
||||||
|
option for detailed JSON output.
|
||||||
.It Nm Ar ident Op Cm NAME
|
.It Nm Ar ident Op Cm NAME
|
||||||
Display indentities of all run/task/services, or only instances
|
Display indentities of all run/task/services, or only instances
|
||||||
matching
|
matching
|
||||||
.Cm NAME .
|
.Cm NAME .
|
||||||
A partial string, e.g.,
|
A partial string, e.g.,
|
||||||
.Cm NAM ,
|
.Cm NAM ,
|
||||||
will not match anything
|
will not match anything.
|
||||||
.It Nm Ar log Op Cm NAME
|
.It Nm Ar log Op Cm NAME
|
||||||
Show ten last Finit, or
|
Show ten last Finit, or
|
||||||
.Cm NAME ,
|
.Cm NAME ,
|
||||||
messages from syslog
|
messages from syslog.
|
||||||
.It Nm Ar start Cm NAME[:ID]
|
.It Nm Ar start Cm NAME[:ID]
|
||||||
Start service by name, with optional ID, e.g.,
|
Start service by name, with optional ID, e.g.,
|
||||||
.Cm initctl start tty:1
|
.Cm initctl start tty:1
|
||||||
.It Nm Ar stop Cm NAME[:ID]
|
.It Nm Ar stop Cm NAME[:ID]
|
||||||
Stop/Pause a running service by name
|
Stop/Pause a running service by name.
|
||||||
.It Nm Ar reload Cm NAME[:ID]
|
.It Nm Ar reload Cm NAME[:ID]
|
||||||
Reload service as if its configuration had changed. Internally,
|
Reload service as if its configuration had changed. Internally,
|
||||||
.Nm finit
|
.Nm finit
|
||||||
@@ -180,52 +196,72 @@ Except for two things:
|
|||||||
if the service supports HUP, it's signaled instead of stop-started, and
|
if the service supports HUP, it's signaled instead of stop-started, and
|
||||||
.It
|
.It
|
||||||
it allows restarting run/task in the same runlevel -- which is otherwise
|
it allows restarting run/task in the same runlevel -- which is otherwise
|
||||||
restricted
|
restricted.
|
||||||
.El
|
.El
|
||||||
.It Nm Ar signal Cm NAME:[ID] S
|
.It Nm Ar signal Cm NAME:[ID] S
|
||||||
Send signal S to service, by name.
|
Send signal S to service, by name.
|
||||||
.Cm S
|
.Cm S
|
||||||
may be a complete signal name such as SIGHUP, or short name such as HUP, or the signal number such as 1 (SIGHUP).
|
may be a complete signal name such as SIGHUP, or short name such as HUP, or the signal number such as 1 (SIGHUP).
|
||||||
.It Nm Ar restart Cm NAME[:ID]
|
.It Nm Ar restart Cm NAME[:ID]
|
||||||
Restart (stop/start) service by name
|
Restart (stop/start) service by name.
|
||||||
.It Nm Ar status Cm NAME[:ID]
|
.It Nm Ar status Cm NAME[:ID]
|
||||||
Show service status, by name. If only
|
Show service status, by name. If only
|
||||||
.Cm NAME
|
.Cm NAME
|
||||||
is given and multiple instances exits, a summary of all matching
|
is given and multiple instances exits, a summary of all matching
|
||||||
instances are shown. Only an exact match displays the detailed status
|
instances are shown. Only an exact match displays detailed status
|
||||||
for a particular instance
|
for a given instance.
|
||||||
|
.Pp
|
||||||
|
With the
|
||||||
|
.Fl q
|
||||||
|
option this command is silent, provided the
|
||||||
|
.Ar NAME[:ID]
|
||||||
|
selection matches a single run/task/service. The exit code of
|
||||||
|
.Nm
|
||||||
|
is non-zero if there is a problem. Zero is returned if a run/task has
|
||||||
|
run (at least) once in the current runlevel, and when a service is running
|
||||||
|
(as expected). See the
|
||||||
|
.Fl j
|
||||||
|
option for detailed JSON output suitable for machine parsing.
|
||||||
|
.Pp
|
||||||
|
.Sy Tip:
|
||||||
|
.Xr jq 1
|
||||||
|
is a useful scripting tool in combination with JSON output.
|
||||||
.It Nm Ar status
|
.It Nm Ar status
|
||||||
Show status of all services, default command
|
Show status of all services, default command. Also supports the
|
||||||
|
.Fl j
|
||||||
|
option for detailed JSON output.
|
||||||
.It Nm Ar cgroup
|
.It Nm Ar cgroup
|
||||||
List cgroup config overview
|
List cgroup config overview.
|
||||||
.It Nm Ar ps
|
.It Nm Ar ps
|
||||||
List processes based on cgroups
|
List processes based on cgroups.
|
||||||
.It Nm Ar top
|
.It Nm Ar top
|
||||||
Show top-like listing based on cgroups
|
Show top-like listing based on cgroups.
|
||||||
|
.It Nm Ar plugins
|
||||||
|
List installed plugins.
|
||||||
.It Nm Ar runlevel Op Ar 0-9
|
.It Nm Ar runlevel Op Ar 0-9
|
||||||
Show or set runlevel: 0 halt, 6 reboot
|
Show or set runlevel: 0 halt, 6 reboot.
|
||||||
.It Nm Ar reboot
|
.It Nm Ar reboot
|
||||||
Reboot system, default if
|
Reboot system, default if
|
||||||
.Cm reboot
|
.Cm reboot
|
||||||
is symlinked to
|
is symlinked to
|
||||||
.Nm
|
.Nm .
|
||||||
.It Nm Ar halt
|
.It Nm Ar halt
|
||||||
Halt system, default if
|
Halt system, default if
|
||||||
.Cm halt
|
.Cm halt
|
||||||
is symlinked to
|
is symlinked to
|
||||||
.Nm
|
.Nm .
|
||||||
.It Nm Ar poweroff
|
.It Nm Ar poweroff
|
||||||
Power-off system, default if
|
Power-off system, default if
|
||||||
.Cm poweroff
|
.Cm poweroff
|
||||||
is symlinked to
|
is symlinked to
|
||||||
.Nm
|
.Nm .
|
||||||
.It Nm Ar suspend
|
.It Nm Ar suspend
|
||||||
Suspend system, default if
|
Suspend system, default if
|
||||||
.Cm suspend
|
.Cm suspend
|
||||||
is symlinked to
|
is symlinked to
|
||||||
.Nm
|
.Nm .
|
||||||
.It Nm Ar utmp show
|
.It Nm Ar utmp show
|
||||||
Raw dump of UTMP/WTMP db
|
Raw dump of UTMP/WTMP db.
|
||||||
.El
|
.El
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr finit.conf 5
|
.Xr finit.conf 5
|
||||||
|
|||||||
+2
-10
@@ -1,9 +1,9 @@
|
|||||||
pkglibdir = $(plugin_path)
|
pkglibdir = $(plugin_path)
|
||||||
AM_LDFLAGS = -module -avoid-version -shared
|
AM_LDFLAGS = -module -avoid-version -shared
|
||||||
AM_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
AM_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||||
AM_CPPFLAGS = -I$(top_srcdir)/src -U_FORTIFY_SOURCE
|
AM_CPPFLAGS = -I$(top_srcdir)/src
|
||||||
AM_CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
|
AM_CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
|
||||||
AM_CPPFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
|
AM_CPPFLAGS += -D__FINIT__ $(lite_CFLAGS) $(uev_CFLAGS)
|
||||||
|
|
||||||
if STATIC
|
if STATIC
|
||||||
noinst_LTLIBRARIES = libplug.la
|
noinst_LTLIBRARIES = libplug.la
|
||||||
@@ -17,10 +17,6 @@ if BUILD_DBUS_PLUGIN
|
|||||||
libplug_la_SOURCES += dbus.c
|
libplug_la_SOURCES += dbus.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if BUILD_HOTPLUG_PLUGIN
|
|
||||||
libplug_la_SOURCES += hotplug.c
|
|
||||||
endif
|
|
||||||
|
|
||||||
if BUILD_MODULES_LOAD_PLUGIN
|
if BUILD_MODULES_LOAD_PLUGIN
|
||||||
libplug_la_SOURCES += modules-load.c
|
libplug_la_SOURCES += modules-load.c
|
||||||
endif
|
endif
|
||||||
@@ -68,10 +64,6 @@ if BUILD_HOOK_SCRIPTS_PLUGIN
|
|||||||
pkglib_LTLIBRARIES += hook-scripts.la
|
pkglib_LTLIBRARIES += hook-scripts.la
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if BUILD_HOTPLUG_PLUGIN
|
|
||||||
pkglib_LTLIBRARIES += hotplug.la
|
|
||||||
endif
|
|
||||||
|
|
||||||
if BUILD_MODULES_LOAD_PLUGIN
|
if BUILD_MODULES_LOAD_PLUGIN
|
||||||
pkglib_LTLIBRARIES += modules-load.la
|
pkglib_LTLIBRARIES += modules-load.la
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* Save and restore ALSA sound settings using alsactl
|
/* Save and restore ALSA sound settings using alsactl
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -36,12 +36,12 @@
|
|||||||
static void save(void *arg)
|
static void save(void *arg)
|
||||||
{
|
{
|
||||||
if (rescue) {
|
if (rescue) {
|
||||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (whichp(ALSACTL)) {
|
if (whichp(ALSACTL)) {
|
||||||
_d("Saving sound settings ...");
|
dbg("Saving sound settings ...");
|
||||||
run_interactive(ALSACTL " -g store", "Saving sound settings");
|
run_interactive(ALSACTL " -g store", "Saving sound settings");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,12 +49,12 @@ static void save(void *arg)
|
|||||||
static void restore(void *arg)
|
static void restore(void *arg)
|
||||||
{
|
{
|
||||||
if (rescue) {
|
if (rescue) {
|
||||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (whichp(ALSACTL)) {
|
if (whichp(ALSACTL)) {
|
||||||
_d("Restoring sound settings ...");
|
dbg("Restoring sound settings ...");
|
||||||
run_interactive(ALSACTL " -g restore", "Restoring sound settings");
|
run_interactive(ALSACTL " -g restore", "Restoring sound settings");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+43
-81
@@ -1,6 +1,6 @@
|
|||||||
/* Setup necessary system files for, e.g. UTMP (tracking logins)
|
/* Setup necessary system files for, e.g. UTMP (tracking logins)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -38,6 +38,7 @@
|
|||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
#include "tmpfiles.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "utmp-api.h"
|
#include "utmp-api.h"
|
||||||
|
|
||||||
@@ -80,7 +81,7 @@ static int bootclean(const char *fpath, const struct stat *sb, int tflag, struct
|
|||||||
if (ftw->level == 0)
|
if (ftw->level == 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
_d("Removing %s ...", fpath);
|
dbg("Removing %s ...", fpath);
|
||||||
(void)remove(fpath);
|
(void)remove(fpath);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -110,10 +111,43 @@ static void clean(void *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ln(const char *target, const char *linkpath)
|
/* Kernel defines the following compulsory and recommended links
|
||||||
|
* https://github.com/torvalds/linux/blob/v5.18/Documentation/admin-guide/devices.rst#compulsory-links
|
||||||
|
*/
|
||||||
|
static void kernel_links(void)
|
||||||
{
|
{
|
||||||
if (symlink(target, linkpath) && errno != EEXIST)
|
struct {
|
||||||
_pe("Failed creating %s -> %s symlink", target, linkpath);
|
char *tgt, *lnk;
|
||||||
|
int optional;
|
||||||
|
} k[] = {
|
||||||
|
{ "/proc/self/fd", "/dev/fd", 0 },
|
||||||
|
{ "fd/0", "/dev/stdin", 0 },
|
||||||
|
{ "fd/1", "/dev/stdout", 0 },
|
||||||
|
{ "fd/2", "/dev/stderr", 0 },
|
||||||
|
{ "socksys", "/dev/nfsd", 0 },
|
||||||
|
{ "null", "/dev/X0R", 0 },
|
||||||
|
{ "/proc/kcore", "/dev/core", 1 },
|
||||||
|
{ "ram0", "/dev/ramdisk", 1 },
|
||||||
|
{ "qft0", "/dev/ftape", 1 },
|
||||||
|
{ "video0", "/dev/bttv0", 1 },
|
||||||
|
{ "radio0", "/dev/radio", 1 },
|
||||||
|
};
|
||||||
|
char *fn, buf[80];
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < NELEMS(k); i++) {
|
||||||
|
fn = k[i].tgt;
|
||||||
|
|
||||||
|
if (k[i].optional) {
|
||||||
|
if (fn[0] != '/') {
|
||||||
|
snprintf(buf, sizeof(buf), "/dev/%s", k[i].tgt);
|
||||||
|
fn = buf;
|
||||||
|
}
|
||||||
|
if (!fexist(fn))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ln(k[i].tgt, k[i].lnk);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -125,87 +159,15 @@ static void setup(void *arg)
|
|||||||
|
|
||||||
prev = umask(0);
|
prev = umask(0);
|
||||||
|
|
||||||
_d("Setting up FHS structure in /var ...");
|
/* Kernel symlinks, e.g. /proc/self/fd -> /dev/fd */
|
||||||
makedir("/var/cache", 0755);
|
kernel_links();
|
||||||
makedir("/var/db", 0755); /* _PATH_VARDB on some systems */
|
|
||||||
makedir("/var/games", 0755);
|
|
||||||
makedir("/var/lib", 0755);
|
|
||||||
makedir("/var/lib/misc", 0755); /* _PATH_VARDB on some systems */
|
|
||||||
makedir("/var/lib/alarm", 0755);
|
|
||||||
makedir("/var/lib/urandom",0755);
|
|
||||||
if (fisdir("/run")) {
|
|
||||||
_d("System with new /run tmpfs ...");
|
|
||||||
if (!fisdir("/run/lock"))
|
|
||||||
makedir("/run/lock", 1777);
|
|
||||||
ln("/run/lock", "/var/lock");
|
|
||||||
ln("/dev/shm", "/run/shm");
|
|
||||||
|
|
||||||
/* compat only, should really be set up by OS/dist */
|
/* Create all system tmpfiles.d(5) */
|
||||||
ln("/run", "/var/run");
|
tmpfilesd();
|
||||||
} else {
|
|
||||||
makedir("/var/lock", 1777);
|
|
||||||
makedir("/var/run", 0755);
|
|
||||||
}
|
|
||||||
makedir("/var/log", 0755);
|
|
||||||
makedir("/var/mail", 0755);
|
|
||||||
makedir("/var/opt", 0755);
|
|
||||||
makedir("/var/spool", 0755);
|
|
||||||
makedir("/var/spool/cron", 0755);
|
|
||||||
makedir("/var/tmp", 0755);
|
|
||||||
makedir("/var/empty", 0755);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* UTMP actually needs multiple db files
|
|
||||||
*/
|
|
||||||
if (has_utmp()) {
|
|
||||||
int gid;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If /etc/group or "utmp" group is missing, default to
|
|
||||||
* "root", or "wheel", group.
|
|
||||||
*/
|
|
||||||
_d("Setting up necessary UTMP files ...");
|
|
||||||
gid = getgroup("utmp");
|
|
||||||
if (gid < 0)
|
|
||||||
gid = 0;
|
|
||||||
|
|
||||||
create("/var/run/utmp", 0644, 0, gid); /* Currently logged in */
|
|
||||||
create("/var/log/wtmp", 0644, 0, gid); /* Login history */
|
|
||||||
create("/var/log/btmp", 0600, 0, gid); /* Failed logins */
|
|
||||||
create("/var/log/lastlog", 0644, 0, gid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set BOOT_TIME UTMP entry */
|
/* Set BOOT_TIME UTMP entry */
|
||||||
utmp_set_boot();
|
utmp_set_boot();
|
||||||
|
|
||||||
#ifdef TOUCH_ETC_NETWORK_RUN_IFSTATE
|
|
||||||
touch("/etc/network/run/ifstate");
|
|
||||||
#else
|
|
||||||
erase("/etc/network/run/ifstate");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_d("Setting up misc files ...");
|
|
||||||
makedir("/var/run/network",0755); /* Needed by Debian/Ubuntu ifupdown */
|
|
||||||
makedir("/var/run/lldpd", 0755); /* Needed by lldpd */
|
|
||||||
makedir("/var/run/pluto", 0755); /* Needed by Openswan */
|
|
||||||
mksubsys("/var/run/quagga", 0755, "quagga", "quagga");
|
|
||||||
mksubsys("/var/log/quagga", 0755, "quagga", "quagga");
|
|
||||||
mksubsys("/var/run/frr", 0755, "frr", "frr");
|
|
||||||
mksubsys("/var/log/frr", 0755, "frr", "frr");
|
|
||||||
makedir("/var/run/sshd", 01755); /* OpenSSH */
|
|
||||||
|
|
||||||
if (!fexist("/etc/mtab"))
|
|
||||||
ln("../proc/self/mounts", "/etc/mtab");
|
|
||||||
|
|
||||||
/* Void Linux has a uuidd that runs as uuid:uuid and needs /run/uuid */
|
|
||||||
mksubsys("/var/run/uuidd", 0755, "uuidd", "uuidd");
|
|
||||||
|
|
||||||
/* Debian has /run/sudo, ensure correct perms and SELinux label */
|
|
||||||
mksubsys("/var/run/sudo", 0711, "root", "root");
|
|
||||||
mksubsys("/var/run/sudo/ts", 0700, "root", "root");
|
|
||||||
if (whichp("restorecon"))
|
|
||||||
run("restorecon /var/run/sudo /var/run/sudo/ts", "restorecon");
|
|
||||||
|
|
||||||
umask(prev);
|
umask(prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+102
-26
@@ -1,6 +1,6 @@
|
|||||||
/* Setup and start system message bus, D-Bus
|
/* Setup and start system message bus, D-Bus
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -35,60 +35,136 @@
|
|||||||
#include "service.h"
|
#include "service.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
|
||||||
#define DAEMON "dbus-daemon"
|
#define DBUS_DAEMON "dbus-daemon"
|
||||||
#define ARGS "--nofork --system --syslog-only"
|
#define DBUS_ARGS "--nofork --system --syslog-only"
|
||||||
#define DESC "D-Bus message bus daemon"
|
#define DBUS_DESC "D-Bus message bus daemon"
|
||||||
|
|
||||||
#ifndef DAEMONUSER
|
#ifndef DBUS_DAEMONUSER
|
||||||
#define DAEMONUSER "messagebus"
|
#define DBUS_DAEMONUSER "messagebus"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef DAEMONPIDFILE
|
#ifndef DBUS_DAEMONGROUP
|
||||||
#define DAEMONPIDFILE "/var/run/dbus/pid"
|
#define DBUS_DAEMONGROUP "messagebus"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dumnpster diving for the D-Bus main configuration file
|
||||||
|
* where <pidfile> is defined.
|
||||||
|
*/
|
||||||
|
static char *dbus_pidfn(void)
|
||||||
|
{
|
||||||
|
char *alt[] = {
|
||||||
|
"/usr/share/dbus-1/system.conf",
|
||||||
|
"/etc/dbus-1/system.conf",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; alt[i]; i++) {
|
||||||
|
char *fn = alt[i];
|
||||||
|
char buf[256];
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopen(fn, "r");
|
||||||
|
if (!fp)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
fn = NULL;
|
||||||
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
char *pos;
|
||||||
|
|
||||||
|
pos = strstr(buf, "<pidfile>");
|
||||||
|
if (!pos)
|
||||||
|
continue;
|
||||||
|
fn = pos + strlen("<pidfile>");
|
||||||
|
pos = strstr(fn, "</pidfile>");
|
||||||
|
if (!pos) {
|
||||||
|
fn = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
if (fn)
|
||||||
|
return strdup(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
{
|
{
|
||||||
|
char *group = DBUS_DAEMONGROUP;
|
||||||
|
char *user = DBUS_DAEMONUSER;
|
||||||
char line[256];
|
char line[256];
|
||||||
|
char *pidfn;
|
||||||
mode_t prev;
|
mode_t prev;
|
||||||
char *cmd;
|
char *cmd;
|
||||||
|
|
||||||
if (rescue) {
|
if (rescue) {
|
||||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = which(DAEMON);
|
cmd = which(DBUS_DAEMON);
|
||||||
if (!cmd) {
|
if (!cmd) {
|
||||||
_d("Skipping plugin, %s is not installed.", DAEMON);
|
dbg("Skipping plugin, %s is not installed.", DBUS_DAEMON);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
prev =umask(0);
|
if (getuser(user, NULL) == -1) {
|
||||||
|
if (getuser("dbus", NULL) == -1)
|
||||||
|
user = "root"; /* fallback */
|
||||||
|
else
|
||||||
|
user = "dbus"; /* e.g., Buildroot */
|
||||||
|
}
|
||||||
|
|
||||||
mksubsys("/var/run/dbus", 0755, DAEMONUSER, DAEMONUSER);
|
if (getgroup(group) == -1) {
|
||||||
|
if (getgroup("dbus") == -1)
|
||||||
|
group = "root"; /* fallback */
|
||||||
|
else
|
||||||
|
group = "dbus"; /* e.g., Buildroot */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clean up from any previous pre-bootstrap run */
|
||||||
|
pidfn = dbus_pidfn();
|
||||||
|
if (pidfn)
|
||||||
|
remove(pidfn);
|
||||||
|
|
||||||
|
dbg("Creating D-Bus Required Directories ...");
|
||||||
|
prev = umask(0);
|
||||||
|
mksubsys("/var/run/dbus", 0755, user, group);
|
||||||
|
mksubsys("/var/run/lock/subsys", 0755, user, group);
|
||||||
|
mksubsys("/var/lib/dbus", 0755, user, group);
|
||||||
|
mksubsys("/tmp/dbus", 0755, user, group);
|
||||||
|
umask(prev);
|
||||||
|
|
||||||
|
/* Generate machine id for dbus */
|
||||||
if (whichp("dbus-uuidgen"))
|
if (whichp("dbus-uuidgen"))
|
||||||
run_interactive("dbus-uuidgen --ensure", "Creating machine UUID for D-Bus");
|
run_interactive("dbus-uuidgen --ensure", "Creating machine UUID for D-Bus");
|
||||||
|
|
||||||
/* Clean up from any previous pre-bootstrap run */
|
/*
|
||||||
remove(DAEMONPIDFILE);
|
* 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",
|
||||||
|
pidfn, cmd, DBUS_ARGS, DBUS_DESC);
|
||||||
|
free(pidfn);
|
||||||
|
} else
|
||||||
|
snprintf(line, sizeof(line), "[S123456789] cgroup.system name:dbus %s %s -- %s",
|
||||||
|
cmd, DBUS_ARGS, DBUS_DESC);
|
||||||
|
|
||||||
/* Register service with Finit */
|
|
||||||
snprintf(line, sizeof(line), "[S12345789] cgroup.system pid:!%s @%s:%s %s %s -- %s",
|
|
||||||
DAEMONPIDFILE, DAEMONUSER, DAEMONUSER, cmd, ARGS, DESC);
|
|
||||||
if (service_register(SVC_TYPE_SERVICE, line, global_rlimit, NULL))
|
if (service_register(SVC_TYPE_SERVICE, line, global_rlimit, NULL))
|
||||||
_pe("Failed registering %s", DAEMON);
|
err(1, "Failed registering %s", DBUS_DAEMON);
|
||||||
free(cmd);
|
|
||||||
|
|
||||||
umask(prev);
|
free(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
.name = __FILE__,
|
.name = __FILE__,
|
||||||
.hook[HOOK_BASEFS_UP] = {
|
.hook[HOOK_SVC_PLUGIN] = { .cb = setup },
|
||||||
.cb = setup
|
|
||||||
},
|
|
||||||
.depends = { "bootmisc", },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
|
|||||||
+11
-10
@@ -26,18 +26,11 @@
|
|||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#define CHOOSE(x, y) y
|
extern void plugin_script_run(hook_point_t no);
|
||||||
static const char *hscript_paths[] = HOOK_TYPES;
|
|
||||||
#undef CHOOSE
|
|
||||||
|
|
||||||
static void hscript_run_parts(hook_point_t hook)
|
static void hscript_run_parts(hook_point_t no)
|
||||||
{
|
{
|
||||||
char path[CMD_SIZE] = "";
|
plugin_script_run(no);
|
||||||
|
|
||||||
strlcat(path, PLUGIN_HOOK_SCRIPTS_PATH, sizeof(path));
|
|
||||||
strlcat(path, hscript_paths[hook] + 4, sizeof(path));
|
|
||||||
|
|
||||||
run_parts(path, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hscript_banner(void *arg)
|
static void hscript_banner(void *arg)
|
||||||
@@ -96,6 +89,14 @@ static plugin_t plugin = {
|
|||||||
.hook[HOOK_SVC_UP] = { .cb = hscript_svc_up },
|
.hook[HOOK_SVC_UP] = { .cb = hscript_svc_up },
|
||||||
.hook[HOOK_SYSTEM_UP] = { .cb = hscript_system_up },
|
.hook[HOOK_SYSTEM_UP] = { .cb = hscript_system_up },
|
||||||
.hook[HOOK_SHUTDOWN] = { .cb = hscript_shutdown },
|
.hook[HOOK_SHUTDOWN] = { .cb = hscript_shutdown },
|
||||||
|
/*
|
||||||
|
* We have exited here, so these are handled a bit differently by Finit,
|
||||||
|
* when hook scripts are enabled, just to provide the user with the same
|
||||||
|
* interface:
|
||||||
|
*
|
||||||
|
* .hook[HOOK_SVC_DN] = { .cb = hscript_svc_down },
|
||||||
|
* .hook[HOOK_SYS_DN] = { .cb = hscript_system_down },
|
||||||
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
|
|||||||
@@ -1,116 +0,0 @@
|
|||||||
/* Heuristically find and initialize a suitable hotplug daemon
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "conf.h"
|
|
||||||
#include "finit.h"
|
|
||||||
#include "helpers.h"
|
|
||||||
#include "plugin.h"
|
|
||||||
#include "service.h"
|
|
||||||
|
|
||||||
static void setup(void *arg)
|
|
||||||
{
|
|
||||||
char cmd[256];
|
|
||||||
char *path;
|
|
||||||
|
|
||||||
if (rescue) {
|
|
||||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Populate /dev and prepare for runtime events from kernel.
|
|
||||||
* Prefer udev if mdev is also available on the system.
|
|
||||||
*/
|
|
||||||
path = which("udevd");
|
|
||||||
if (!path)
|
|
||||||
path = which("/lib/systemd/systemd-udevd");
|
|
||||||
if (path) {
|
|
||||||
/* Register udevd as a monitored service */
|
|
||||||
snprintf(cmd, sizeof(cmd), "[S12345789] cgroup.system pid:udevd name:udevd log %s "
|
|
||||||
"-- Device event managing daemon", path);
|
|
||||||
if (service_register(SVC_TYPE_SERVICE, cmd, global_rlimit, NULL)) {
|
|
||||||
_pe("Failed registering %s", path);
|
|
||||||
} else {
|
|
||||||
snprintf(cmd, sizeof(cmd), "cgroup.init :1 [S] <pid/udevd> log "
|
|
||||||
"udevadm trigger -c add -t devices "
|
|
||||||
"-- Requesting device events");
|
|
||||||
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
|
||||||
|
|
||||||
snprintf(cmd, sizeof(cmd), "cgroup.init :2 [S] <pid/udevd> log "
|
|
||||||
"udevadm trigger -c add -t subsystems "
|
|
||||||
"-- Requesting subsystem events");
|
|
||||||
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(path);
|
|
||||||
|
|
||||||
/* Debian has this little script to copy generated
|
|
||||||
* rules while the system was read-only. TODO: When
|
|
||||||
* this functionality was hardcoded in finit.c, this
|
|
||||||
* call was made in crank_worker(). Now that
|
|
||||||
* filesystems are mounted earlier we should be able
|
|
||||||
* to make this call directly after the triggers have
|
|
||||||
* run, but this has not been tested AT ALL. */
|
|
||||||
if (fexist("/lib/udev/udev-finish"))
|
|
||||||
run_interactive("/lib/udev/udev-finish", "Finalizing udev");
|
|
||||||
} else {
|
|
||||||
path = which("mdev");
|
|
||||||
if (path) {
|
|
||||||
/* Embedded Linux systems usually have BusyBox mdev */
|
|
||||||
if (debug)
|
|
||||||
touch("/dev/mdev.log");
|
|
||||||
|
|
||||||
snprintf(cmd, sizeof(cmd), "%s -s", path);
|
|
||||||
free(path);
|
|
||||||
|
|
||||||
run_interactive(cmd, "Populating device tree");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static plugin_t plugin = {
|
|
||||||
.name = __FILE__,
|
|
||||||
.hook[HOOK_BASEFS_UP] = {
|
|
||||||
.cb = setup
|
|
||||||
},
|
|
||||||
.depends = { "bootmisc" },
|
|
||||||
};
|
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
|
||||||
{
|
|
||||||
plugin_register(&plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
|
||||||
{
|
|
||||||
plugin_unregister(&plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Local Variables:
|
|
||||||
* indent-tabs-mode: t
|
|
||||||
* c-file-style: "linux"
|
|
||||||
* End:
|
|
||||||
*/
|
|
||||||
+73
-13
@@ -1,6 +1,6 @@
|
|||||||
/* Coldplug modules using modalias magic
|
/* Coldplug modules using modalias magic
|
||||||
*
|
*
|
||||||
* Copyright (c) 2021-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2021-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -71,14 +71,14 @@ static int modprobe(char *alias)
|
|||||||
pid = fork();
|
pid = fork();
|
||||||
switch (pid) {
|
switch (pid) {
|
||||||
case -1:
|
case -1:
|
||||||
_pe("Failed forking modprobe child");
|
err(1, "Failed forking modprobe child");
|
||||||
return 1;
|
return 1;
|
||||||
case 0:
|
case 0:
|
||||||
execvp(args[0], args);
|
execvp(args[0], args);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (!complete(args[0], pid))
|
if (!complete(args[0], pid))
|
||||||
_d("Successful modprobe of %s", alias);
|
dbg("Successful modprobe of %s", alias);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ static void alias_remove(struct module *m)
|
|||||||
TAILQ_REMOVE(&modules, m, link);
|
TAILQ_REMOVE(&modules, m, link);
|
||||||
free(m->alias);
|
free(m->alias);
|
||||||
free(m);
|
free(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int alias_exist(char *alias)
|
static int alias_exist(char *alias)
|
||||||
{
|
{
|
||||||
@@ -120,27 +120,87 @@ static int alias_exist(char *alias)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int scan_alias(const char *path, const struct stat *st, int flag, struct FTW *unused)
|
static void alias_add_uniq(char *alias)
|
||||||
|
{
|
||||||
|
if (alias_exist(alias))
|
||||||
|
return;
|
||||||
|
|
||||||
|
alias_add(alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
static FILE *maybe_fopen_alias(const char *file, const char *path)
|
||||||
|
{
|
||||||
|
const char *basename;
|
||||||
|
|
||||||
|
basename = rindex(path, '/');
|
||||||
|
if (!basename)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
basename++;
|
||||||
|
if (strcmp(file, basename))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return fopen(path, "r");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int scan_modalias(const char *path)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
|
||||||
char buf[256];
|
char buf[256];
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
if (fnmatch("*/modalias", path, 0))
|
fp = maybe_fopen_alias("modalias", path);
|
||||||
return 0;
|
|
||||||
|
|
||||||
fp = fopen(path, "r");
|
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return 0;
|
return 1;
|
||||||
|
|
||||||
if (fgets(buf, sizeof(buf), fp)) {
|
if (fgets(buf, sizeof(buf), fp)) {
|
||||||
chomp(buf);
|
chomp(buf);
|
||||||
if (!alias_exist(buf))
|
alias_add_uniq(buf);
|
||||||
alias_add(buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int scan_uevent(const char *path)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = maybe_fopen_alias("uevent", path);
|
||||||
|
if (!fp)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
if (strstr(buf, "MODALIAS=") != buf)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
chomp(buf);
|
||||||
|
|
||||||
|
alias_add_uniq(buf + strlen("MODALIAS="));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int scan_alias(const char *path, const struct stat *st,
|
||||||
|
int flag, struct FTW *unused)
|
||||||
|
{
|
||||||
|
/* Sanity check: is this a regular file we can read? */
|
||||||
|
if (!(S_ISREG(st->st_mode) && (st->st_mode & S_IRUSR)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!scan_uevent(path))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
scan_modalias(path);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void coldplug(void *arg)
|
static void coldplug(void *arg)
|
||||||
{
|
{
|
||||||
struct module *m, *tmp;
|
struct module *m, *tmp;
|
||||||
|
|||||||
+87
-31
@@ -62,62 +62,120 @@
|
|||||||
#ifndef MODULES_LOAD_PATH
|
#ifndef MODULES_LOAD_PATH
|
||||||
#define MODULES_LOAD_PATH "/etc/modules-load.d"
|
#define MODULES_LOAD_PATH "/etc/modules-load.d"
|
||||||
#endif
|
#endif
|
||||||
|
#define MODPROBE_PATH "/sbin/modprobe"
|
||||||
#define SERVICE_LINE \
|
#define SERVICE_LINE \
|
||||||
"cgroup.init name:modprobe.%s :%d [2345] /sbin/modprobe %s %s -- Kernel module: %s"
|
"cgroup.init name:modprobe.%s :%d [%s] %s %s %s --"
|
||||||
#define SERVICE_LINE_NOINDEX \
|
#define SERVICE_LINE_NOINDEX \
|
||||||
"cgroup.init name:modprobe.%s [2345] /sbin/modprobe %s %s -- Kernel module: %s"
|
"cgroup.init name:modprobe.%s [%s] %s %s %s --"
|
||||||
|
|
||||||
static int load_file(const char *file, int index)
|
static int modules_load(const char *file, int index)
|
||||||
{
|
{
|
||||||
char module_path[PATH_MAX];
|
char module_path[PATH_MAX];
|
||||||
char line[256];
|
char *modprobe_path;
|
||||||
int num = 0;
|
int num = 0;
|
||||||
|
char *line;
|
||||||
|
char *lvl;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
strlcpy(module_path, MODULES_LOAD_PATH "/", sizeof(module_path));
|
strlcpy(module_path, MODULES_LOAD_PATH "/", sizeof(module_path));
|
||||||
strlcat(module_path, file, sizeof(module_path));
|
strlcat(module_path, file, sizeof(module_path));
|
||||||
|
|
||||||
fp = fopen(module_path, "r");
|
fp = fopen(module_path, "r");
|
||||||
if (!fp)
|
if (!fp) {
|
||||||
|
warnx("failed opening %s for reading, skipping ...", module_path);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
while (fgets(line, sizeof(line), fp)) {
|
modprobe_path = strdup(MODPROBE_PATH);
|
||||||
char cmd[CMD_SIZE], *mod, *args;
|
if (!modprobe_path) {
|
||||||
|
fail:
|
||||||
|
warnx("failed allocating memory in modules-load plugin.");
|
||||||
|
fclose(fp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
chomp(line);
|
lvl = strdup("S");
|
||||||
|
if (!lvl) {
|
||||||
|
free(modprobe_path);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((line = fparseln(fp, NULL, NULL, NULL, 0))) {
|
||||||
|
char cmd[CMD_SIZE * 2], *mod, *args, *set;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* fparseln() skips regular UNIX comments only.
|
||||||
|
* This is for modules-load.d(5) compat.
|
||||||
|
*/
|
||||||
|
if (line[0] == ';')
|
||||||
|
goto next;
|
||||||
|
|
||||||
|
/* trim whitespace */
|
||||||
mod = strip_line(line);
|
mod = strip_line(line);
|
||||||
if (!mod[0])
|
if (!mod[0])
|
||||||
continue;
|
goto next;
|
||||||
|
|
||||||
if (mod[0] == '#' || mod[0] == ';')
|
/* Finit extension 'set foo bar' */
|
||||||
continue;
|
if ((set = fgetval(mod, "set", "= \t"))) {
|
||||||
|
char *val = mod;
|
||||||
|
|
||||||
if (!strcmp(mod, "set noindex")) {
|
if (!strcmp(set, "noindex")) {
|
||||||
index = 0;
|
index = 0;
|
||||||
continue;
|
free(set);
|
||||||
}
|
goto next;
|
||||||
if (!strncmp(mod, "set index", 9)) {
|
}
|
||||||
mod += 9;
|
|
||||||
args = strchr(mod, '=');
|
if ((val = fgetval(set, "index", "= \t"))) {
|
||||||
if (args) /* optional */
|
index = atoi(val);
|
||||||
mod = args + 1;
|
free(set);
|
||||||
index = atoi(mod);
|
free(val);
|
||||||
continue;
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((val = fgetval(set, "runlevel", "= \t"))) {
|
||||||
|
free(lvl);
|
||||||
|
lvl = val;
|
||||||
|
free(set);
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((val = fgetval(set, "modprobe", "= \t"))) {
|
||||||
|
if (access(val, X_OK)) {
|
||||||
|
warn("%s: cannot use %s", module_path, val);
|
||||||
|
free(set);
|
||||||
|
free(val);
|
||||||
|
free(line);
|
||||||
|
goto skip;
|
||||||
|
} else {
|
||||||
|
free(modprobe_path);
|
||||||
|
modprobe_path = val;
|
||||||
|
}
|
||||||
|
free(set);
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* unknown 'set' command, ignore. */
|
||||||
|
goto next;
|
||||||
}
|
}
|
||||||
|
|
||||||
mod = strtok_r(mod, " ", &args);
|
mod = strtok_r(mod, " ", &args);
|
||||||
if (!mod)
|
if (!mod)
|
||||||
continue;
|
goto next;
|
||||||
|
|
||||||
if (!index)
|
if (!index)
|
||||||
snprintf(cmd, sizeof(cmd), SERVICE_LINE_NOINDEX, mod, mod, args, mod);
|
snprintf(cmd, sizeof(cmd), SERVICE_LINE_NOINDEX, mod, lvl, modprobe_path, mod, args);
|
||||||
else
|
else
|
||||||
snprintf(cmd, sizeof(cmd), SERVICE_LINE, mod, index++, mod, args, mod);
|
snprintf(cmd, sizeof(cmd), SERVICE_LINE, mod, index++, lvl, modprobe_path, mod, args);
|
||||||
|
|
||||||
|
dbg("task %s", cmd);
|
||||||
service_register(SVC_TYPE_TASK, cmd, global_rlimit, NULL);
|
service_register(SVC_TYPE_TASK, cmd, global_rlimit, NULL);
|
||||||
num++;
|
num++;
|
||||||
|
next:
|
||||||
|
free(line);
|
||||||
}
|
}
|
||||||
|
skip:
|
||||||
|
free(modprobe_path);
|
||||||
|
free(lvl);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
return num;
|
return num;
|
||||||
@@ -142,11 +200,11 @@ static void load(void *arg)
|
|||||||
int index = 1;
|
int index = 1;
|
||||||
int i, num;
|
int i, num;
|
||||||
|
|
||||||
_d("Scanning " MODULES_LOAD_PATH " for config files ...");
|
dbg("Scanning " MODULES_LOAD_PATH " for config files ...");
|
||||||
num = scandir(MODULES_LOAD_PATH, &dentry, module_filter, alphasort);
|
num = scandir(MODULES_LOAD_PATH, &dentry, module_filter, alphasort);
|
||||||
if (num > 0) {
|
if (num > 0) {
|
||||||
for (i = 0; i < num; i++) {
|
for (i = 0; i < num; i++) {
|
||||||
index += load_file(dentry[i]->d_name, index);
|
index += modules_load(dentry[i]->d_name, index);
|
||||||
free(dentry[i]);
|
free(dentry[i]);
|
||||||
}
|
}
|
||||||
free(dentry);
|
free(dentry);
|
||||||
@@ -154,10 +212,8 @@ static void load(void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
.name = __FILE__,
|
.name = __FILE__,
|
||||||
.hook[HOOK_BASEFS_UP] = {
|
.hook[HOOK_SVC_PLUGIN] = { .cb = load },
|
||||||
.cb = load
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
|
|||||||
+36
-36
@@ -2,7 +2,7 @@
|
|||||||
/* Netlink plugin for IFUP/IFDN and GW events
|
/* Netlink plugin for IFUP/IFDN and GW events
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009-2011 Mårten Wikström <marten.wikstrom@keystream.se>
|
* Copyright (C) 2009-2011 Mårten Wikström <marten.wikstrom@keystream.se>
|
||||||
* Copyright (C) 2009-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (C) 2009-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
@@ -62,7 +62,7 @@ static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
int la;
|
int la;
|
||||||
|
|
||||||
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg))) {
|
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg))) {
|
||||||
_e("Packet too small or truncated!");
|
errx(1, "Packet too small or truncated!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
a = RTM_RTA(r);
|
a = RTM_RTA(r);
|
||||||
la = RTM_PAYLOAD(nlmsg);
|
la = RTM_PAYLOAD(nlmsg);
|
||||||
if (la >= len) {
|
if (la >= len) {
|
||||||
_e("Packet too large!");
|
errx(1, "Packet too large!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,18 +80,18 @@ static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
switch (a->rta_type) {
|
switch (a->rta_type) {
|
||||||
case RTA_GATEWAY:
|
case RTA_GATEWAY:
|
||||||
gw = *((int *)data);
|
gw = *((int *)data);
|
||||||
//_d("GW: 0x%04x", gw);
|
//dbg("GW: 0x%04x", gw);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTA_DST:
|
case RTA_DST:
|
||||||
dst = *((int *)data);
|
dst = *((int *)data);
|
||||||
plen = r->rtm_dst_len;
|
plen = r->rtm_dst_len;
|
||||||
//_d("Prefix LEN: 0x%04x", plen);
|
//dbg("Prefix LEN: 0x%04x", plen);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTA_OIF:
|
case RTA_OIF:
|
||||||
idx = *((int *)data);
|
idx = *((int *)data);
|
||||||
//_d("IDX: 0x%04x", idx);
|
//dbg("IDX: 0x%04x", idx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
ing.s_addr = gw;
|
ing.s_addr = gw;
|
||||||
inet_ntop(AF_INET, &ind, daddr, sizeof(daddr));
|
inet_ntop(AF_INET, &ind, daddr, sizeof(daddr));
|
||||||
inet_ntop(AF_INET, &ing, gaddr, sizeof(gaddr));
|
inet_ntop(AF_INET, &ing, gaddr, sizeof(gaddr));
|
||||||
_d("Got gw %s dst/len %s/%d ifindex %d", gaddr, daddr, plen, idx);
|
dbg("Got gw %s dst/len %s/%d ifindex %d", gaddr, daddr, plen, idx);
|
||||||
|
|
||||||
if ((!dst && !plen) && (gw || idx)) {
|
if ((!dst && !plen) && (gw || idx)) {
|
||||||
if (nlmsg->nlmsg_type == RTM_DELROUTE) {
|
if (nlmsg->nlmsg_type == RTM_DELROUTE) {
|
||||||
@@ -167,7 +167,7 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
int la;
|
int la;
|
||||||
|
|
||||||
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) {
|
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) {
|
||||||
_e("Packet too small or truncated!");
|
errx(1, "Packet too small or truncated!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +175,7 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
a = (struct rtattr *)((char *)i + NLMSG_ALIGN(sizeof(struct ifinfomsg)));
|
a = (struct rtattr *)((char *)i + NLMSG_ALIGN(sizeof(struct ifinfomsg)));
|
||||||
la = NLMSG_PAYLOAD(nlmsg, sizeof(struct ifinfomsg));
|
la = NLMSG_PAYLOAD(nlmsg, sizeof(struct ifinfomsg));
|
||||||
if (la >= len) {
|
if (la >= len) {
|
||||||
_e("Packet too large!");
|
errx(1, "Packet too large!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,7 +185,7 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
|
|
||||||
strlcpy(ifname, RTA_DATA(a), sizeof(ifname));
|
strlcpy(ifname, RTA_DATA(a), sizeof(ifname));
|
||||||
if (validate_ifname(ifname)) {
|
if (validate_ifname(ifname)) {
|
||||||
_d("Invalid interface name '%s', skipping ...", ifname);
|
dbg("Invalid interface name '%s', skipping ...", ifname);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +195,7 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
* New interface has appeared, or interface flags has changed.
|
* New interface has appeared, or interface flags has changed.
|
||||||
* Check ifi_flags here to see if the interface is UP/DOWN
|
* Check ifi_flags here to see if the interface is UP/DOWN
|
||||||
*/
|
*/
|
||||||
_d("%s: New link, flags 0x%x, change 0x%x", ifname, i->ifi_flags, i->ifi_change);
|
dbg("%s: New link, flags 0x%x, change 0x%x", ifname, i->ifi_flags, i->ifi_change);
|
||||||
net_cond_set(ifname, "exist", 1);
|
net_cond_set(ifname, "exist", 1);
|
||||||
net_cond_set(ifname, "up", i->ifi_flags & IFF_UP);
|
net_cond_set(ifname, "up", i->ifi_flags & IFF_UP);
|
||||||
net_cond_set(ifname, "running", i->ifi_flags & IFF_RUNNING);
|
net_cond_set(ifname, "running", i->ifi_flags & IFF_RUNNING);
|
||||||
@@ -205,7 +205,7 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
|
|
||||||
case RTM_DELLINK:
|
case RTM_DELLINK:
|
||||||
/* NOTE: Interface has disappeared, not link down ... */
|
/* NOTE: Interface has disappeared, not link down ... */
|
||||||
_d("%s: Delete link", ifname);
|
dbg("%s: Delete link", ifname);
|
||||||
net_cond_set(ifname, "exist", 0);
|
net_cond_set(ifname, "exist", 0);
|
||||||
net_cond_set(ifname, "up", 0);
|
net_cond_set(ifname, "up", 0);
|
||||||
net_cond_set(ifname, "running", 0);
|
net_cond_set(ifname, "running", 0);
|
||||||
@@ -213,15 +213,15 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case RTM_NEWADDR:
|
case RTM_NEWADDR:
|
||||||
_d("%s: New Address", ifname);
|
dbg("%s: New Address", ifname);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTM_DELADDR:
|
case RTM_DELADDR:
|
||||||
_d("%s: Deconfig Address", ifname);
|
dbg("%s: Deconfig Address", ifname);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_d("%s: Msg 0x%x", ifname, nlmsg->nlmsg_type);
|
dbg("%s: Msg 0x%x", ifname, nlmsg->nlmsg_type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -246,46 +246,46 @@ static int nl_parse(int sd)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_pe("recv()");
|
err(1, "recv()");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// _d("recv %zd bytes", len);
|
// dbg("recv %zd bytes", len);
|
||||||
l = (size_t)len;
|
l = (size_t)len;
|
||||||
for (nh = (struct nlmsghdr *)nl_buf; NLMSG_OK(nh, l); nh = NLMSG_NEXT(nh, l)) {
|
for (nh = (struct nlmsghdr *)nl_buf; NLMSG_OK(nh, l); nh = NLMSG_NEXT(nh, l)) {
|
||||||
struct nlmsgerr *nle;
|
struct nlmsgerr *nle;
|
||||||
|
|
||||||
switch (nh->nlmsg_type) {
|
switch (nh->nlmsg_type) {
|
||||||
case NLMSG_DONE:
|
case NLMSG_DONE:
|
||||||
// _d("Done with netlink messages.");
|
// dbg("Done with netlink messages.");
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case NLMSG_ERROR:
|
case NLMSG_ERROR:
|
||||||
// _d("Kernel netlink comm. error.");
|
// dbg("Kernel netlink comm. error.");
|
||||||
nle = NLMSG_DATA(nh);
|
nle = NLMSG_DATA(nh);
|
||||||
if (nle) {
|
if (nle) {
|
||||||
errno = -nle->error;
|
errno = -nle->error;
|
||||||
_pe("Kernel netlink error %d", errno);
|
err(1, "Kernel netlink error %d", errno);
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
case RTM_NEWROUTE:
|
case RTM_NEWROUTE:
|
||||||
case RTM_DELROUTE:
|
case RTM_DELROUTE:
|
||||||
// _d("Netlink route ...");
|
// dbg("Netlink route ...");
|
||||||
nl_route(nh, len);
|
nl_route(nh, len);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTM_NEWLINK:
|
case RTM_NEWLINK:
|
||||||
case RTM_DELLINK:
|
case RTM_DELLINK:
|
||||||
// _d("Netlink link ...");
|
// dbg("Netlink link ...");
|
||||||
nl_link(nh, len);
|
nl_link(nh, len);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_w("unhandled netlink message, type %d", nh->nlmsg_type);
|
warnx("unhandled netlink message, type %d", nh->nlmsg_type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -304,21 +304,21 @@ static int nl_request(int sd, unsigned int seq, int type)
|
|||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case RTM_GETROUTE:
|
case RTM_GETROUTE:
|
||||||
// _d("RTM_GETROUTE");
|
// dbg("RTM_GETROUTE");
|
||||||
nlr->rtm.rtm_family = AF_INET;
|
nlr->rtm.rtm_family = AF_INET;
|
||||||
nlr->rtm.rtm_table = RT_TABLE_MAIN;
|
nlr->rtm.rtm_table = RT_TABLE_MAIN;
|
||||||
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTM_GETLINK:
|
case RTM_GETLINK:
|
||||||
// _d("RTM_GETLINK");
|
// dbg("RTM_GETLINK");
|
||||||
nlr->ifi.ifi_family = AF_UNSPEC;
|
nlr->ifi.ifi_family = AF_UNSPEC;
|
||||||
nlr->ifi.ifi_change = 0xFFFFFFFF;
|
nlr->ifi.ifi_change = 0xFFFFFFFF;
|
||||||
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_w("Cannot resync, unhandled message type %d", type);
|
warnx("Cannot resync, unhandled message type %d", type);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,13 +331,13 @@ static int nl_request(int sd, unsigned int seq, int type)
|
|||||||
static void nl_resync_routes(int sd, unsigned int seq)
|
static void nl_resync_routes(int sd, unsigned int seq)
|
||||||
{
|
{
|
||||||
if (nl_request(sd, seq, RTM_GETROUTE))
|
if (nl_request(sd, seq, RTM_GETROUTE))
|
||||||
_pe("Failed netlink route request");
|
err(1, "Failed netlink route request");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nl_resync_ifaces(int sd, unsigned int seq)
|
static void nl_resync_ifaces(int sd, unsigned int seq)
|
||||||
{
|
{
|
||||||
if (nl_request(sd, seq, RTM_GETLINK))
|
if (nl_request(sd, seq, RTM_GETLINK))
|
||||||
_pe("Failed netlink link request");
|
err(1, "Failed netlink link request");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -350,12 +350,12 @@ static void nl_resync(int all)
|
|||||||
|
|
||||||
sd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
|
sd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
|
||||||
if (sd < 0) {
|
if (sd < 0) {
|
||||||
_pe("netlink socket");
|
err(1, "netlink socket");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (all) {
|
if (all) {
|
||||||
_d("============================ RESYNC =================================");
|
dbg("============================ RESYNC =================================");
|
||||||
/* this doesn't update conditions, and thus does not stop services */
|
/* this doesn't update conditions, and thus does not stop services */
|
||||||
cond_deassert("net/");
|
cond_deassert("net/");
|
||||||
|
|
||||||
@@ -364,7 +364,7 @@ static void nl_resync(int all)
|
|||||||
|
|
||||||
/* delayed update after we've corrected things */
|
/* delayed update after we've corrected things */
|
||||||
service_step_all(SVC_TYPE_ANY);
|
service_step_all(SVC_TYPE_ANY);
|
||||||
_d("=========================== RESYNCED ================================");
|
dbg("=========================== RESYNCED ================================");
|
||||||
} else
|
} else
|
||||||
nl_resync_routes(sd, seq++);
|
nl_resync_routes(sd, seq++);
|
||||||
|
|
||||||
@@ -375,7 +375,7 @@ static void nl_callback(void *arg, int sd, int events)
|
|||||||
{
|
{
|
||||||
if (nl_parse(sd) < 0) {
|
if (nl_parse(sd) < 0) {
|
||||||
if (errno == ENOBUFS) { /* netlink(7) */
|
if (errno == ENOBUFS) { /* netlink(7) */
|
||||||
_w("busy system, resynchronizing with kernel.");
|
warnx("busy system, resynchronizing with kernel.");
|
||||||
nl_resync(1);
|
nl_resync(1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -386,7 +386,7 @@ static void nl_callback(void *arg, int sd, int events)
|
|||||||
* we need to check ourselves, e.g. for loss of default route.
|
* we need to check ourselves, e.g. for loss of default route.
|
||||||
*/
|
*/
|
||||||
if (nl_ifdown) {
|
if (nl_ifdown) {
|
||||||
_d("interface down, checking default route.");
|
dbg("interface down, checking default route.");
|
||||||
if (nl_defidx > 0) {
|
if (nl_defidx > 0) {
|
||||||
nl_defidx = 0;
|
nl_defidx = 0;
|
||||||
nl_resync(0);
|
nl_resync(0);
|
||||||
@@ -421,7 +421,7 @@ PLUGIN_INIT(plugin_init)
|
|||||||
|
|
||||||
sd = socket(AF_NETLINK, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, NETLINK_ROUTE);
|
sd = socket(AF_NETLINK, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, NETLINK_ROUTE);
|
||||||
if (sd < 0) {
|
if (sd < 0) {
|
||||||
_pe("socket()");
|
err(1, "socket()");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,14 +431,14 @@ PLUGIN_INIT(plugin_init)
|
|||||||
sa.nl_pid = getpid();
|
sa.nl_pid = getpid();
|
||||||
|
|
||||||
if (bind(sd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
if (bind(sd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
||||||
_pe("bind()");
|
err(1, "bind()");
|
||||||
close(sd);
|
close(sd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nl_buf = malloc(NL_BUFSZ);
|
nl_buf = malloc(NL_BUFSZ);
|
||||||
if (!nl_buf) {
|
if (!nl_buf) {
|
||||||
_pe("malloc()");
|
err(1, "malloc()");
|
||||||
close(sd);
|
close(sd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
+42
-25
@@ -1,7 +1,7 @@
|
|||||||
/* Simple pidfile event monitor for the Finit condition engine
|
/* Simple pidfile event monitor for the Finit condition engine
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
|
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
|
||||||
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -52,7 +52,7 @@ static int pidfile_add_path(struct iwatch *iw, char *path)
|
|||||||
ptr = slash++;
|
ptr = slash++;
|
||||||
slash = strchr(ptr, '/');
|
slash = strchr(ptr, '/');
|
||||||
if (slash) {
|
if (slash) {
|
||||||
_d("Path too deep, skipping.");
|
dbg("Path too deep, skipping.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,30 +71,39 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
|
|||||||
if (fnmatch("*\\.pid", fn, 0) && fnmatch("*/pid", fn, 0))
|
if (fnmatch("*\\.pid", fn, 0) && fnmatch("*/pid", fn, 0))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_d("path: %s, mask: %08x", fn, mask);
|
dbg("path: %s, mask: %08x", fn, mask);
|
||||||
|
|
||||||
svc = svc_find_by_pidfile(fn);
|
svc = svc_find_by_pidfile(fn);
|
||||||
if (!svc) {
|
if (!svc) {
|
||||||
_d("No matching svc for %s", fn);
|
dbg("No matching svc for %s", fn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("Found svc %s for %s with pid %d", svc->name, fn, svc->pid);
|
dbg("Found svc %s for %s with pid %d", svc->name, fn, svc->pid);
|
||||||
|
|
||||||
mkcond(svc, cond, sizeof(cond));
|
mkcond(svc, cond, sizeof(cond));
|
||||||
|
|
||||||
if (mask & (IN_CLOSE_WRITE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) {
|
if (mask & (IN_CLOSE_WRITE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) {
|
||||||
svc_started(svc);
|
/*
|
||||||
|
* only mark native services as started, the s6 and
|
||||||
|
* systemd style services rely on their respective
|
||||||
|
* readiness notification. Issue #343
|
||||||
|
*/
|
||||||
|
if (!svc->notify)
|
||||||
|
svc_started(svc);
|
||||||
|
|
||||||
if (!svc_has_pidfile(svc)) {
|
if (!svc_has_pidfile(svc)) {
|
||||||
_d("Setting %s PID file to %s", svc->name, fn);
|
dbg("Setting %s PID file to %s", svc->name, fn);
|
||||||
pid_file_set(svc, fn, 1);
|
pid_file_set(svc, fn, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (svc_is_forking(svc)) {
|
if (svc_is_forking(svc)) {
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
pid = pid_file_read(pid_file(svc));
|
pid = pid_file_read(fn);
|
||||||
if (pid == -1) {
|
if (pid == -1) {
|
||||||
cond_clear(cond);
|
/* handle case when service dies immediately */
|
||||||
|
if (!fexist(fn))
|
||||||
|
cond_clear(cond);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +111,7 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
|
|||||||
service_forked(svc);
|
service_forked(svc);
|
||||||
|
|
||||||
if (pid != svc->pid) {
|
if (pid != svc->pid) {
|
||||||
_d("Forking service %s (cmd %s) changed PID from %d to %d",
|
dbg("Forking service %s (cmd %s) changed PID from %d to %d",
|
||||||
svc_ident(svc, NULL, 0), svc->cmd, svc->pid, pid);
|
svc_ident(svc, NULL, 0), svc->cmd, svc->pid, pid);
|
||||||
svc->pid = pid;
|
svc->pid = pid;
|
||||||
|
|
||||||
@@ -112,8 +121,13 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cond_set(cond);
|
cond_set(cond);
|
||||||
} else if (mask & IN_DELETE)
|
if (!svc->notify)
|
||||||
|
service_ready(svc);
|
||||||
|
} else if (mask & IN_DELETE) {
|
||||||
cond_clear(cond);
|
cond_clear(cond);
|
||||||
|
if (!svc->notify)
|
||||||
|
service_ready(svc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* synthesize events in case of new run dirs */
|
/* synthesize events in case of new run dirs */
|
||||||
@@ -135,7 +149,7 @@ static void pidfile_scandir(struct iwatch *iw, char *dir, int len)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
for (i = 0; i < gl.gl_pathc; i++) {
|
for (i = 0; i < gl.gl_pathc; i++) {
|
||||||
_d("scan found %s", gl.gl_pathv[i]);
|
dbg("scan found %s", gl.gl_pathv[i]);
|
||||||
pidfile_update_conds(dir, gl.gl_pathv[i], IN_CREATE);
|
pidfile_update_conds(dir, gl.gl_pathv[i], IN_CREATE);
|
||||||
}
|
}
|
||||||
globfree(&gl);
|
globfree(&gl);
|
||||||
@@ -150,7 +164,7 @@ static void pidfile_handle_dir(struct iwatch *iw, char *dir, char *name, int mas
|
|||||||
struct iwatch_path *iwp;
|
struct iwatch_path *iwp;
|
||||||
|
|
||||||
paste(path, sizeof(path), dir, name);
|
paste(path, sizeof(path), dir, name);
|
||||||
_d("path: %s", path);
|
dbg("path: %s", path);
|
||||||
|
|
||||||
iwp = iwatch_find_by_path(iw, path);
|
iwp = iwatch_find_by_path(iw, path);
|
||||||
|
|
||||||
@@ -174,7 +188,7 @@ static void pidfile_callback(void *arg, int fd, int events)
|
|||||||
|
|
||||||
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
||||||
if (sz <= 0) {
|
if (sz <= 0) {
|
||||||
_pe("invalid inotify event");
|
err(1, "invalid inotify event");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ev_buf[sz] = 0;
|
ev_buf[sz] = 0;
|
||||||
@@ -226,6 +240,9 @@ static void pidfile_reconf(void *arg)
|
|||||||
if (svc_is_changed(svc) || svc_is_starting(svc))
|
if (svc_is_changed(svc) || svc_is_starting(svc))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (!svc->notify)
|
||||||
|
service_ready(svc);
|
||||||
|
|
||||||
mkcond(svc, cond, sizeof(cond));
|
mkcond(svc, cond, sizeof(cond));
|
||||||
if (cond_get(cond) == COND_ON)
|
if (cond_get(cond) == COND_ON)
|
||||||
continue;
|
continue;
|
||||||
@@ -234,9 +251,9 @@ static void pidfile_reconf(void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This will call service_step(), which in turn will schedule itself
|
* This calls service_step(), which in turn schedules itself as
|
||||||
* as long as stepped services change state. Services going from
|
* long as stepped services change state. Services going from
|
||||||
* WAITING to RUNNING will reassert their conditions in that loop,
|
* PAUSED to RUNNING reassert their conditions in that loop,
|
||||||
* which in turn may unlock other services, and so on.
|
* which in turn may unlock other services, and so on.
|
||||||
*/
|
*/
|
||||||
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_RUNTASK);
|
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_RUNTASK);
|
||||||
@@ -248,7 +265,7 @@ static void pidfile_init(void *arg)
|
|||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
if (mkpath(pid_runpath(_PATH_CONDPID, piddir, sizeof(piddir)), 0755) && errno != EEXIST) {
|
if (mkpath(pid_runpath(_PATH_CONDPID, piddir, sizeof(piddir)), 0755) && errno != EEXIST) {
|
||||||
_pe("Failed creating %s condition directory, %s", COND_PID, _PATH_CONDPID);
|
err(1, "Failed creating %s condition directory, %s", COND_PID, _PATH_CONDPID);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,10 +276,10 @@ static void pidfile_init(void *arg)
|
|||||||
*/
|
*/
|
||||||
path = realpath(_PATH_VARRUN, NULL);
|
path = realpath(_PATH_VARRUN, NULL);
|
||||||
if (!path) {
|
if (!path) {
|
||||||
_d("Failed querying realpath(%s): %s", _PATH_VARRUN, strerror(errno));
|
dbg("Failed querying realpath(%s): %s", _PATH_VARRUN, strerror(errno));
|
||||||
path = realpath("/run", NULL);
|
path = realpath("/run", NULL);
|
||||||
if (!path) {
|
if (!path) {
|
||||||
_e("System does not have %s or /run, aborting.", _PATH_VARRUN);
|
errx(1, "System does not have %s or /run, aborting.", _PATH_VARRUN);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -283,15 +300,15 @@ static void pidfile_init(void *arg)
|
|||||||
*
|
*
|
||||||
* service <net/iface/lo> /sbin/dropbear ...
|
* service <net/iface/lo> /sbin/dropbear ...
|
||||||
*
|
*
|
||||||
* Which provides the <pid/dropbear> condition, will not be set by
|
* This service provides the <pid/dropbear> condition, which will not be
|
||||||
* pidfile.so during `initctl reload` because dropbear is still
|
* set by pidfile.so during `initctl reload` because dropbear is still
|
||||||
* SIGSTP:ed waiting for <net/iface/lo>.
|
* SIGSTP:ed (in state PAUSED) waiting for <net/iface/lo>.
|
||||||
*/
|
*/
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
.name = __FILE__,
|
.name = __FILE__,
|
||||||
.hook[HOOK_BASEFS_UP] = { .cb = pidfile_init },
|
.hook[HOOK_BASEFS_UP] = { .cb = pidfile_init },
|
||||||
.hook[HOOK_SVC_RECONF] = { .cb = pidfile_reconf },
|
.hook[HOOK_SVC_RECONF] = { .cb = pidfile_reconf },
|
||||||
.depends = { "netlink" },
|
.depends = { "netlink" }, /* bootmisc depends on us */
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
/* Set kernel variables from /etc/sysctl.conf et al
|
/* Set kernel variables from /etc/sysctl.conf et al
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -37,7 +37,7 @@ static void setup(void *arg)
|
|||||||
glob_t gl;
|
glob_t gl;
|
||||||
|
|
||||||
if (rescue) {
|
if (rescue) {
|
||||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* Setup necessary files for resolvconf
|
/* Setup necessary files for resolvconf
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
*/
|
*/
|
||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
{
|
{
|
||||||
_d("Setting up the resolver ...");
|
dbg("Setting up the resolver ...");
|
||||||
mkpath("/etc/resolvconf", 0755);
|
mkpath("/etc/resolvconf", 0755);
|
||||||
mkpath("/etc/resolvconf/run", 0755);
|
mkpath("/etc/resolvconf/run", 0755);
|
||||||
mkpath("/var/run/resolvconf", 0755);
|
mkpath("/var/run/resolvconf", 0755);
|
||||||
@@ -45,7 +45,7 @@ static void setup(void *arg)
|
|||||||
|
|
||||||
touch("/etc/resolvconf/run/enable-updates");
|
touch("/etc/resolvconf/run/enable-updates");
|
||||||
chdir("/etc/resolvconf/run/interface");
|
chdir("/etc/resolvconf/run/interface");
|
||||||
run_parts("/etc/resolvconf/update.d", "-i");
|
run_parts("/etc/resolvconf/update.d", "-i", NULL, 0);
|
||||||
chdir("/");
|
chdir("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+28
-11
@@ -1,6 +1,6 @@
|
|||||||
/* Save and restore RTC using hwclock
|
/* Save and restore RTC using hwclock
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -21,6 +21,8 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <linux/rtc.h>
|
#include <linux/rtc.h>
|
||||||
@@ -35,7 +37,13 @@
|
|||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
|
||||||
/* Kernel RTC driver validates against this date for sanity check */
|
/* Kernel RTC driver validates against this date for sanity check */
|
||||||
#define RTC_TIMESTAMP_BEGIN_2000 946684800LL /* 2000-01-01 00:00:00 */
|
#define RTC_TIMESTAMP_BEGIN_2000 "2000-01-01 00:00:00"
|
||||||
|
#ifdef RTC_TIMESTAMP_CUSTOM
|
||||||
|
static char *rtc_timestamp = RTC_TIMESTAMP_CUSTOM;
|
||||||
|
#else
|
||||||
|
static char *rtc_timestamp = RTC_TIMESTAMP_BEGIN_2000;
|
||||||
|
#endif
|
||||||
|
static time_t rtc_date_fallback = 946684800LL;
|
||||||
|
|
||||||
static void tz_set(char *tz, size_t len)
|
static void tz_set(char *tz, size_t len)
|
||||||
{
|
{
|
||||||
@@ -89,7 +97,7 @@ static void rtc_save(void *arg)
|
|||||||
char tz[128];
|
char tz[128];
|
||||||
|
|
||||||
if (rescue) {
|
if (rescue) {
|
||||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,10 +107,10 @@ static void rtc_save(void *arg)
|
|||||||
|
|
||||||
tz_set(tz, sizeof(tz));
|
tz_set(tz, sizeof(tz));
|
||||||
rc = gettimeofday(&tv, NULL);
|
rc = gettimeofday(&tv, NULL);
|
||||||
if (rc < 0 || tv.tv_sec < RTC_TIMESTAMP_BEGIN_2000) {
|
if (rc < 0 || tv.tv_sec < rtc_date_fallback) {
|
||||||
print_desc(NULL, "System clock invalid, not saving to RTC");
|
print_desc(NULL, "System clock invalid, not saving to RTC");
|
||||||
invalid:
|
invalid:
|
||||||
logit(LOG_ERR, "System clock invalid, before 2000-01-01 00:00, not saving to RTC");
|
logit(LOG_ERR, "System clock invalid, before %s, not saving to RTC", rtc_timestamp);
|
||||||
rc = 2;
|
rc = 2;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -131,13 +139,15 @@ static void rtc_restore(void *arg)
|
|||||||
char tz[128];
|
char tz[128];
|
||||||
|
|
||||||
if (rescue) {
|
if (rescue) {
|
||||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = rtc_open();
|
fd = rtc_open();
|
||||||
if (fd < 0)
|
if (fd < 0) {
|
||||||
|
logit(LOG_NOTICE, "System has no RTC (missing driver?), skipping restore.");
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
tz_set(tz, sizeof(tz));
|
tz_set(tz, sizeof(tz));
|
||||||
if (ioctl(fd, RTC_RD_TIME, &tm) < 0) {
|
if (ioctl(fd, RTC_RD_TIME, &tm) < 0) {
|
||||||
@@ -151,7 +161,7 @@ static void rtc_restore(void *arg)
|
|||||||
invalid:
|
invalid:
|
||||||
logit(LOG_ERR, "Failed restoring system clock from RTC.");
|
logit(LOG_ERR, "Failed restoring system clock from RTC.");
|
||||||
if (EINVAL == errno)
|
if (EINVAL == errno)
|
||||||
logit(LOG_ERR, "RTC time is too old (before 2000-01-01 00:00)");
|
logit(LOG_ERR, "RTC time is too old (before %s)", rtc_timestamp);
|
||||||
else if (ENOENT == errno)
|
else if (ENOENT == errno)
|
||||||
logit(LOG_ERR, "RTC has no previously saved (valid) time.");
|
logit(LOG_ERR, "RTC has no previously saved (valid) time.");
|
||||||
else
|
else
|
||||||
@@ -162,18 +172,18 @@ static void rtc_restore(void *arg)
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* Attempt to set RTC to a sane value ... */
|
/* Attempt to set RTC to a sane value ... */
|
||||||
tv.tv_sec = RTC_TIMESTAMP_BEGIN_2000;
|
tv.tv_sec = rtc_date_fallback;
|
||||||
if (!gmtime_r(&tv.tv_sec, &tm))
|
if (!gmtime_r(&tv.tv_sec, &tm))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
logit(LOG_NOTICE, "Resetting RTC to kernel default, 2000-01-01 00:00.");
|
logit(LOG_NOTICE, "Resetting RTC to kernel default, %s.", rtc_timestamp);
|
||||||
rc = 2;
|
rc = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
print_desc(NULL, "Restoring system clock (UTC) from RTC");
|
print_desc(NULL, "Restoring system clock (UTC) from RTC");
|
||||||
tm.tm_isdst = -1; /* Use tzdata to figure it out, please. */
|
tm.tm_isdst = -1; /* Use tzdata to figure it out, please. */
|
||||||
tv.tv_sec = mktime(&tm);
|
tv.tv_sec = mktime(&tm);
|
||||||
if (tv.tv_sec < RTC_TIMESTAMP_BEGIN_2000) {
|
if (tv.tv_sec == (time_t)-1 || tv.tv_sec < rtc_date_fallback) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
goto invalid;
|
goto invalid;
|
||||||
}
|
}
|
||||||
@@ -199,6 +209,13 @@ static plugin_t plugin = {
|
|||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
{
|
{
|
||||||
|
struct tm tm = { 0 };
|
||||||
|
|
||||||
|
if (!strptime(rtc_timestamp, "%Y-%m-%d %H:%M", &tm))
|
||||||
|
rtc_date_fallback = mktime(&tm);
|
||||||
|
else
|
||||||
|
rtc_timestamp = RTC_TIMESTAMP_BEGIN_2000;
|
||||||
|
|
||||||
plugin_register(&plugin);
|
plugin_register(&plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-8
@@ -1,6 +1,6 @@
|
|||||||
/* System condition event monitor for the Finit condition engine
|
/* System condition event monitor for the Finit condition engine
|
||||||
*
|
*
|
||||||
* Copyright (c) 2021-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2021-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -63,7 +63,7 @@ static void sys_update_conds(char *dir, char *name, uint32_t mask)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
cond += strlen(COND_BASE) + 1;
|
cond += strlen(COND_BASE) + 1;
|
||||||
_d("cond: %s set: %d", cond, mask & IN_CREATE ? 1 : 0);
|
dbg("cond: %s set: %d", cond, (mask & IN_CREATE) ? 1 : 0);
|
||||||
if (!cond_update(cond))
|
if (!cond_update(cond))
|
||||||
unlink(path);
|
unlink(path);
|
||||||
}
|
}
|
||||||
@@ -82,7 +82,7 @@ static void sys_scandir(struct iwatch *iw, char *dir, int len)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
for (i = 0; i < gl.gl_pathc; i++) {
|
for (i = 0; i < gl.gl_pathc; i++) {
|
||||||
_d("scan found %s", gl.gl_pathv[i]);
|
dbg("scan found %s", gl.gl_pathv[i]);
|
||||||
sys_update_conds(dir, gl.gl_pathv[i], IN_CREATE);
|
sys_update_conds(dir, gl.gl_pathv[i], IN_CREATE);
|
||||||
}
|
}
|
||||||
globfree(&gl);
|
globfree(&gl);
|
||||||
@@ -97,7 +97,7 @@ static void sys_handle_dir(struct iwatch *iw, char *dir, char *name, int mask)
|
|||||||
struct iwatch_path *iwp;
|
struct iwatch_path *iwp;
|
||||||
|
|
||||||
paste(path, sizeof(path), dir, name);
|
paste(path, sizeof(path), dir, name);
|
||||||
_d("path: %s", path);
|
dbg("path: %s", path);
|
||||||
|
|
||||||
iwp = iwatch_find_by_path(iw, path);
|
iwp = iwatch_find_by_path(iw, path);
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ static void sys_callback(void *arg, int fd, int events)
|
|||||||
|
|
||||||
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
||||||
if (sz <= 0) {
|
if (sz <= 0) {
|
||||||
_pe("invalid inotify event");
|
err(1, "invalid inotify event");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ev_buf[sz] = 0;
|
ev_buf[sz] = 0;
|
||||||
@@ -136,7 +136,7 @@ static void sys_callback(void *arg, int fd, int events)
|
|||||||
if (off + sizeof(*ev) + ev->len > (size_t)sz)
|
if (off + sizeof(*ev) + ev->len > (size_t)sz)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
_d("name %s, event: 0x%08x", ev->name, ev->mask);
|
dbg("name %s, event: 0x%08x", ev->name, ev->mask);
|
||||||
if (!ev->mask)
|
if (!ev->mask)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -160,24 +160,28 @@ static void sys_init(void *arg)
|
|||||||
char sysdir[MAX_ARG_LEN];
|
char sysdir[MAX_ARG_LEN];
|
||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
|
mkpath(_PATH_COND, 0755);
|
||||||
if (mkpath(pid_runpath(_PATH_CONDSYS, sysdir, sizeof(sysdir)), 0755) && errno != EEXIST) {
|
if (mkpath(pid_runpath(_PATH_CONDSYS, sysdir, sizeof(sysdir)), 0755) && errno != EEXIST) {
|
||||||
_pe("Failed creating %s condition directory, %s", COND_SYS, _PATH_CONDSYS);
|
err(1, "Failed creating %s condition directory, %s", COND_SYS, _PATH_CONDSYS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
path = realpath(_PATH_CONDSYS, NULL);
|
path = realpath(_PATH_CONDSYS, NULL);
|
||||||
if (!path) {
|
if (!path) {
|
||||||
_pe("Cannot figure out real path to %s, aborting", _PATH_CONDSYS);
|
err(1, "Cannot figure out real path to %s, aborting", _PATH_CONDSYS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iwatch_add(&iw_sys, path, IN_ONLYDIR))
|
if (iwatch_add(&iw_sys, path, IN_ONLYDIR))
|
||||||
iwatch_exit(&iw_sys);
|
iwatch_exit(&iw_sys);
|
||||||
|
|
||||||
|
free(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
.name = __FILE__,
|
.name = __FILE__,
|
||||||
.hook[HOOK_BASEFS_UP] = { .cb = sys_init },
|
.hook[HOOK_BASEFS_UP] = { .cb = sys_init },
|
||||||
|
.depends = { "bootmisc", },
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
|
|||||||
+6
-6
@@ -1,7 +1,7 @@
|
|||||||
/* Optional TTY Watcher, used to catch new TTYs that are discovered, e.g., USB
|
/* 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 Mattias Walström <lazzer@gmail.com>
|
||||||
* Copyright (c) 2013-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2013-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -55,7 +55,7 @@ static void setup(void)
|
|||||||
|
|
||||||
plugin.io.fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
plugin.io.fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
||||||
if (-1 == plugin.io.fd || inotify_add_watch(plugin.io.fd, "/dev", IN_CREATE | IN_DELETE) < 0)
|
if (-1 == plugin.io.fd || inotify_add_watch(plugin.io.fd, "/dev", IN_CREATE | IN_DELETE) < 0)
|
||||||
_pe("Failed starting TTY watcher");
|
err(1, "Failed starting TTY watcher");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_tty(char *tty, size_t len, int creat)
|
static void do_tty(char *tty, size_t len, int creat)
|
||||||
@@ -67,10 +67,10 @@ static void do_tty(char *tty, size_t len, int creat)
|
|||||||
svc = svc_find_by_tty(name);
|
svc = svc_find_by_tty(name);
|
||||||
if (svc) {
|
if (svc) {
|
||||||
if (svc_is_blocked(svc) && creat) {
|
if (svc_is_blocked(svc) && creat) {
|
||||||
_d("%s: blocked, re-enabling", svc_ident(svc, NULL, 0));
|
dbg("%s: blocked, re-enabling", svc_ident(svc, NULL, 0));
|
||||||
svc_start(svc);
|
svc_start(svc);
|
||||||
} else if (svc->pid) {
|
} else if (svc->pid) {
|
||||||
_d("%s: missing ...", svc_ident(svc, NULL, 0));
|
dbg("%s: missing ...", svc_ident(svc, NULL, 0));
|
||||||
svc_missing(svc);
|
svc_missing(svc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ static void tty_watcher(void *arg, int fd, int events)
|
|||||||
|
|
||||||
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
||||||
if (sz <= 0) {
|
if (sz <= 0) {
|
||||||
_pe("invalid inotify event");
|
err(1, "invalid inotify event");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ev_buf[sz] = 0;
|
ev_buf[sz] = 0;
|
||||||
@@ -103,7 +103,7 @@ static void tty_watcher(void *arg, int fd, int events)
|
|||||||
if (!ev->mask)
|
if (!ev->mask)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_d("tty %s, event: 0x%08x", ev->name, ev->mask);
|
dbg("tty %s, event: 0x%08x", ev->name, ev->mask);
|
||||||
do_tty(ev->name, ev->len, ev->mask & IN_CREATE);
|
do_tty(ev->name, ev->len, ev->mask & IN_CREATE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -1,6 +1,6 @@
|
|||||||
/* Setup and save random seed at boot/shutdown
|
/* Setup and save random seed at boot/shutdown
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -51,7 +51,7 @@ static void setup(void *arg)
|
|||||||
int fd, err;
|
int fd, err;
|
||||||
|
|
||||||
if (rescue) {
|
if (rescue) {
|
||||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ static void setup(void *arg)
|
|||||||
umask(prev);
|
umask(prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
print_desc("Initializing random number generator", NULL);
|
print_desc("Seeding random number generator", NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Simply copying our saved entropy to /dev/urandom doesn't
|
* Simply copying our saved entropy to /dev/urandom doesn't
|
||||||
@@ -144,7 +144,7 @@ static void save(void *arg)
|
|||||||
mode_t prev;
|
mode_t prev;
|
||||||
|
|
||||||
if (rescue) {
|
if (rescue) {
|
||||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-5
@@ -1,6 +1,6 @@
|
|||||||
/* User-defined condition event monitor for the Finit condition engine
|
/* User-defined condition event monitor for the Finit condition engine
|
||||||
*
|
*
|
||||||
* Copyright (c) 2021-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2021-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -52,7 +52,7 @@ static void usr_callback(void *arg, int fd, int events)
|
|||||||
|
|
||||||
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
||||||
if (sz <= 0) {
|
if (sz <= 0) {
|
||||||
_pe("invalid inotify event");
|
err(1, "invalid inotify event");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ev_buf[sz] = 0;
|
ev_buf[sz] = 0;
|
||||||
@@ -65,7 +65,7 @@ static void usr_callback(void *arg, int fd, int events)
|
|||||||
if (off + sizeof(*ev) + ev->len > (size_t)sz)
|
if (off + sizeof(*ev) + ev->len > (size_t)sz)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
_d("name %s, event: 0x%08x", ev->name, ev->mask);
|
dbg("name %s, event: 0x%08x", ev->name, ev->mask);
|
||||||
if (!ev->mask)
|
if (!ev->mask)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -84,14 +84,15 @@ static void usr_init(void *arg)
|
|||||||
char usrdir[MAX_ARG_LEN];
|
char usrdir[MAX_ARG_LEN];
|
||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
|
mkpath(_PATH_COND, 0755);
|
||||||
if (mkpath(pid_runpath(_PATH_CONDUSR, usrdir, sizeof(usrdir)), 0755) && errno != EEXIST) {
|
if (mkpath(pid_runpath(_PATH_CONDUSR, usrdir, sizeof(usrdir)), 0755) && errno != EEXIST) {
|
||||||
_pe("Failed creating %s condition directory, %s", COND_USR, _PATH_CONDUSR);
|
err(1, "Failed creating %s condition directory, %s", COND_USR, _PATH_CONDUSR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
path = realpath(_PATH_CONDUSR, NULL);
|
path = realpath(_PATH_CONDUSR, NULL);
|
||||||
if (!path) {
|
if (!path) {
|
||||||
_pe("Cannot figure out real path to %s, aborting", _PATH_CONDUSR);
|
err(1, "Cannot figure out real path to %s, aborting", _PATH_CONDUSR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,6 +105,7 @@ static void usr_init(void *arg)
|
|||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
.name = __FILE__,
|
.name = __FILE__,
|
||||||
.hook[HOOK_BASEFS_UP] = { .cb = usr_init },
|
.hook[HOOK_BASEFS_UP] = { .cb = usr_init },
|
||||||
|
.depends = { "bootmisc", },
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
|
|||||||
+4
-33
@@ -1,6 +1,6 @@
|
|||||||
/* Console setup (for X)
|
/* Console setup (for X)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -36,47 +36,18 @@
|
|||||||
|
|
||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
{
|
{
|
||||||
const char *username = "nobody";
|
|
||||||
char line[LINE_SIZE];
|
|
||||||
mode_t prev;
|
|
||||||
#ifdef PAM_CONSOLE
|
|
||||||
int fd;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (rescue) {
|
if (rescue) {
|
||||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
prev = umask(0);
|
if (fexist("/var/run/console/console.lock") && which("pam_console_apply"))
|
||||||
|
|
||||||
makedir("/var/run/console", 01777);
|
|
||||||
snprintf(line, sizeof(line), "/var/run/console/%s", username);
|
|
||||||
touch(line);
|
|
||||||
|
|
||||||
#ifdef PAM_CONSOLE
|
|
||||||
if ((fd = open("/var/run/console/console.lock", O_CREAT|O_WRONLY|O_TRUNC, 0644)) >= 0) {
|
|
||||||
write(fd, username, strlen(username));
|
|
||||||
close(fd);
|
|
||||||
run("pam_console_apply", "pam-console");
|
run("pam_console_apply", "pam-console");
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
makedir("/tmp/.X11-unix", 01777);
|
|
||||||
makedir("/tmp/.ICE-unix", 01777);
|
|
||||||
|
|
||||||
if (whichp("restorecon"))
|
|
||||||
run("restorecon /tmp/.ICE-unix /tmp/.X11-unix", "restorecon");
|
|
||||||
|
|
||||||
umask(prev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
.name = __FILE__,
|
.name = __FILE__,
|
||||||
.hook[HOOK_NETWORK_UP] = {
|
.hook[HOOK_SVC_PLUGIN] = { .cb = setup },
|
||||||
.cb = setup
|
|
||||||
},
|
|
||||||
.depends = { "bootmisc", }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
|
|||||||
+7
-2
@@ -42,8 +42,10 @@ logit_CFLAGS += $(lite_CFLAGS)
|
|||||||
logit_LDADD = $(lite_LIBS)
|
logit_LDADD = $(lite_LIBS)
|
||||||
|
|
||||||
finit_SOURCES = api.c cgroup.c cgroup.h \
|
finit_SOURCES = api.c cgroup.c cgroup.h \
|
||||||
|
client.c client.h \
|
||||||
cond.c cond-w.c cond.h \
|
cond.c cond-w.c cond.h \
|
||||||
conf.c conf.h \
|
conf.c conf.h \
|
||||||
|
devmon.c devmon.h \
|
||||||
exec.c finit.c finit.h \
|
exec.c finit.c finit.h \
|
||||||
stty.c \
|
stty.c \
|
||||||
helpers.c helpers.h \
|
helpers.c helpers.h \
|
||||||
@@ -57,6 +59,7 @@ finit_SOURCES = api.c cgroup.c cgroup.h \
|
|||||||
sig.c sig.h \
|
sig.c sig.h \
|
||||||
sm.c sm.h \
|
sm.c sm.h \
|
||||||
svc.c svc.h \
|
svc.c svc.h \
|
||||||
|
tmpfiles.c tmpfiles.h \
|
||||||
tty.c tty.h \
|
tty.c tty.h \
|
||||||
util.c util.h \
|
util.c util.h \
|
||||||
utmp-api.c utmp-api.h
|
utmp-api.c utmp-api.h
|
||||||
@@ -64,8 +67,10 @@ if LOGROTATE
|
|||||||
finit_SOURCES += logrotate.c
|
finit_SOURCES += logrotate.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
pkginclude_HEADERS = cgroup.h cond.h finit.h helpers.h log.h plugin.h svc.h
|
pkginclude_HEADERS = cgroup.h cond.h conf.h finit.h helpers.h log.h \
|
||||||
|
plugin.h svc.h service.h
|
||||||
|
|
||||||
|
finit_CPPFLAGS = $(AM_CPPFLAGS) -D__FINIT__
|
||||||
finit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
finit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||||
finit_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
|
finit_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
|
||||||
finit_LDADD = $(lite_LIBS) $(uev_LIBS)
|
finit_LDADD = $(lite_LIBS) $(uev_LIBS)
|
||||||
@@ -77,7 +82,7 @@ endif
|
|||||||
|
|
||||||
initctl_SOURCES = initctl.c initctl.h cgutil.c cgutil.h \
|
initctl_SOURCES = initctl.c initctl.h cgutil.c cgutil.h \
|
||||||
client.c client.h cond.c cond.h reboot.c \
|
client.c client.h cond.c cond.h reboot.c \
|
||||||
serv.c serv.h svc.h util.c util.h
|
serv.c serv.h svc.h util.c util.h log.h
|
||||||
initctl_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
initctl_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||||
initctl_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
|
initctl_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
|
||||||
initctl_LDADD = $(lite_LIBS) $(uev_LIBS)
|
initctl_LDADD = $(lite_LIBS) $(uev_LIBS)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* External client API, using UNIX domain socket.
|
/* External client API, using UNIX domain socket.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2015-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -45,11 +45,11 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
#include "private.h"
|
#include "private.h"
|
||||||
#include "sig.h"
|
#include "schedule.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
|
#include "sig.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
extern svc_t *wdog;
|
|
||||||
static uev_t api_watcher;
|
static uev_t api_watcher;
|
||||||
|
|
||||||
static int call(int (*action)(svc_t *, void *), char *buf, size_t len)
|
static int call(int (*action)(svc_t *, void *), char *buf, size_t len)
|
||||||
@@ -62,6 +62,7 @@ static int stop(svc_t *svc, void *user_data)
|
|||||||
if (!svc)
|
if (!svc)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
service_timeout_cancel(svc);
|
||||||
svc_stop(svc);
|
svc_stop(svc);
|
||||||
service_step(svc);
|
service_step(svc);
|
||||||
|
|
||||||
@@ -73,6 +74,7 @@ static int start(svc_t *svc, void *user_data)
|
|||||||
if (!svc)
|
if (!svc)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
service_timeout_cancel(svc);
|
||||||
svc_start(svc);
|
svc_start(svc);
|
||||||
service_step(svc);
|
service_step(svc);
|
||||||
|
|
||||||
@@ -89,8 +91,11 @@ static int restart(svc_t *svc, void *user_data)
|
|||||||
if (!svc)
|
if (!svc)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
svc_mark_dirty(svc);
|
if (!svc_is_running(svc))
|
||||||
svc_start(svc);
|
return start(svc, user_data);
|
||||||
|
|
||||||
|
service_timeout_cancel(svc);
|
||||||
|
service_stop(svc);
|
||||||
service_step(svc);
|
service_step(svc);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -103,6 +108,8 @@ static int reload(svc_t *svc, void *user_data)
|
|||||||
|
|
||||||
if (svc_is_blocked(svc))
|
if (svc_is_blocked(svc))
|
||||||
svc_start(svc);
|
svc_start(svc);
|
||||||
|
else
|
||||||
|
service_timeout_cancel(svc);
|
||||||
|
|
||||||
svc_mark_dirty(svc);
|
svc_mark_dirty(svc);
|
||||||
service_step(svc);
|
service_step(svc);
|
||||||
@@ -203,53 +210,76 @@ static svc_t *do_find(char *buf, size_t len)
|
|||||||
|
|
||||||
static svc_t *do_find_byc(char *buf, size_t len)
|
static svc_t *do_find_byc(char *buf, size_t len)
|
||||||
{
|
{
|
||||||
svc_t *svc, *iter = NULL;
|
|
||||||
char *input;
|
char *input;
|
||||||
|
|
||||||
input = sanitize(buf, len);
|
input = sanitize(buf, len);
|
||||||
if (!input) {
|
if (!input) {
|
||||||
_d("Invalid input");
|
dbg("Invalid input");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
return svc_find_by_cond(input);
|
||||||
char cond[MAX_COND_LEN];
|
|
||||||
|
|
||||||
mkcond(svc, cond, sizeof(cond));
|
|
||||||
_d("Comparing input %s with cond %s", input, cond);
|
|
||||||
if (string_compare(cond, input))
|
|
||||||
return svc;
|
|
||||||
}
|
|
||||||
|
|
||||||
_d("None found");
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_reboot(int cmd, char *buf, size_t len)
|
static void bypass_shutdown(void *);
|
||||||
|
struct wq emergency = { .cb = bypass_shutdown };
|
||||||
|
|
||||||
|
static void bypass_shutdown(void *unused)
|
||||||
|
{
|
||||||
|
cprintf("TIMEOUT TIMEOUT SHUTTING DOWN NOW!!\n");
|
||||||
|
do_shutdown(halt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_reboot(int cmd, int timeout, char *buf, size_t len)
|
||||||
{
|
{
|
||||||
int rc = 1;
|
int rc = 1;
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case INIT_CMD_REBOOT:
|
case INIT_CMD_REBOOT:
|
||||||
_d("reboot");
|
halt = SHUT_REBOOT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INIT_CMD_HALT:
|
||||||
|
halt = SHUT_HALT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INIT_CMD_POWEROFF:
|
||||||
|
halt = SHUT_OFF;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INIT_CMD_SUSPEND:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout > 0) {
|
||||||
|
emergency.delay = timeout * 1000;
|
||||||
|
schedule_work(&emergency);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case INIT_CMD_REBOOT:
|
||||||
|
dbg("reboot");
|
||||||
halt = SHUT_REBOOT;
|
halt = SHUT_REBOOT;
|
||||||
service_runlevel(6);
|
service_runlevel(6);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_HALT:
|
case INIT_CMD_HALT:
|
||||||
_d("halt");
|
dbg("halt");
|
||||||
halt = SHUT_HALT;
|
halt = SHUT_HALT;
|
||||||
service_runlevel(0);
|
service_runlevel(0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_POWEROFF:
|
case INIT_CMD_POWEROFF:
|
||||||
_d("poweroff");
|
dbg("poweroff");
|
||||||
halt = SHUT_OFF;
|
halt = SHUT_OFF;
|
||||||
service_runlevel(0);
|
service_runlevel(0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_SUSPEND:
|
case INIT_CMD_SUSPEND:
|
||||||
_d("suspend");
|
dbg("suspend");
|
||||||
sync();
|
sync();
|
||||||
rc = suspend();
|
rc = suspend();
|
||||||
if (rc) {
|
if (rc) {
|
||||||
@@ -261,7 +291,7 @@ static int do_reboot(int cmd, char *buf, size_t len)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
rc = 255;
|
/* Handled previously */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,7 +320,7 @@ static void send_svc(int sd, svc_t *svc)
|
|||||||
|
|
||||||
len = write(sd, svc, sizeof(*svc));
|
len = write(sd, svc, sizeof(*svc));
|
||||||
if (len != sizeof(*svc))
|
if (len != sizeof(*svc))
|
||||||
_d("Failed sending svc_t to client");
|
dbg("Failed sending svc_t to client");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void api_cb(uev_t *w, void *arg, int events)
|
static void api_cb(uev_t *w, void *arg, int events)
|
||||||
@@ -302,7 +332,7 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
|
|
||||||
sd = accept(w->fd, NULL, NULL);
|
sd = accept(w->fd, NULL, NULL);
|
||||||
if (sd < 0) {
|
if (sd < 0) {
|
||||||
_pe("Failed serving API request");
|
err(1, "Failed serving API request");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,14 +349,37 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
if (EAGAIN == errno)
|
if (EAGAIN == errno)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
_e("Failed reading initctl request, error %d: %s", errno, strerror(errno));
|
/* we get here when client restarts itself */
|
||||||
|
if (ECONNRESET == errno)
|
||||||
|
break;
|
||||||
|
|
||||||
|
errx(1, "Failed reading initctl request, error %d: %s", errno, strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rq.magic != INIT_MAGIC || len != sizeof(rq)) {
|
if (rq.magic != INIT_MAGIC || len != sizeof(rq)) {
|
||||||
_e("Invalid initctl request");
|
errx(1, "Invalid initctl request");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (rq.cmd) {
|
||||||
|
case INIT_CMD_RUNLVL:
|
||||||
|
case INIT_CMD_RELOAD:
|
||||||
|
case INIT_CMD_START_SVC:
|
||||||
|
case INIT_CMD_RESTART_SVC:
|
||||||
|
case INIT_CMD_STOP_SVC:
|
||||||
|
case INIT_CMD_RELOAD_SVC:
|
||||||
|
case INIT_CMD_REBOOT:
|
||||||
|
case INIT_CMD_HALT:
|
||||||
|
case INIT_CMD_POWEROFF:
|
||||||
|
case INIT_CMD_SUSPEND:
|
||||||
|
if (IS_RESERVED_RUNLEVEL(runlevel)) {
|
||||||
|
warnx("Unsupported command in runlevel S and 6.");
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,7 +392,7 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
|
|
||||||
case '0'...'9':
|
case '0'...'9':
|
||||||
_d("Setting new runlevel %c", rq.runlevel);
|
dbg("Setting new runlevel %c", rq.runlevel);
|
||||||
lvl = rq.runlevel - '0';
|
lvl = rq.runlevel - '0';
|
||||||
if (lvl == 0)
|
if (lvl == 0)
|
||||||
halt = SHUT_OFF;
|
halt = SHUT_OFF;
|
||||||
@@ -349,47 +402,55 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_d("Unsupported runlevel: %d", rq.runlevel);
|
dbg("Unsupported runlevel: %d", rq.runlevel);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_DEBUG:
|
case INIT_CMD_DEBUG:
|
||||||
_d("debug");
|
dbg("debug");
|
||||||
log_debug();
|
log_debug();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_RELOAD: /* 'init q' and 'initctl reload' */
|
case INIT_CMD_RELOAD: /* 'init q' and 'initctl reload' */
|
||||||
_d("reload");
|
dbg("reload");
|
||||||
service_reload_dynamic();
|
service_reload_dynamic();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_START_SVC:
|
case INIT_CMD_START_SVC:
|
||||||
_d("start %s", rq.data);
|
dbg("start %s", rq.data);
|
||||||
strterm(rq.data, sizeof(rq.data));
|
strterm(rq.data, sizeof(rq.data));
|
||||||
result = do_start(rq.data, sizeof(rq.data));
|
result = do_start(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_RESTART_SVC:
|
case INIT_CMD_RESTART_SVC:
|
||||||
_d("restart %s", rq.data);
|
dbg("restart %s", rq.data);
|
||||||
strterm(rq.data, sizeof(rq.data));
|
strterm(rq.data, sizeof(rq.data));
|
||||||
result = do_restart(rq.data, sizeof(rq.data));
|
result = do_restart(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_STOP_SVC:
|
case INIT_CMD_STOP_SVC:
|
||||||
_d("stop %s", rq.data);
|
dbg("stop %s", rq.data);
|
||||||
strterm(rq.data, sizeof(rq.data));
|
strterm(rq.data, sizeof(rq.data));
|
||||||
result = do_stop(rq.data, sizeof(rq.data));
|
result = do_stop(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_RELOAD_SVC:
|
case INIT_CMD_RELOAD_SVC:
|
||||||
_d("reload %s", rq.data);
|
dbg("reload %s", rq.data);
|
||||||
strterm(rq.data, sizeof(rq.data));
|
strterm(rq.data, sizeof(rq.data));
|
||||||
result = do_reload(rq.data, sizeof(rq.data));
|
result = do_reload(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case INIT_CMD_GET_PLUGINS:
|
||||||
|
result = plugin_list(rq.data, sizeof(rq.data));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INIT_CMD_PLUGIN_DEPS:
|
||||||
|
result = plugin_deps(rq.data, sizeof(rq.data));
|
||||||
|
break;
|
||||||
|
|
||||||
case INIT_CMD_GET_RUNLEVEL:
|
case INIT_CMD_GET_RUNLEVEL:
|
||||||
_d("get runlevel");
|
dbg("get runlevel");
|
||||||
rq.runlevel = runlevel;
|
rq.runlevel = runlevel;
|
||||||
rq.sleeptime = prevlevel;
|
rq.sleeptime = prevlevel;
|
||||||
break;
|
break;
|
||||||
@@ -398,21 +459,21 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
case INIT_CMD_HALT:
|
case INIT_CMD_HALT:
|
||||||
case INIT_CMD_POWEROFF:
|
case INIT_CMD_POWEROFF:
|
||||||
case INIT_CMD_SUSPEND:
|
case INIT_CMD_SUSPEND:
|
||||||
result = do_reboot(rq.cmd, rq.data, sizeof(rq.data));
|
result = do_reboot(rq.cmd, rq.sleeptime, rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_ACK:
|
case INIT_CMD_ACK:
|
||||||
_d("Client failed reading ACK");
|
dbg("Client failed reading ACK");
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
case INIT_CMD_WDOG_HELLO:
|
case INIT_CMD_WDOG_HELLO:
|
||||||
_d("wdog hello");
|
dbg("wdog hello");
|
||||||
if (rq.runlevel <= 0) {
|
if (rq.runlevel <= 0) {
|
||||||
result = 1;
|
result = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("Request to hand-over wdog ... to PID %d", rq.runlevel);
|
dbg("Request to hand-over wdog ... to PID %d", rq.runlevel);
|
||||||
svc = svc_find_by_pid(rq.runlevel);
|
svc = svc_find_by_pid(rq.runlevel);
|
||||||
if (!svc) {
|
if (!svc) {
|
||||||
logit(LOG_ERR, "Cannot find PID %d, not registered.", rq.runlevel);
|
logit(LOG_ERR, "Cannot find PID %d, not registered.", rq.runlevel);
|
||||||
@@ -436,7 +497,7 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_SVC_ITER:
|
case INIT_CMD_SVC_ITER:
|
||||||
// _d("svc iter, first: %d", rq.runlevel);
|
// dbg("svc iter, first: %d", rq.runlevel);
|
||||||
/*
|
/*
|
||||||
* XXX: This severely limits the number of
|
* XXX: This severely limits the number of
|
||||||
* simultaneous client connections, but will
|
* simultaneous client connections, but will
|
||||||
@@ -447,32 +508,46 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
case INIT_CMD_SVC_QUERY:
|
case INIT_CMD_SVC_QUERY:
|
||||||
_d("svc query: %s", rq.data);
|
dbg("svc query: %s", rq.data);
|
||||||
strterm(rq.data, sizeof(rq.data));
|
strterm(rq.data, sizeof(rq.data));
|
||||||
result = do_query(rq.data, sizeof(rq.data));
|
result = do_query(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_SVC_FIND:
|
case INIT_CMD_SVC_FIND:
|
||||||
_d("svc find: %s", rq.data);
|
dbg("svc find: %s", rq.data);
|
||||||
strterm(rq.data, sizeof(rq.data));
|
strterm(rq.data, sizeof(rq.data));
|
||||||
send_svc(sd, do_find(rq.data, sizeof(rq.data)));
|
send_svc(sd, do_find(rq.data, sizeof(rq.data)));
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
case INIT_CMD_SVC_FIND_BYC:
|
case INIT_CMD_SVC_FIND_BYC:
|
||||||
_d("svc find by cond: %s", rq.data);
|
dbg("svc find by cond: %s", rq.data);
|
||||||
strterm(rq.data, sizeof(rq.data));
|
strterm(rq.data, sizeof(rq.data));
|
||||||
send_svc(sd, do_find_byc(rq.data, sizeof(rq.data)));
|
send_svc(sd, do_find_byc(rq.data, sizeof(rq.data)));
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
case INIT_CMD_SIGNAL:
|
case INIT_CMD_SIGNAL:
|
||||||
/* runlevel is reused for signal */
|
/* runlevel is reused for signal */
|
||||||
_d("svc signal %d: %s", rq.runlevel, rq.data);
|
dbg("svc signal %d: %s", rq.runlevel, rq.data);
|
||||||
strterm(rq.data, sizeof(rq.data));
|
strterm(rq.data, sizeof(rq.data));
|
||||||
result = do_signal(rq.data, sizeof(rq.data), rq.runlevel);
|
result = do_signal(rq.data, sizeof(rq.data), rq.runlevel);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case INIT_CMD_NOTIFY_SOCKET:
|
||||||
|
svc = svc_find_by_pid(rq.runlevel);
|
||||||
|
if (!svc) {
|
||||||
|
errx(1, "Unknown PID, cannot register notify socket");
|
||||||
|
result = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uev_io_init(ctx, &svc->notify_watcher, service_notify_cb, svc, sd, UEV_READ)) {
|
||||||
|
err(1, "Falied initializing %s readiness notifier", svc_ident(svc, NULL, 0));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return; /* Don't close sd, used for notify */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_d("Unsupported cmd: %d", rq.cmd);
|
dbg("Unsupported cmd: %d", rq.cmd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -482,7 +557,7 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
rq.cmd = INIT_CMD_ACK;
|
rq.cmd = INIT_CMD_ACK;
|
||||||
len = write(sd, &rq, sizeof(rq));
|
len = write(sd, &rq, sizeof(rq));
|
||||||
if (len != sizeof(rq))
|
if (len != sizeof(rq))
|
||||||
_d("Failed sending ACK/NACK back to client");
|
dbg("Failed sending ACK/NACK back to client");
|
||||||
}
|
}
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
@@ -493,7 +568,7 @@ leave:
|
|||||||
error:
|
error:
|
||||||
api_exit();
|
api_exit();
|
||||||
if (api_init(w->ctx))
|
if (api_init(w->ctx))
|
||||||
_e("Unrecoverable error on API socket");
|
errx(1, "Unrecoverable error on API socket");
|
||||||
}
|
}
|
||||||
|
|
||||||
int api_init(uev_ctx_t *ctx)
|
int api_init(uev_ctx_t *ctx)
|
||||||
@@ -506,10 +581,10 @@ int api_init(uev_ctx_t *ctx)
|
|||||||
int uid, gid;
|
int uid, gid;
|
||||||
int sd;
|
int sd;
|
||||||
|
|
||||||
_d("Setting up external API socket ...");
|
dbg("Setting up external API socket ...");
|
||||||
sd = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
|
sd = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
|
||||||
if (-1 == sd) {
|
if (-1 == sd) {
|
||||||
_pe("Failed starting external API socket");
|
err(1, "Failed starting external API socket");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -525,14 +600,14 @@ int api_init(uev_ctx_t *ctx)
|
|||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (chown(INIT_SOCKET, uid, gid))
|
if (chown(INIT_SOCKET, uid, gid))
|
||||||
_pe("Failed setting group %s on %s", DEFGROUP, INIT_SOCKET);
|
err(1, "Failed setting group %s on %s", DEFGROUP, INIT_SOCKET);
|
||||||
|
|
||||||
umask(oldmask);
|
umask(oldmask);
|
||||||
if (!uev_io_init(ctx, &api_watcher, api_cb, NULL, sd, UEV_READ))
|
if (!uev_io_init(ctx, &api_watcher, api_cb, NULL, sd, UEV_READ))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
_pe("Failed initializing API socket");
|
err(1, "Failed initializing API socket");
|
||||||
umask(oldmask);
|
umask(oldmask);
|
||||||
close(sd);
|
close(sd);
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
+32
-29
@@ -1,6 +1,6 @@
|
|||||||
/* Finit control group support functions
|
/* Finit control group support functions
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2019-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -63,16 +63,16 @@ static void cgset(const char *path, char *ctrl, char *prop)
|
|||||||
{
|
{
|
||||||
char *val;
|
char *val;
|
||||||
|
|
||||||
_d("path %s, ctrl %s, prop %s", path ?: "NIL", ctrl ?: "NIL", prop ?: "NIL");
|
dbg("path %s, ctrl %s, prop %s", path ?: "NIL", ctrl ?: "NIL", prop ?: "NIL");
|
||||||
if (!path || !ctrl) {
|
if (!path || !ctrl) {
|
||||||
_e("Missing path or controller, skipping!");
|
errx(1, "Missing path or controller, skipping!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!prop) {
|
if (!prop) {
|
||||||
prop = strchr(ctrl, '.');
|
prop = strchr(ctrl, '.');
|
||||||
if (!prop) {
|
if (!prop) {
|
||||||
_e("Invalid cgroup ctrl syntax: %s", ctrl);
|
errx(1, "Invalid cgroup ctrl syntax: %s", ctrl);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,20 +81,20 @@ static void cgset(const char *path, char *ctrl, char *prop)
|
|||||||
|
|
||||||
val = strchr(prop, ':');
|
val = strchr(prop, ':');
|
||||||
if (!val) {
|
if (!val) {
|
||||||
_e("Missing cgroup ctrl value, prop %s", prop);
|
errx(1, "Missing cgroup ctrl value, prop %s", prop);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*val++ = 0;
|
*val++ = 0;
|
||||||
|
|
||||||
/* disallow sneaky relative paths */
|
/* disallow sneaky relative paths */
|
||||||
if (strstr(ctrl, "..") || strstr(prop, "..")) {
|
if (strstr(ctrl, "..") || strstr(prop, "..")) {
|
||||||
_e("Possible security violation; '..' not allowed in cgroup config!");
|
errx(1, "Possible security violation; '..' not allowed in cgroup config!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("%s/%s.%s <= %s", path, ctrl, prop, val);
|
dbg("%s/%s.%s <= %s", path, ctrl, prop, val);
|
||||||
if (fnwrite(val, "%s/%s.%s", path, ctrl, prop))
|
if (fnwrite(val, "%s/%s.%s", path, ctrl, prop))
|
||||||
_pe("Failed setting %s/%s.%s = %s", path, ctrl, prop, val);
|
err(1, "Failed setting %s/%s.%s = %s", path, ctrl, prop, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -106,16 +106,16 @@ static void group_init(char *path, int leaf, const char *cfg)
|
|||||||
{
|
{
|
||||||
char *ptr, *s;
|
char *ptr, *s;
|
||||||
|
|
||||||
_d("path %s, leaf %d, cfg %s", path, leaf, cfg ?: "NIL");
|
dbg("path %s, leaf %d, cfg %s", path, leaf, cfg ?: "NIL");
|
||||||
if (!fisdir(path)) {
|
if (!fisdir(path)) {
|
||||||
if (mkdir(path, 0755)) {
|
if (mkdir(path, 0755)) {
|
||||||
_pe("Failed creating cgroup %s", path);
|
err(1, "Failed creating cgroup %s", path);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* enable detected controllers on domain groups */
|
/* enable detected controllers on domain groups */
|
||||||
if (!leaf && fnwrite(controllers, "%s/cgroup.subtree_control", path))
|
if (!leaf && fnwrite(controllers, "%s/cgroup.subtree_control", path))
|
||||||
_pe("Failed enabling %s for %s", controllers, path);
|
err(1, "Failed enabling %s for %s", controllers, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cfg || !cfg[0])
|
if (!cfg || !cfg[0])
|
||||||
@@ -123,14 +123,14 @@ static void group_init(char *path, int leaf, const char *cfg)
|
|||||||
|
|
||||||
s = strdupa(cfg);
|
s = strdupa(cfg);
|
||||||
if (!s) {
|
if (!s) {
|
||||||
_pe("Failed activating cgroup cfg for %s", path);
|
err(1, "Failed activating cgroup cfg for %s", path);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("%s <=> %s", path, s);
|
dbg("%s <=> %s", path, s);
|
||||||
ptr = strtok(s, ",");
|
ptr = strtok(s, ",");
|
||||||
while (ptr) {
|
while (ptr) {
|
||||||
_d("ptr: %s", ptr);
|
dbg("ptr: %s", ptr);
|
||||||
if (!strncmp("mem.", ptr, 4))
|
if (!strncmp("mem.", ptr, 4))
|
||||||
cgset(path, "memory", &ptr[4]);
|
cgset(path, "memory", &ptr[4]);
|
||||||
else
|
else
|
||||||
@@ -144,7 +144,7 @@ static int cgroup_leaf_init(char *group, char *name, int pid, const char *cfg)
|
|||||||
{
|
{
|
||||||
char path[256];
|
char path[256];
|
||||||
|
|
||||||
_d("group %s, name %s, pid %d, cfg %s", group, name, pid, cfg ?: "NIL");
|
dbg("group %s, name %s, pid %d, cfg %s", group, name, pid, cfg ?: "NIL");
|
||||||
if (pid < 0 || pid == 1) {
|
if (pid < 0 || pid == 1) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return 1;
|
return 1;
|
||||||
@@ -156,7 +156,7 @@ static int cgroup_leaf_init(char *group, char *name, int pid, const char *cfg)
|
|||||||
|
|
||||||
/* move process to new group */
|
/* move process to new group */
|
||||||
if (fnwrite(str("%d", pid), "%s/cgroup.procs", path))
|
if (fnwrite(str("%d", pid), "%s/cgroup.procs", path))
|
||||||
_pe("Failed moving pid %d to group %s", pid, path);
|
err(1, "Failed moving pid %d to group %s", pid, path);
|
||||||
|
|
||||||
strlcat(path, "/cgroup.events", sizeof(path));
|
strlcat(path, "/cgroup.events", sizeof(path));
|
||||||
|
|
||||||
@@ -211,13 +211,13 @@ static void cgroup_handle_event(char *event, uint32_t mask)
|
|||||||
char *ptr;
|
char *ptr;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
_d("event: '%s', mask: %08x", event, mask);
|
dbg("event: '%s', mask: %08x", event, mask);
|
||||||
if (!(mask & IN_MODIFY))
|
if (!(mask & IN_MODIFY))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fp = fopen(event, "r");
|
fp = fopen(event, "r");
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
_d("Failed opening %s, skipping ...", event);
|
dbg("Failed opening %s, skipping ...", event);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,7 +261,7 @@ static void cgroup_events_cb(uev_t *w, void *arg, int events)
|
|||||||
|
|
||||||
sz = read(w->fd, ev_buf, sizeof(ev_buf) - 1);
|
sz = read(w->fd, ev_buf, sizeof(ev_buf) - 1);
|
||||||
if (sz <= 0) {
|
if (sz <= 0) {
|
||||||
_pe("invalid inotify event");
|
err(1, "invalid inotify event");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ev_buf[sz] = 0;
|
ev_buf[sz] = 0;
|
||||||
@@ -287,7 +287,7 @@ static void cgroup_events_cb(uev_t *w, void *arg, int events)
|
|||||||
cgroup_handle_event(iwp->path, ev->mask);
|
cgroup_handle_event(iwp->path, ev->mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_AUTO_RELOAD
|
#ifdef AUTO_RELOAD
|
||||||
if (conf_any_change())
|
if (conf_any_change())
|
||||||
service_reload_dynamic();
|
service_reload_dynamic();
|
||||||
#endif
|
#endif
|
||||||
@@ -364,12 +364,12 @@ int cgroup_add(char *name, char *cfg, int is_protected)
|
|||||||
if (!cg) {
|
if (!cg) {
|
||||||
cg = malloc(sizeof(struct cg));
|
cg = malloc(sizeof(struct cg));
|
||||||
if (!cg) {
|
if (!cg) {
|
||||||
_pe("Failed allocating 'struct cg' for %s", name);
|
err(1, "Failed allocating 'struct cg' for %s", name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
cg->name = strdup(name);
|
cg->name = strdup(name);
|
||||||
if (!cg->name) {
|
if (!cg->name) {
|
||||||
_pe("Failed setting cgroup name %s", name);
|
err(1, "Failed setting cgroup name %s", name);
|
||||||
free(cg);
|
free(cg);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -379,7 +379,7 @@ int cgroup_add(char *name, char *cfg, int is_protected)
|
|||||||
|
|
||||||
cg->cfg = strdup(cfg);
|
cg->cfg = strdup(cfg);
|
||||||
if (!cg->cfg) {
|
if (!cg->cfg) {
|
||||||
_pe("Failed add/update of cgroup %s", name);
|
err(1, "Failed add/update of cgroup %s", name);
|
||||||
TAILQ_REMOVE(&cgroups, cg, link);
|
TAILQ_REMOVE(&cgroups, cg, link);
|
||||||
free(cg->name);
|
free(cg->name);
|
||||||
free(cg);
|
free(cg);
|
||||||
@@ -414,7 +414,7 @@ int cgroup_del(char *dir)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rmdir(dir) && errno != ENOENT) {
|
if (rmdir(dir) && errno != ENOENT) {
|
||||||
_d("Failed removing %s: %s", dir, strerror(errno));
|
dbg("Failed removing %s: %s", dir, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -469,7 +469,7 @@ void cgroup_init(uev_ctx_t *ctx)
|
|||||||
else if (errno == EPERM) /* Probably inside an unpriviliged container */
|
else if (errno == EPERM) /* Probably inside an unpriviliged container */
|
||||||
logit(LOG_INFO, "Not allowed to mount cgroups v2, disabling.");
|
logit(LOG_INFO, "Not allowed to mount cgroups v2, disabling.");
|
||||||
else
|
else
|
||||||
_pe("Failed mounting cgroup v2");
|
err(1, "Failed mounting cgroup v2");
|
||||||
avail = 0;
|
avail = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -478,7 +478,7 @@ void cgroup_init(uev_ctx_t *ctx)
|
|||||||
/* Find available controllers */
|
/* Find available controllers */
|
||||||
fp = fopen(FINIT_CGPATH "/cgroup.controllers", "r");
|
fp = fopen(FINIT_CGPATH "/cgroup.controllers", "r");
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
_pe("Failed opening %s", FINIT_CGPATH "/cgroup.controllers");
|
err(1, "Failed opening %s", FINIT_CGPATH "/cgroup.controllers");
|
||||||
abort:
|
abort:
|
||||||
umount(FINIT_CGPATH);
|
umount(FINIT_CGPATH);
|
||||||
avail = 0;
|
avail = 0;
|
||||||
@@ -505,14 +505,17 @@ void cgroup_init(uev_ctx_t *ctx)
|
|||||||
|
|
||||||
/* Enable all controllers */
|
/* Enable all controllers */
|
||||||
if (fnwrite(controllers, FINIT_CGPATH "/cgroup.subtree_control")) {
|
if (fnwrite(controllers, FINIT_CGPATH "/cgroup.subtree_control")) {
|
||||||
_pe("Failed enabling %s for %s", controllers, FINIT_CGPATH "/cgroup.subtree_control");
|
err(1, "Failed enabling %s for %s", controllers, FINIT_CGPATH "/cgroup.subtree_control");
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* prepare cgroup.events watcher */
|
/* prepare cgroup.events watcher */
|
||||||
fd = iwatch_init(&iw_cgroup);
|
fd = iwatch_init(&iw_cgroup);
|
||||||
|
if (fd == -1)
|
||||||
|
goto abort;
|
||||||
|
|
||||||
if (uev_io_init(ctx, &cgw, cgroup_events_cb, NULL, fd, UEV_READ)) {
|
if (uev_io_init(ctx, &cgw, cgroup_events_cb, NULL, fd, UEV_READ)) {
|
||||||
_pe("Failed setting up cgroup.events watcher");
|
err(1, "Failed setting up cgroup.events watcher");
|
||||||
iwatch_exit(&iw_cgroup);
|
iwatch_exit(&iw_cgroup);
|
||||||
close(fd);
|
close(fd);
|
||||||
goto abort;
|
goto abort;
|
||||||
@@ -526,7 +529,7 @@ void cgroup_init(uev_ctx_t *ctx)
|
|||||||
|
|
||||||
/* Move ourselves to init (best effort, otherwise run in 'root' group */
|
/* Move ourselves to init (best effort, otherwise run in 'root' group */
|
||||||
if (fnwrite("1", FINIT_CGPATH "/init/cgroup.procs")) {
|
if (fnwrite("1", FINIT_CGPATH "/init/cgroup.procs")) {
|
||||||
_pe("Failed moving PID 1 to cgroup %s", FINIT_CGPATH "/init");
|
err(1, "Failed moving PID 1 to cgroup %s", FINIT_CGPATH "/init");
|
||||||
uev_io_stop(&cgw);
|
uev_io_stop(&cgw);
|
||||||
iwatch_exit(&iw_cgroup);
|
iwatch_exit(&iw_cgroup);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
/* Finit control group support functions
|
/* Finit control group support functions
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2019-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
+2
-1
@@ -1,6 +1,6 @@
|
|||||||
/* New client tool, replaces old /dev/initctl API and telinit tool
|
/* New client tool, replaces old /dev/initctl API and telinit tool
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2019-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -38,6 +38,7 @@
|
|||||||
|
|
||||||
#include "cgutil.h"
|
#include "cgutil.h"
|
||||||
#include "initctl.h"
|
#include "initctl.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
#define CDIM plain ? "" : "\e[2m"
|
#define CDIM plain ? "" : "\e[2m"
|
||||||
#define CRST plain ? "" : "\e[0m"
|
#define CRST plain ? "" : "\e[0m"
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
/* Cgroup utility functions for initctl
|
/* Cgroup utility functions for initctl
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2019-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
+61
-28
@@ -1,6 +1,6 @@
|
|||||||
/* External client API, using UNIX domain socket.
|
/* External client API, using UNIX domain socket.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2015-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "initctl.h"
|
#include "log.h"
|
||||||
|
|
||||||
static int sd = -1;
|
static int sd = -1;
|
||||||
|
|
||||||
@@ -40,15 +40,15 @@ int client_connect(void)
|
|||||||
|
|
||||||
sd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
|
sd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
|
||||||
if (-1 == sd) {
|
if (-1 == sd) {
|
||||||
WARN("Failed creating UNIX domain socket");
|
warn("Failed creating UNIX domain socket");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connect(sd, (struct sockaddr*)&sun, sizeof(sun)) == -1) {
|
if (connect(sd, (struct sockaddr*)&sun, sizeof(sun)) == -1) {
|
||||||
if (errno != ENOENT)
|
if (errno != ENOENT)
|
||||||
WARNX("Failed connecting to finit");
|
warnx("Failed connecting to finit");
|
||||||
close(sd);
|
close(sd);
|
||||||
return -1;
|
sd = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sd;
|
return sd;
|
||||||
@@ -69,10 +69,15 @@ int client_disconnect(void)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int client_send(struct init_request *rq, ssize_t len)
|
/* Only valid after client_connect() */
|
||||||
|
int client_socket(void)
|
||||||
|
{
|
||||||
|
return sd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int client_request(struct init_request *rq, ssize_t len)
|
||||||
{
|
{
|
||||||
struct pollfd pfd = { 0 };
|
struct pollfd pfd = { 0 };
|
||||||
int result = 255;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (client_connect() == -1)
|
if (client_connect() == -1)
|
||||||
@@ -81,13 +86,23 @@ int client_send(struct init_request *rq, ssize_t len)
|
|||||||
pfd.fd = sd;
|
pfd.fd = sd;
|
||||||
pfd.events = POLLOUT;
|
pfd.events = POLLOUT;
|
||||||
if (poll(&pfd, 1, 2000) <= 0) {
|
if (poll(&pfd, 1, 2000) <= 0) {
|
||||||
WARN("Timed out waiting for Finit, errno %d", errno);
|
warn("Timed out waiting for Finit, errno %d", errno);
|
||||||
goto exit;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (write(sd, rq, len) != len) {
|
if (write(sd, rq, len) != len) {
|
||||||
WARN("Failed communicating with Finit, errno %d", errno);
|
warn("Failed communicating with Finit, errno %d", errno);
|
||||||
goto exit;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Exception, only command that don't need to wait for a
|
||||||
|
* response from Finit. Registers the client socket as a
|
||||||
|
* readiness notification socket with Finit
|
||||||
|
*/
|
||||||
|
if (rq->cmd == INIT_CMD_NOTIFY_SOCKET) {
|
||||||
|
rq->cmd = INIT_CMD_ACK;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pfd.fd = sd;
|
pfd.fd = sd;
|
||||||
@@ -95,26 +110,45 @@ int client_send(struct init_request *rq, ssize_t len)
|
|||||||
if ((rc = poll(&pfd, 1, 2000)) <= 0) {
|
if ((rc = poll(&pfd, 1, 2000)) <= 0) {
|
||||||
if (rc) {
|
if (rc) {
|
||||||
if (errno == EINTR) /* shutdown/reboot */
|
if (errno == EINTR) /* shutdown/reboot */
|
||||||
goto exit;
|
return -1;
|
||||||
WARN("poll(), errno %d", errno);
|
warn("poll(), errno %d", errno);
|
||||||
} else
|
} else
|
||||||
WARNX("Timed out waiting for reply from Finit.");
|
warnx("Timed out waiting for reply from Finit.");
|
||||||
goto exit;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read(sd, rq, len) != len) {
|
if (read(sd, rq, len) != len) {
|
||||||
WARN("Failed reading reply from Finit, errno %d", errno);
|
warn("Failed reading reply from Finit, errno %d", errno);
|
||||||
goto exit;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rq->cmd == INIT_CMD_NACK)
|
if (rq->cmd == INIT_CMD_NACK)
|
||||||
result = 1;
|
return -1;
|
||||||
else
|
|
||||||
result = 0;
|
return 0;
|
||||||
exit:
|
}
|
||||||
|
|
||||||
|
int client_send(struct init_request *rq, ssize_t len)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (client_request(rq, len))
|
||||||
|
rc = 255;
|
||||||
|
|
||||||
client_disconnect();
|
client_disconnect();
|
||||||
|
|
||||||
return result;
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int client_command(int cmd)
|
||||||
|
{
|
||||||
|
struct init_request rq = {
|
||||||
|
.magic = INIT_MAGIC,
|
||||||
|
.runlevel = getpid(),
|
||||||
|
.cmd = cmd,
|
||||||
|
};
|
||||||
|
|
||||||
|
return client_request(&rq, sizeof(rq));
|
||||||
}
|
}
|
||||||
|
|
||||||
svc_t *client_svc_iterator(int first)
|
svc_t *client_svc_iterator(int first)
|
||||||
@@ -144,14 +178,14 @@ svc_t *client_svc_iterator(int first)
|
|||||||
|
|
||||||
return &svc;
|
return &svc;
|
||||||
error:
|
error:
|
||||||
WARN("Failed communicating with finit, error %d", errno);
|
warn("Failed communicating with finit, error %d", errno);
|
||||||
client_disconnect();
|
client_disconnect();
|
||||||
sd = -1;
|
sd = -1;
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
svc_t *do_cmd(int cmd, const char *arg)
|
static svc_t *do_find(int cmd, const char *arg)
|
||||||
{
|
{
|
||||||
struct init_request rq = {
|
struct init_request rq = {
|
||||||
.magic = INIT_MAGIC,
|
.magic = INIT_MAGIC,
|
||||||
@@ -175,20 +209,19 @@ svc_t *do_cmd(int cmd, const char *arg)
|
|||||||
return &svc;
|
return &svc;
|
||||||
error:
|
error:
|
||||||
client_disconnect();
|
client_disconnect();
|
||||||
WARN("Failed communicating with finit, error %d", errno);
|
warn("Failed communicating with finit, error %d", errno);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
svc_t *client_svc_find(const char *arg)
|
svc_t *client_svc_find(const char *arg)
|
||||||
{
|
{
|
||||||
return do_cmd(INIT_CMD_SVC_FIND, arg);
|
return do_find(INIT_CMD_SVC_FIND, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
svc_t *client_svc_find_by_cond(const char *arg)
|
svc_t *client_svc_find_by_cond(const char *arg)
|
||||||
{
|
{
|
||||||
return do_cmd(INIT_CMD_SVC_FIND_BYC, arg);
|
return do_find(INIT_CMD_SVC_FIND_BYC, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+5
-1
@@ -1,6 +1,6 @@
|
|||||||
/* External client API, using UNIX domain socket.
|
/* External client API, using UNIX domain socket.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2015-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -29,8 +29,12 @@
|
|||||||
|
|
||||||
int client_connect (void);
|
int client_connect (void);
|
||||||
int client_disconnect (void);
|
int client_disconnect (void);
|
||||||
|
int client_socket (void);
|
||||||
|
|
||||||
|
int client_request (struct init_request *rq, ssize_t len);
|
||||||
int client_send (struct init_request *rq, ssize_t len);
|
int client_send (struct init_request *rq, ssize_t len);
|
||||||
|
int client_command (int cmd);
|
||||||
|
|
||||||
svc_t *client_svc_iterator (int first);
|
svc_t *client_svc_iterator (int first);
|
||||||
svc_t *client_svc_find (const char *arg);
|
svc_t *client_svc_find (const char *arg);
|
||||||
svc_t *client_svc_find_by_cond (const char *arg);
|
svc_t *client_svc_find_by_cond (const char *arg);
|
||||||
|
|||||||
+137
-43
@@ -36,6 +36,70 @@
|
|||||||
#include "pid.h"
|
#include "pid.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
|
|
||||||
|
struct cond_boot {
|
||||||
|
TAILQ_ENTRY(cond_boot) link;
|
||||||
|
char *name;
|
||||||
|
};
|
||||||
|
static TAILQ_HEAD(, cond_boot) cond_boot_list = TAILQ_HEAD_INITIALIZER(cond_boot_list);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse finit.cond=cond[,cond[,...]] from command line. It creates a
|
||||||
|
* temporary linked list of conds which are freed when finit reaches
|
||||||
|
* cond_init(), which calls cond_boot_strap() to realize the conditions
|
||||||
|
* in the file system as regular static conditions. Policy, however,
|
||||||
|
* dictates that these are read-only and should not be possible to
|
||||||
|
* manage from initctl.
|
||||||
|
*/
|
||||||
|
void cond_boot_parse(char *arg)
|
||||||
|
{
|
||||||
|
struct cond_boot *node;
|
||||||
|
|
||||||
|
if (!arg)
|
||||||
|
return;
|
||||||
|
|
||||||
|
node = malloc(sizeof(*node));
|
||||||
|
if (!node) {
|
||||||
|
err(1, "Out of memory cannot track boot conditions");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->name = strdup(arg);
|
||||||
|
TAILQ_INSERT_HEAD(&cond_boot_list, node, link);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert all conditions read from the kernel command line (above) into
|
||||||
|
* proper finit conditions.
|
||||||
|
*/
|
||||||
|
static void cond_boot_strap(void)
|
||||||
|
{
|
||||||
|
struct cond_boot *node, *tmp;
|
||||||
|
|
||||||
|
TAILQ_FOREACH_SAFE(node, &cond_boot_list, link, tmp) {
|
||||||
|
TAILQ_REMOVE(&cond_boot_list, node, link);
|
||||||
|
if (node->name) {
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
ptr = strtok(node->name, ",");
|
||||||
|
while (ptr) {
|
||||||
|
char cond[strlen(ptr) + 6];
|
||||||
|
|
||||||
|
if (strncmp(ptr, "boot/", 5))
|
||||||
|
snprintf(cond, sizeof(cond), "boot/%s", ptr);
|
||||||
|
else
|
||||||
|
snprintf(cond, sizeof(cond), "%s", ptr);
|
||||||
|
cond_set_oneshot_noupdate(cond);
|
||||||
|
|
||||||
|
ptr = strtok(NULL, ",");
|
||||||
|
}
|
||||||
|
|
||||||
|
free(node->name);
|
||||||
|
}
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The service condition name is constructed from the 'pid/' prefix and
|
* The service condition name is constructed from the 'pid/' prefix and
|
||||||
* the unique NAME:ID tuple that identify each process in Finit. Here
|
* the unique NAME:ID tuple that identify each process in Finit. Here
|
||||||
@@ -111,7 +175,7 @@ static void cond_bump_reconf(void)
|
|||||||
rgen++;
|
rgen++;
|
||||||
|
|
||||||
if (cond_set_gen(_PATH_RECONF, rgen))
|
if (cond_set_gen(_PATH_RECONF, rgen))
|
||||||
_pe("Failed setting %s to gen %d", _PATH_RECONF, rgen);
|
err(1, "Failed setting %s to gen %d", _PATH_RECONF, rgen);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cond_checkpath(const char *path)
|
static int cond_checkpath(const char *path)
|
||||||
@@ -121,35 +185,45 @@ static int cond_checkpath(const char *path)
|
|||||||
strlcpy(buf, path, sizeof(buf));
|
strlcpy(buf, path, sizeof(buf));
|
||||||
dir = dirname(buf);
|
dir = dirname(buf);
|
||||||
if (!dir) {
|
if (!dir) {
|
||||||
_e("Invalid path '%s' for condition", path);
|
errx(1, "Invalid path '%s' for condition", path);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mkpath(dir, 0755) && errno != EEXIST) {
|
if (mkpath(dir, 0755) && errno != EEXIST) {
|
||||||
_pe("Failed creating dir '%s' for condition '%s'", dir, path);
|
err(1, "Failed creating dir '%s' for condition '%s'", dir, path);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Intended for 'service/foo/`, nothing else */
|
static int do_delete(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftw)
|
||||||
|
{
|
||||||
|
const char *cond, *ptr;
|
||||||
|
|
||||||
|
if (ftw->level == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
ptr = strstr(fpath, COND_BASE);
|
||||||
|
if (!ptr) {
|
||||||
|
warnx("%s does not seem to be a Finit condition, skipping", fpath);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remove(fpath))
|
||||||
|
err(1, "Failed removing condition %s", fpath);
|
||||||
|
|
||||||
|
cond = ptr + strlen(COND_BASE) + 1;
|
||||||
|
cond_update(cond);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void cond_delpath(const char *path)
|
static void cond_delpath(const char *path)
|
||||||
{
|
{
|
||||||
char fn[PATH_MAX];
|
nftw(path, do_delete, 20, FTW_DEPTH);
|
||||||
struct dirent *d;
|
if (remove(path) && errno != ENOENT)
|
||||||
DIR *dir;
|
err(1, "Failed removing condition path %s", path);
|
||||||
|
|
||||||
dir = opendir(path);
|
|
||||||
if (!dir)
|
|
||||||
return;
|
|
||||||
|
|
||||||
while ((d = readdir(dir))) {
|
|
||||||
paste(fn, sizeof(fn), path, d->d_name);
|
|
||||||
remove(fn);
|
|
||||||
}
|
|
||||||
closedir(dir);
|
|
||||||
unlink(path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int cond_set_path(const char *path, enum cond_state next)
|
int cond_set_path(const char *path, enum cond_state next)
|
||||||
@@ -157,20 +231,19 @@ int cond_set_path(const char *path, enum cond_state next)
|
|||||||
enum cond_state prev;
|
enum cond_state prev;
|
||||||
unsigned int rgen;
|
unsigned int rgen;
|
||||||
|
|
||||||
_d("%s <= %d", path, next);
|
dbg("%s <= %d", path, next);
|
||||||
|
|
||||||
rgen = cond_get_gen(_PATH_RECONF);
|
|
||||||
if (!rgen) {
|
|
||||||
_e("Unable to read configuration generation (%s)", path);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
prev = cond_get_path(path);
|
prev = cond_get_path(path);
|
||||||
|
|
||||||
switch (next) {
|
switch (next) {
|
||||||
case COND_ON:
|
case COND_ON:
|
||||||
if (cond_checkpath(path))
|
if (cond_checkpath(path))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
rgen = cond_get_gen(_PATH_RECONF);
|
||||||
|
if (!rgen) {
|
||||||
|
errx(1, "Unable to read configuration generation (%s)", path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
cond_set_gen(path, rgen);
|
cond_set_gen(path, rgen);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -183,14 +256,14 @@ int cond_set_path(const char *path, enum cond_state next)
|
|||||||
cond_delpath(path);
|
cond_delpath(path);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
_pe("Failed removing condition '%s'", path);
|
err(1, "Failed removing condition '%s'", path);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_e("Invalid condition state");
|
errx(1, "Invalid condition state");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,13 +276,19 @@ int cond_update(const char *name)
|
|||||||
svc_t *svc, *iter = NULL;
|
svc_t *svc, *iter = NULL;
|
||||||
int affects = 0;
|
int affects = 0;
|
||||||
|
|
||||||
_d("%s", name);
|
dbg("%s", name);
|
||||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
if (!svc_has_cond(svc) || !cond_affects(name, svc->cond))
|
if (!svc_has_cond(svc) || !cond_affects(name, svc->cond))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
affects++;
|
affects++;
|
||||||
_d("%s: match <%s> %s(%s)", name ?: "nil", svc->cond, svc->desc, svc->cmd);
|
dbg("%s: match <%s> %s(%s)", name ?: "nil", svc->cond, svc->desc, svc->cmd);
|
||||||
|
/* Fix bug #314: race condition between crashing services and conditions */
|
||||||
|
if (svc_is_restart(svc) && cond_get_agg(svc->cond) == COND_OFF) {
|
||||||
|
dbg("%s: cancel timer & unblock => WAITING state.", name ?: "nil");
|
||||||
|
service_timeout_cancel(svc);
|
||||||
|
svc_unblock(svc);
|
||||||
|
}
|
||||||
service_step(svc);
|
service_step(svc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,7 +297,7 @@ int cond_update(const char *name)
|
|||||||
|
|
||||||
int cond_set_noupdate(const char *name)
|
int cond_set_noupdate(const char *name)
|
||||||
{
|
{
|
||||||
_d("%s", name);
|
dbg("%s", name);
|
||||||
if (string_compare(name, "nop"))
|
if (string_compare(name, "nop"))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@@ -230,7 +309,7 @@ int cond_set_noupdate(const char *name)
|
|||||||
|
|
||||||
void cond_set(const char *name)
|
void cond_set(const char *name)
|
||||||
{
|
{
|
||||||
_d("%s", name);
|
dbg("%s", name);
|
||||||
if (cond_set_noupdate(name))
|
if (cond_set_noupdate(name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -245,13 +324,13 @@ int cond_set_oneshot_noupdate(const char *name)
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
path = cond_path(name);
|
path = cond_path(name);
|
||||||
_d("%s => %s", name, path);
|
dbg("%s => %s", name, path);
|
||||||
|
|
||||||
if (cond_checkpath(path))
|
if (cond_checkpath(path))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (symlink(_PATH_RECONF, path) && errno != EEXIST) {
|
if (symlink(_PATH_RECONF, path) && errno != EEXIST) {
|
||||||
_pe("Failed creating onshot cond %s", name);
|
err(1, "Failed creating onshot cond %s", name);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,7 +339,7 @@ int cond_set_oneshot_noupdate(const char *name)
|
|||||||
|
|
||||||
void cond_set_oneshot(const char *name)
|
void cond_set_oneshot(const char *name)
|
||||||
{
|
{
|
||||||
_d("%s", name);
|
dbg("%s", name);
|
||||||
if (cond_set_oneshot_noupdate(name))
|
if (cond_set_oneshot_noupdate(name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -269,7 +348,7 @@ void cond_set_oneshot(const char *name)
|
|||||||
|
|
||||||
int cond_clear_noupdate(const char *name)
|
int cond_clear_noupdate(const char *name)
|
||||||
{
|
{
|
||||||
_d("%s", name);
|
dbg("%s", name);
|
||||||
if (string_compare(name, "nop"))
|
if (string_compare(name, "nop"))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@@ -281,7 +360,7 @@ int cond_clear_noupdate(const char *name)
|
|||||||
|
|
||||||
void cond_clear(const char *name)
|
void cond_clear(const char *name)
|
||||||
{
|
{
|
||||||
_d("%s", name);
|
dbg("%s", name);
|
||||||
if (cond_clear_noupdate(name))
|
if (cond_clear_noupdate(name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -290,7 +369,7 @@ void cond_clear(const char *name)
|
|||||||
|
|
||||||
void cond_reload(void)
|
void cond_reload(void)
|
||||||
{
|
{
|
||||||
_d("");
|
dbg("");
|
||||||
|
|
||||||
cond_bump_reconf();
|
cond_bump_reconf();
|
||||||
}
|
}
|
||||||
@@ -307,12 +386,12 @@ static int do_assert(const char *fpath, const struct stat *sb, int tflg, struct
|
|||||||
|
|
||||||
nm = strstr((char *)fpath, COND_BASE);
|
nm = strstr((char *)fpath, COND_BASE);
|
||||||
if (!nm) {
|
if (!nm) {
|
||||||
_e("Incorrect condition path %s, cannot %sassert", fpath, set ? "re" : "de");
|
errx(1, "Incorrect condition path %s, cannot %sassert", fpath, set ? "re" : "de");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
nm += strlen(COND_BASE);
|
nm += strlen(COND_BASE);
|
||||||
_d("%sasserting %s => %s", set ? "Re" : "De", fpath, nm);
|
dbg("%sasserting %s => %s", set ? "Re" : "De", fpath, nm);
|
||||||
if (set)
|
if (set)
|
||||||
cond_set(nm);
|
cond_set(nm);
|
||||||
else
|
else
|
||||||
@@ -337,7 +416,7 @@ static int deassert(const char *fpath, const struct stat *sb, int tflg, struct F
|
|||||||
*/
|
*/
|
||||||
void cond_reassert(const char *pat)
|
void cond_reassert(const char *pat)
|
||||||
{
|
{
|
||||||
_d("%s", pat);
|
dbg("%s", pat);
|
||||||
nftw(cond_path(pat), reassert, 20, FTW_DEPTH);
|
nftw(cond_path(pat), reassert, 20, FTW_DEPTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,20 +425,35 @@ void cond_reassert(const char *pat)
|
|||||||
*/
|
*/
|
||||||
void cond_deassert(const char *pat)
|
void cond_deassert(const char *pat)
|
||||||
{
|
{
|
||||||
_d("%s", pat);
|
dbg("%s", pat);
|
||||||
nftw(cond_path(pat), deassert, 20, FTW_DEPTH);
|
nftw(cond_path(pat), deassert, 20, FTW_DEPTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if we have bootstrapped enough of the system to use conditions.
|
||||||
|
* Will answer 'No' before bootstrap done *and* at shutdown/reboot.
|
||||||
|
*/
|
||||||
|
int cond_is_available(void)
|
||||||
|
{
|
||||||
|
return fisdir(_PATH_COND);
|
||||||
|
}
|
||||||
|
|
||||||
void cond_init(void)
|
void cond_init(void)
|
||||||
{
|
{
|
||||||
char path[MAX_ARG_LEN];
|
char path[MAX_ARG_LEN];
|
||||||
|
|
||||||
if (mkpath(pid_runpath(_PATH_COND, path, sizeof(path)), 0755) && errno != EEXIST) {
|
if (mkpath(pid_runpath(_PATH_COND, path, sizeof(path)), 0755) && errno != EEXIST) {
|
||||||
_pe("Failed creating condition base directory '%s'", _PATH_COND);
|
err(1, "Failed creating condition base directory '%s'", _PATH_COND);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cond_bump_reconf();
|
cond_bump_reconf();
|
||||||
|
cond_boot_strap();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cond_exit(void)
|
||||||
|
{
|
||||||
|
cond_delpath(_PATH_COND);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+1
-1
@@ -112,7 +112,7 @@ enum cond_state cond_get_agg(const char *names)
|
|||||||
|
|
||||||
int cond_affects(const char *name, const char *names)
|
int cond_affects(const char *name, const char *names)
|
||||||
{
|
{
|
||||||
static char conds[MAX_COND_LEN];
|
char conds[MAX_COND_LEN];
|
||||||
char *cond;
|
char *cond;
|
||||||
|
|
||||||
if (!name || !names)
|
if (!name || !names)
|
||||||
|
|||||||
+9
-3
@@ -6,11 +6,13 @@
|
|||||||
#include "svc.h"
|
#include "svc.h"
|
||||||
|
|
||||||
#define COND_BASE "finit/cond"
|
#define COND_BASE "finit/cond"
|
||||||
|
#define COND_DEV "dev/"
|
||||||
#define COND_PID "pid/"
|
#define COND_PID "pid/"
|
||||||
#define COND_SYS "sys/"
|
#define COND_SYS "sys/"
|
||||||
#define COND_USR "usr/"
|
#define COND_USR "usr/"
|
||||||
|
|
||||||
#define _PATH_COND _PATH_VARRUN COND_BASE "/"
|
#define _PATH_COND _PATH_VARRUN COND_BASE "/"
|
||||||
|
#define _PATH_CONDDEV _PATH_COND COND_DEV
|
||||||
#define _PATH_CONDPID _PATH_COND COND_PID
|
#define _PATH_CONDPID _PATH_COND COND_PID
|
||||||
#define _PATH_CONDSYS _PATH_COND COND_SYS
|
#define _PATH_CONDSYS _PATH_COND COND_SYS
|
||||||
#define _PATH_CONDUSR _PATH_COND COND_USR
|
#define _PATH_CONDUSR _PATH_COND COND_USR
|
||||||
@@ -31,6 +33,7 @@ enum cond_state cond_get (const char *name);
|
|||||||
enum cond_state cond_get_agg (const char *names);
|
enum cond_state cond_get_agg (const char *names);
|
||||||
int cond_affects (const char *name, const char *names);
|
int cond_affects (const char *name, const char *names);
|
||||||
|
|
||||||
|
void cond_boot_parse (char *arg);
|
||||||
int cond_update (const char *name);
|
int cond_update (const char *name);
|
||||||
int cond_set_path (const char *path, enum cond_state new);
|
int cond_set_path (const char *path, enum cond_state new);
|
||||||
void cond_set (const char *name);
|
void cond_set (const char *name);
|
||||||
@@ -38,14 +41,17 @@ void cond_set_oneshot (const char *name);
|
|||||||
void cond_clear (const char *name);
|
void cond_clear (const char *name);
|
||||||
void cond_reload (void);
|
void cond_reload (void);
|
||||||
|
|
||||||
int cond_set_noupdate (const char *name);
|
int cond_set_noupdate(const char *name);
|
||||||
int cond_set_oneshot_noupdate(const char *name);
|
int cond_set_oneshot_noupdate(const char *name);
|
||||||
int cond_clear_noupdate(const char *name);
|
int cond_clear_noupdate(const char *name);
|
||||||
|
|
||||||
void cond_reassert (const char *pat);
|
void cond_reassert (const char *pat);
|
||||||
void cond_deassert (const char *pat);
|
void cond_deassert (const char *pat);
|
||||||
|
|
||||||
|
int cond_is_available(void);
|
||||||
|
|
||||||
void cond_init (void);
|
void cond_init (void);
|
||||||
|
void cond_exit (void);
|
||||||
|
|
||||||
#endif /* FINIT_COND_H_ */
|
#endif /* FINIT_COND_H_ */
|
||||||
|
|
||||||
|
|||||||
+381
-93
@@ -1,6 +1,6 @@
|
|||||||
/* Parser for /etc/finit.conf and /etc/finit.d/<SVC>.conf
|
/* Parser for /etc/finit.conf and /etc/finit.d/<SVC>.conf
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -40,6 +40,7 @@
|
|||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
|
#include "devmon.h"
|
||||||
#include "iwatch.h"
|
#include "iwatch.h"
|
||||||
#include "private.h"
|
#include "private.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
@@ -47,9 +48,7 @@
|
|||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#define BOOTSTRAP (runlevel == 0)
|
#define BOOTSTRAP (runlevel == INIT_LEVEL)
|
||||||
#define MATCH_CMD(l, c, x) \
|
|
||||||
(!strncasecmp(l, c, strlen(c)) && (x = (l) + strlen(c)))
|
|
||||||
|
|
||||||
int logfile_size_max = 200000; /* 200 kB */
|
int logfile_size_max = 200000; /* 200 kB */
|
||||||
int logfile_count_max = 5;
|
int logfile_count_max = 5;
|
||||||
@@ -63,6 +62,9 @@ static TAILQ_HEAD(, env_entry) env_list = TAILQ_HEAD_INITIALIZER(env_list);
|
|||||||
struct rlimit initial_rlimit[RLIMIT_NLIMITS];
|
struct rlimit initial_rlimit[RLIMIT_NLIMITS];
|
||||||
struct rlimit global_rlimit[RLIMIT_NLIMITS];
|
struct rlimit global_rlimit[RLIMIT_NLIMITS];
|
||||||
|
|
||||||
|
char *fsck_mode = "";
|
||||||
|
char *fsck_repair = "-p";
|
||||||
|
|
||||||
char cgroup_current[16]; /* cgroup.NAME sets current cgroup for a set of services */
|
char cgroup_current[16]; /* cgroup.NAME sets current cgroup for a set of services */
|
||||||
|
|
||||||
struct conf_change {
|
struct conf_change {
|
||||||
@@ -71,14 +73,18 @@ struct conf_change {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static struct iwatch iw_conf;
|
static struct iwatch iw_conf;
|
||||||
|
static int iwatch_fd;
|
||||||
static uev_t etcw;
|
static uev_t etcw;
|
||||||
|
|
||||||
static TAILQ_HEAD(, conf_change) conf_change_list = TAILQ_HEAD_INITIALIZER(conf_change_list);
|
static TAILQ_HEAD(, conf_change) conf_change_list = TAILQ_HEAD_INITIALIZER(conf_change_list);
|
||||||
|
|
||||||
|
static char *path;
|
||||||
|
static char *shell;
|
||||||
|
|
||||||
static int parse_conf(char *file, int is_rcsd);
|
static int parse_conf(char *file, int is_rcsd);
|
||||||
static void drop_changes(void);
|
static void drop_changes(void);
|
||||||
|
|
||||||
int get_bool(char *arg, int default_value)
|
static int get_bool(char *arg, int default_value)
|
||||||
{
|
{
|
||||||
if (!arg)
|
if (!arg)
|
||||||
goto fallback;
|
goto fallback;
|
||||||
@@ -91,7 +97,19 @@ fallback:
|
|||||||
return default_value;
|
return default_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int validate_arg(char *arg, const char *opt)
|
||||||
|
{
|
||||||
|
if (!arg) {
|
||||||
|
errx(1, "option %s missing argument, skipping.", opt);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* finit.cond = foo (=> <boot/foo>)
|
||||||
|
* finit.config = /path/to/etc/alt-finit.conf
|
||||||
* finit.debug = [on,off]
|
* finit.debug = [on,off]
|
||||||
* finit.fstab = /path/to/etc/fstab.aternative
|
* finit.fstab = /path/to/etc/fstab.aternative
|
||||||
* finit.status = [on,off] (compat finit.show_status)
|
* finit.status = [on,off] (compat finit.show_status)
|
||||||
@@ -105,21 +123,39 @@ static void parse_finit_opts(char *opt)
|
|||||||
if (arg)
|
if (arg)
|
||||||
*arg++ = 0;
|
*arg++ = 0;
|
||||||
|
|
||||||
|
if (string_compare(opt, "cond")) {
|
||||||
|
if (validate_arg(arg, "finit.cond"))
|
||||||
|
return;
|
||||||
|
cond_boot_parse(arg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string_compare(opt, "config")) {
|
||||||
|
if (validate_arg(arg, "finit.config"))
|
||||||
|
return;
|
||||||
|
if (finit_conf)
|
||||||
|
free(finit_conf);
|
||||||
|
finit_conf = strdup(arg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (string_compare(opt, "debug")) {
|
if (string_compare(opt, "debug")) {
|
||||||
debug = get_bool(arg, 1);
|
debug = get_bool(arg, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string_compare(opt, "fstab")) {
|
if (string_compare(opt, "fstab")) {
|
||||||
fstab = arg;
|
if (validate_arg(arg, "finit.fstab"))
|
||||||
|
return;
|
||||||
|
if (fstab)
|
||||||
|
free(fstab);
|
||||||
|
fstab = strdup(arg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string_compare(opt, "status_style")) {
|
if (string_compare(opt, "status_style")) {
|
||||||
if (!arg) {
|
if (validate_arg(arg, "finit.status_style"))
|
||||||
_e("status_style option requires an argument, skipping.");
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (string_compare(arg, "old") || string_compare(arg, "classic"))
|
if (string_compare(arg, "old") || string_compare(arg, "classic"))
|
||||||
show_progress(PROGRESS_CLASSIC);
|
show_progress(PROGRESS_CLASSIC);
|
||||||
@@ -134,6 +170,43 @@ static void parse_finit_opts(char *opt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void parse_fsck_opts(char *opt)
|
||||||
|
{
|
||||||
|
char *arg;
|
||||||
|
|
||||||
|
arg = strchr(opt, '=');
|
||||||
|
if (arg)
|
||||||
|
*arg++ = 0;
|
||||||
|
|
||||||
|
if (string_compare(opt, "mode")) {
|
||||||
|
if (validate_arg(arg, "fsck.mode"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!strcmp(arg, "skip"))
|
||||||
|
fsck_mode = NULL;
|
||||||
|
if (!strcmp(arg, "auto"))
|
||||||
|
fsck_mode = "";
|
||||||
|
if (!strcmp(arg, "force"))
|
||||||
|
fsck_mode = "-f";
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string_compare(opt, "repair")) {
|
||||||
|
if (validate_arg(arg, "fsck.repair"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!strcmp(arg, "no"))
|
||||||
|
fsck_repair = "-n";
|
||||||
|
if (!strcmp(arg, "preen"))
|
||||||
|
fsck_repair = "-p";
|
||||||
|
if (!strcmp(arg, "yes"))
|
||||||
|
fsck_repair = "-y";
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When runlevel (single integer) is given on the command line,
|
* When runlevel (single integer) is given on the command line,
|
||||||
* it overrides the runlevel in finit.conf and the built-in
|
* it overrides the runlevel in finit.conf and the built-in
|
||||||
@@ -154,7 +227,7 @@ static int parse_runlevel(char *arg)
|
|||||||
|
|
||||||
num = strtonum(arg, 1, 9, &err);
|
num = strtonum(arg, 1, 9, &err);
|
||||||
if (err || num == 6) {
|
if (err || num == 6) {
|
||||||
_d("Not a valid runlevel (%s), valid levels are [1-9], excluding 6, skipping.", arg);
|
dbg("Not a valid runlevel (%s), valid levels are [1-9], excluding 6, skipping.", arg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,6 +241,11 @@ static void parse_arg(char *arg)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!strncmp(arg, "fsck.", 5)) {
|
||||||
|
parse_fsck_opts(&arg[5]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (string_compare(arg, "rescue") || string_compare(arg, "recover")) {
|
if (string_compare(arg, "rescue") || string_compare(arg, "recover")) {
|
||||||
rescue = 1;
|
rescue = 1;
|
||||||
return;
|
return;
|
||||||
@@ -207,7 +285,7 @@ static void parse_kernel_cmdline(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cmdline = chomp(line);
|
cmdline = chomp(line);
|
||||||
_d("%s", cmdline);
|
dbg("%s", cmdline);
|
||||||
|
|
||||||
while ((tok = strtok(cmdline, " \t"))) {
|
while ((tok = strtok(cmdline, " \t"))) {
|
||||||
cmdline = NULL;
|
cmdline = NULL;
|
||||||
@@ -236,7 +314,7 @@ static void parse_kernel_loglevel(void)
|
|||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
ptr = chomp(line);
|
ptr = chomp(line);
|
||||||
_d("%s", ptr);
|
dbg("%s", ptr);
|
||||||
val = atoi(ptr);
|
val = atoi(ptr);
|
||||||
if (val >= 7)
|
if (val >= 7)
|
||||||
kerndebug = 1;
|
kerndebug = 1;
|
||||||
@@ -247,6 +325,13 @@ static void parse_kernel_loglevel(void)
|
|||||||
*/
|
*/
|
||||||
void conf_parse_cmdline(int argc, char *argv[])
|
void conf_parse_cmdline(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
/* Set up defaults */
|
||||||
|
fstab = strdup(FINIT_FSTAB);
|
||||||
|
finit_conf = strdup(FINIT_CONF);
|
||||||
|
finit_rcsd = strdup(FINIT_RCSD);
|
||||||
|
path = getenv("PATH");
|
||||||
|
shell = getenv("SHELL");
|
||||||
|
|
||||||
for (int i = 1; i < argc; i++)
|
for (int i = 1; i < argc; i++)
|
||||||
parse_arg(argv[i]);
|
parse_arg(argv[i]);
|
||||||
|
|
||||||
@@ -271,12 +356,41 @@ void conf_reset_env(void)
|
|||||||
free(node);
|
free(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
setenv("PATH", _PATH_STDPATH, 1);
|
if (path)
|
||||||
setenv("SHELL", _PATH_BSHELL, 1);
|
setenv("PATH", path, 1);
|
||||||
|
else
|
||||||
|
setenv("PATH", _PATH_STDPATH, 1);
|
||||||
|
if (shell)
|
||||||
|
setenv("SHELL", shell, 1);
|
||||||
|
else
|
||||||
|
setenv("SHELL", _PATH_BSHELL, 1);
|
||||||
setenv("LOGNAME", "root", 1);
|
setenv("LOGNAME", "root", 1);
|
||||||
setenv("USER", "root", 1);
|
setenv("USER", "root", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sourced mainly by initctl and other Finit helper tools
|
||||||
|
*/
|
||||||
|
void conf_saverc(void)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
mkpath(_PATH_VARRUN "finit", 0755);
|
||||||
|
fp = fopen(_PATH_VARRUN "finit/.initrc", "w");
|
||||||
|
if (!fp) {
|
||||||
|
err(1, "failed creating .finitrc");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(fp, "FINIT_CONF=%s\n", finit_conf);
|
||||||
|
fprintf(fp, "FINIT_RCSD=%s\n", finit_rcsd);
|
||||||
|
fprintf(fp, "FINIT_CGPATH=%s\n", FINIT_CGPATH);
|
||||||
|
fprintf(fp, "INIT_SOCKET=%s\n", INIT_SOCKET);
|
||||||
|
fprintf(fp, "INIT_MAGIC=0x%08x\n", INIT_MAGIC);
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sets, and makes a note of, all KEY=VALUE lines in a given .conf line
|
* 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
|
* from finit.conf, or other .conf file. Note, PATH is always reset in
|
||||||
@@ -339,7 +453,7 @@ static void parse_env(char *line)
|
|||||||
|
|
||||||
node = malloc(sizeof(*node));
|
node = malloc(sizeof(*node));
|
||||||
if (!node) {
|
if (!node) {
|
||||||
_pe("Out of memory cannot track env vars");
|
err(1, "Out of memory cannot track env vars");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
node->name = strdup(key);
|
node->name = strdup(key);
|
||||||
@@ -372,7 +486,7 @@ static void kmod_load(char *mod)
|
|||||||
char module[64] = { 0 };
|
char module[64] = { 0 };
|
||||||
char cmd[CMD_SIZE];
|
char cmd[CMD_SIZE];
|
||||||
|
|
||||||
if (runlevel != 0)
|
if (runlevel != INIT_LEVEL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Strip args for progress below and kmod_exists() */
|
/* Strip args for progress below and kmod_exists() */
|
||||||
@@ -405,15 +519,16 @@ int conf_parse_runlevels(char *runlevels)
|
|||||||
break;
|
break;
|
||||||
if ('!' == lvl) {
|
if ('!' == lvl) {
|
||||||
not = 1;
|
not = 1;
|
||||||
bitmask = 0x3FE;
|
bitmask = 0x7FE;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('s' == lvl || 'S' == lvl)
|
if ('s' == lvl || 'S' == lvl)
|
||||||
lvl = '0';
|
level = INIT_LEVEL;
|
||||||
|
else
|
||||||
|
level = lvl - '0';
|
||||||
|
|
||||||
level = lvl - '0';
|
if (level > INIT_LEVEL || level < 0)
|
||||||
if (level > 9 || level < 0)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (not)
|
if (not)
|
||||||
@@ -429,9 +544,10 @@ void conf_parse_cond(svc_t *svc, char *cond)
|
|||||||
{
|
{
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
char *ptr;
|
char *ptr;
|
||||||
|
char *c;
|
||||||
|
|
||||||
if (!svc) {
|
if (!svc) {
|
||||||
_e("Invalid service pointer");
|
errx(1, "Invalid service pointer");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -439,8 +555,10 @@ void conf_parse_cond(svc_t *svc, char *cond)
|
|||||||
if (svc_is_daemon(svc))
|
if (svc_is_daemon(svc))
|
||||||
svc->sighup = 1;
|
svc->sighup = 1;
|
||||||
|
|
||||||
if (!cond)
|
if (!cond) {
|
||||||
|
memset(svc->cond, 0, sizeof(svc->cond));
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* First character must be '!' if SIGHUP is not supported. */
|
/* First character must be '!' if SIGHUP is not supported. */
|
||||||
ptr = cond;
|
ptr = cond;
|
||||||
@@ -454,16 +572,17 @@ void conf_parse_cond(svc_t *svc, char *cond)
|
|||||||
ptr[i] = 0;
|
ptr[i] = 0;
|
||||||
|
|
||||||
if (i >= sizeof(svc->cond)) {
|
if (i >= sizeof(svc->cond)) {
|
||||||
logit(LOG_WARNING, "Too long event list in declaration of %s: %s", svc_ident(svc, NULL, 0), ptr);
|
logit(LOG_WARNING, "%s: too long list of conditions: %s", svc_ident(svc, NULL, 0), ptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strncmp(ptr, "svc/", 4)) {
|
svc->cond[0] = 0;
|
||||||
logit(LOG_ERR, "Unsupported cond syntax for %s: <%s", svc_ident(svc, NULL, 0), ptr);
|
for (i = 0, c = strtok(ptr, ","); c; c = strtok(NULL, ","), i++) {
|
||||||
return;
|
devmon_add_cond(c);
|
||||||
|
if (i)
|
||||||
|
strlcat(svc->cond, ",", sizeof(svc->cond));
|
||||||
|
strlcat(svc->cond, c, sizeof(svc->cond));
|
||||||
}
|
}
|
||||||
|
|
||||||
strlcpy(svc->cond, ptr, sizeof(svc->cond));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct rlimit_name {
|
struct rlimit_name {
|
||||||
@@ -649,18 +768,29 @@ static int parse_static(char *line, int is_rcsd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (BOOTSTRAP && MATCH_CMD(line, "rcsd ", x)) {
|
||||||
|
if (finit_rcsd) free(finit_rcsd);
|
||||||
|
finit_rcsd = strdup(strip_line(x));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (BOOTSTRAP && MATCH_CMD(line, "runparts ", x)) {
|
if (BOOTSTRAP && MATCH_CMD(line, "runparts ", x)) {
|
||||||
if (runparts) free(runparts);
|
if (runparts) free(runparts);
|
||||||
runparts = strdup(strip_line(x));
|
runparts = strdup(strip_line(x));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (BOOTSTRAP && MATCH_CMD(line, "set ", x)) {
|
||||||
|
parse_env(x);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (MATCH_CMD(line, "include ", x)) {
|
if (MATCH_CMD(line, "include ", x)) {
|
||||||
char *file = strip_line(x);
|
char *file = strip_line(x);
|
||||||
|
|
||||||
strlcpy(cmd, file, sizeof(cmd));
|
strlcpy(cmd, file, sizeof(cmd));
|
||||||
if (!fexist(cmd)) {
|
if (!fexist(cmd)) {
|
||||||
_e("Cannot find include file %s, absolute path required!", x);
|
errx(1, "Cannot find include file %s, absolute path required!", x);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -712,6 +842,11 @@ static int parse_static(char *line, int is_rcsd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (MATCH_CMD(line, "reboot-delay ", x)) {
|
||||||
|
syncsec = strtonum(strip_line(x), 0, 60, NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Periodic check and instability index leveler, seconds
|
* Periodic check and instability index leveler, seconds
|
||||||
*/
|
*/
|
||||||
@@ -790,12 +925,79 @@ static int parse_dynamic(char *line, struct rlimit rlimit[], char *file)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Very simple and crude implementation, only supports '%i'
|
||||||
|
*/
|
||||||
|
static char *instantiate(char *line, char *name)
|
||||||
|
{
|
||||||
|
char *ptr, *end = strchr(line, 0);
|
||||||
|
char *pos = line;
|
||||||
|
size_t num = 0;
|
||||||
|
|
||||||
|
if (!name[0] || !end)
|
||||||
|
return line;
|
||||||
|
|
||||||
|
while ((ptr = strchr(pos, '%'))) {
|
||||||
|
num++;
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = realloc(line, strlen(line) + num * strlen(name) + 1);
|
||||||
|
if (!ptr)
|
||||||
|
return line;
|
||||||
|
|
||||||
|
pos = line = ptr;
|
||||||
|
while ((ptr = strchr(pos, '%'))) {
|
||||||
|
if (!strncmp(ptr, "%i", 2)) {
|
||||||
|
char *rest = &ptr[2];
|
||||||
|
char *next = ptr + strlen(name);
|
||||||
|
|
||||||
|
memmove(next, rest, strlen(rest) + 1);
|
||||||
|
memcpy(ptr, name, strlen(name));
|
||||||
|
|
||||||
|
pos += strlen(name);
|
||||||
|
} else
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int is_template(const char *file, char *name, size_t len)
|
||||||
|
{
|
||||||
|
char *ptr, *nm;
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
ptr = strchr(file, '@');
|
||||||
|
if (!ptr)
|
||||||
|
return 0; /* not a template */
|
||||||
|
|
||||||
|
nm = ptr + 1;
|
||||||
|
ptr = strstr(nm, ".conf");
|
||||||
|
if (!strcmp(nm, ".conf") || !ptr)
|
||||||
|
return 1; /* template itself or invalid */
|
||||||
|
|
||||||
|
while (nm < ptr && i < len - 1)
|
||||||
|
name[i++] = *nm++;
|
||||||
|
name[i] = 0;
|
||||||
|
|
||||||
|
return 1; /* instantiated template */
|
||||||
|
}
|
||||||
|
|
||||||
static int parse_conf(char *file, int is_rcsd)
|
static int parse_conf(char *file, int is_rcsd)
|
||||||
{
|
{
|
||||||
struct rlimit rlimit[RLIMIT_NLIMITS];
|
struct rlimit rlimit[RLIMIT_NLIMITS];
|
||||||
char line[LINE_SIZE] = "";
|
char name[65] = { 0 };
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
|
if (is_template(file, name, sizeof(name))) {
|
||||||
|
if (!name[0]) {
|
||||||
|
dbg("*** Skipping template file %s", file);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
dbg("*** instantiating %s from %s ...", name, file);
|
||||||
|
}
|
||||||
|
|
||||||
fp = fopen(file, "r");
|
fp = fopen(file, "r");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return 1;
|
return 1;
|
||||||
@@ -806,28 +1008,27 @@ static int parse_conf(char *file, int is_rcsd)
|
|||||||
cgroup_current[0] = 0;
|
cgroup_current[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("*** Parsing %s", file);
|
dbg("*** Parsing %s", file);
|
||||||
while (!feof(fp)) {
|
while (!feof(fp)) {
|
||||||
char *x;
|
char *line;
|
||||||
|
|
||||||
if (!fgets(line, sizeof(line), fp))
|
line = fparseln(fp, NULL, NULL, NULL, FPARSELN_UNESCCOMM);
|
||||||
|
if (!line)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
chomp(line);
|
|
||||||
tabstospaces(line);
|
tabstospaces(line);
|
||||||
//DEV _d("%s", line);
|
// dbg("raw: %s", line);
|
||||||
|
line = instantiate(line, name);
|
||||||
/* Skip comments, i.e. lines beginning with # */
|
// dbg("ins: %s", line);
|
||||||
if (MATCH_CMD(line, "#", x))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!parse_static(line, is_rcsd))
|
if (!parse_static(line, is_rcsd))
|
||||||
continue;
|
;
|
||||||
if (!parse_dynamic(line, is_rcsd ? rlimit : global_rlimit, file))
|
else if (!parse_dynamic(line, is_rcsd ? rlimit : global_rlimit, file))
|
||||||
continue;
|
;
|
||||||
|
else
|
||||||
|
parse_env(line);
|
||||||
|
|
||||||
/* Not static or dynamic conf, check if it is a global env. */
|
free(line);
|
||||||
parse_env(line);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
@@ -835,17 +1036,41 @@ static int parse_conf(char *file, int is_rcsd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void glob_append(glob_t *gl, int append, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
size_t len;
|
||||||
|
char *path;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
len = vsnprintf(NULL, 0, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
path = alloca(++len);
|
||||||
|
if (!path) {
|
||||||
|
warn("failed alloca() in glob_append()");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vsnprintf(path, len, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
dbg("conf_reload(): glob %s ...", path);
|
||||||
|
glob(path, append ? GLOB_APPEND : 0, NULL, gl);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reload /etc/finit.conf and all *.conf in /etc/finit.d/
|
* Reload /etc/finit.conf and all *.conf in /etc/finit.d/
|
||||||
*/
|
*/
|
||||||
int conf_reload(void)
|
int conf_reload(void)
|
||||||
{
|
{
|
||||||
size_t i;
|
|
||||||
glob_t gl;
|
glob_t gl;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
/* Set time according to current time zone */
|
/* Set time according to current time zone */
|
||||||
tzset();
|
tzset();
|
||||||
_d("Set time daylight: %d timezone: %ld tzname: %s %s",
|
dbg("Set time daylight: %d timezone: %ld tzname: %s %s",
|
||||||
daylight, timezone, tzname[0], tzname[1]);
|
daylight, timezone, tzname[0], tzname[1]);
|
||||||
|
|
||||||
/* Mark and sweep */
|
/* Mark and sweep */
|
||||||
@@ -860,7 +1085,7 @@ int conf_reload(void)
|
|||||||
|
|
||||||
if (rescue) {
|
if (rescue) {
|
||||||
int rc;
|
int rc;
|
||||||
char line[80] = "tty [12345] rescue";
|
char line[80] = "tty [12345789] rescue";
|
||||||
|
|
||||||
/* If rescue.conf is missing, fall back to a root shell */
|
/* If rescue.conf is missing, fall back to a root shell */
|
||||||
rc = parse_conf(RESCUE_CONF, 0);
|
rc = parse_conf(RESCUE_CONF, 0);
|
||||||
@@ -872,7 +1097,7 @@ int conf_reload(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* First, read /etc/finit.conf */
|
/* First, read /etc/finit.conf */
|
||||||
parse_conf(FINIT_CONF, 0);
|
parse_conf(finit_conf, 0);
|
||||||
|
|
||||||
/* Set global limits */
|
/* Set global limits */
|
||||||
for (int i = 0; i < RLIMIT_NLIMITS; i++) {
|
for (int i = 0; i < RLIMIT_NLIMITS; i++) {
|
||||||
@@ -881,25 +1106,45 @@ int conf_reload(void)
|
|||||||
rlim2str(i), lim2str(&global_rlimit[i]));
|
rlim2str(i), lim2str(&global_rlimit[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Next, read all *.conf in /etc/finit.d/ */
|
/*
|
||||||
glob(FINIT_RCSD "/*.conf", 0, NULL, &gl);
|
* Next, read all *.conf in /lib/finit/system and /etc/finit.d/
|
||||||
glob(FINIT_RCSD "/enabled/*.conf", GLOB_APPEND, NULL, &gl);
|
* The system files were previously created at runtime by plugins
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
glob_append(&gl, 0, "%s/*.conf", finit_rcsd);
|
||||||
|
glob_append(&gl, 1, "%s/*.conf", FINIT_SYSPATH);
|
||||||
|
glob_append(&gl, 1, "%s/enabled/*.conf", finit_rcsd);
|
||||||
|
|
||||||
for (i = 0; i < gl.gl_pathc; i++) {
|
for (i = 0; i < gl.gl_pathc; i++) {
|
||||||
char *path = gl.gl_pathv[i];
|
char *path = gl.gl_pathv[i];
|
||||||
char *rp = NULL;
|
char *rp = NULL;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
size_t len;
|
size_t j, len;
|
||||||
|
|
||||||
|
/* check for FINIT_SYSPATH overrides */
|
||||||
|
for (j = i + 1; j < gl.gl_pathc; j++) {
|
||||||
|
if (strncmp(path, FINIT_SYSPATH, strlen(FINIT_SYSPATH)))
|
||||||
|
continue;
|
||||||
|
if (strcmp(basename(path), basename(gl.gl_pathv[j])))
|
||||||
|
continue;
|
||||||
|
path = NULL; /* replacement later in list, skip this */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!path)
|
||||||
|
continue; /* skip, override exists */
|
||||||
|
|
||||||
/* Check that it's an actual file ... beyond any symlinks */
|
/* Check that it's an actual file ... beyond any symlinks */
|
||||||
if (lstat(path, &st)) {
|
if (lstat(path, &st)) {
|
||||||
_d("Skipping %s, cannot access: %s", path, strerror(errno));
|
dbg("Skipping %s, cannot access: %s", path, strerror(errno));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Skip directories */
|
/* Skip directories */
|
||||||
if (S_ISDIR(st.st_mode)) {
|
if (S_ISDIR(st.st_mode)) {
|
||||||
_d("Skipping directory %s", path);
|
dbg("Skipping directory %s", path);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -915,7 +1160,7 @@ int conf_reload(void)
|
|||||||
/* Check that file ends with '.conf' */
|
/* Check that file ends with '.conf' */
|
||||||
len = strlen(path);
|
len = strlen(path);
|
||||||
if (len < 6 || strcmp(&path[len - 5], ".conf"))
|
if (len < 6 || strcmp(&path[len - 5], ".conf"))
|
||||||
_d("Skipping %s, not a Finit .conf file ... ", path);
|
dbg("Skipping %s, not a Finit .conf file ... ", path);
|
||||||
else
|
else
|
||||||
parse_conf(path, 1);
|
parse_conf(path, 1);
|
||||||
|
|
||||||
@@ -928,6 +1173,9 @@ int conf_reload(void)
|
|||||||
/* Mark any reverse deps as chenaged. */
|
/* Mark any reverse deps as chenaged. */
|
||||||
service_update_rdeps();
|
service_update_rdeps();
|
||||||
|
|
||||||
|
/* Prune according to if:[!]ident or if:<[!]cond> */
|
||||||
|
service_mark_unavail();
|
||||||
|
|
||||||
/* Set up top-level cgroups */
|
/* Set up top-level cgroups */
|
||||||
cgroup_config();
|
cgroup_config();
|
||||||
done:
|
done:
|
||||||
@@ -981,39 +1229,45 @@ static void drop_changes(void)
|
|||||||
drop_change(node);
|
drop_change(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_change(char *dir, char *name, uint32_t mask)
|
static int conf_change_act(char *dir, char *name, uint32_t mask)
|
||||||
{
|
{
|
||||||
char fn[strlen(dir) + strlen(name) + 2];
|
char fn[strlen(dir) + strlen(name) + 2];
|
||||||
struct conf_change *node;
|
struct conf_change *node;
|
||||||
|
char *rp = NULL;
|
||||||
|
|
||||||
paste(fn, sizeof(fn), dir, name);
|
paste(fn, sizeof(fn), dir, name);
|
||||||
_d("path: %s mask: %08x", fn, mask);
|
dbg("path: %s mask: %08x", fn, mask);
|
||||||
|
|
||||||
node = conf_find(fn);
|
/* Handle disabling/removal of service */
|
||||||
if (mask & (IN_DELETE | IN_MOVED_FROM)) {
|
rp = realpath(fn, NULL);
|
||||||
drop_change(node);
|
if (!rp) {
|
||||||
return 0;
|
if (errno != ENOENT)
|
||||||
|
goto fail;
|
||||||
|
rp = strdup(fn);
|
||||||
|
if (!rp)
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node = conf_find(rp);
|
||||||
if (node) {
|
if (node) {
|
||||||
_d("Event already registered for %s ...", name);
|
dbg("event already registered for %s ...", name);
|
||||||
|
free(rp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
node = malloc(sizeof(*node));
|
node = malloc(sizeof(*node));
|
||||||
if (!node)
|
if (!node) {
|
||||||
return 1;
|
free(rp);
|
||||||
|
goto fail;
|
||||||
node->name = strdup(fn);
|
|
||||||
if (!node->name) {
|
|
||||||
free(node);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("Event registered for %s, mask 0x%x", fn, mask);
|
node->name = rp;
|
||||||
TAILQ_INSERT_HEAD(&conf_change_list, node, link);
|
TAILQ_INSERT_HEAD(&conf_change_list, node, link);
|
||||||
|
dbg("event registered for %s, mask 0x%x", rp, mask);
|
||||||
return 0;
|
return 0;
|
||||||
|
fail:
|
||||||
|
warn("failed registering %s event", fn);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int conf_any_change(void)
|
int conf_any_change(void)
|
||||||
@@ -1043,18 +1297,16 @@ int conf_changed(char *file)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void conf_cb(uev_t *w, void *arg, int events)
|
static int conf_iwatch_read(int fd)
|
||||||
{
|
{
|
||||||
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
||||||
struct inotify_event *ev;
|
struct inotify_event *ev;
|
||||||
ssize_t sz;
|
ssize_t sz;
|
||||||
size_t off;
|
size_t off;
|
||||||
|
|
||||||
sz = read(w->fd, ev_buf, sizeof(ev_buf) - 1);
|
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
||||||
if (sz <= 0) {
|
if (sz <= 0)
|
||||||
_pe("invalid inotify event");
|
return -1;
|
||||||
return;
|
|
||||||
}
|
|
||||||
ev_buf[sz] = 0;
|
ev_buf[sz] = 0;
|
||||||
|
|
||||||
for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) {
|
for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) {
|
||||||
@@ -1070,30 +1322,48 @@ static void conf_cb(uev_t *w, void *arg, int events)
|
|||||||
if (!ev->mask)
|
if (!ev->mask)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_d("name %s, event: 0x%08x", ev->name, ev->mask);
|
dbg("name %s, event: 0x%08x", ev->name, ev->mask);
|
||||||
|
|
||||||
/* Find base path for this event */
|
/* Find base path for this event */
|
||||||
iwp = iwatch_find_by_wd(&iw_conf, ev->wd);
|
iwp = iwatch_find_by_wd(&iw_conf, ev->wd);
|
||||||
if (!iwp)
|
if (!iwp)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (do_change(iwp->path, ev->name, ev->mask)) {
|
if (conf_change_act(iwp->path, ev->name, ev->mask)) {
|
||||||
_pe(" Out of memory");
|
err(1, " Out of memory");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_AUTO_RELOAD
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void conf_cb(uev_t *w, void *arg, int events)
|
||||||
|
{
|
||||||
|
if (conf_iwatch_read(w->fd)) {
|
||||||
|
err(1, "invalid inotify event");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef AUTO_RELOAD
|
||||||
if (conf_any_change())
|
if (conf_any_change())
|
||||||
service_reload_dynamic();
|
service_reload_dynamic();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void conf_flush_events(void)
|
||||||
|
{
|
||||||
|
while (!conf_iwatch_read(iwatch_fd))
|
||||||
|
dbg("emptying inotify queue ...");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up inotify watcher and load all *.conf in /etc/finit.d/
|
* Set up inotify watcher and load all *.conf in /etc/finit.d/
|
||||||
*/
|
*/
|
||||||
int conf_monitor(void)
|
int conf_monitor(void)
|
||||||
{
|
{
|
||||||
|
char path[strlen(finit_rcsd) + 16];
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1102,10 +1372,12 @@ int conf_monitor(void)
|
|||||||
* have or not have symlinks in place. We need to monitor for
|
* have or not have symlinks in place. We need to monitor for
|
||||||
* changes to either symlink or target.
|
* changes to either symlink or target.
|
||||||
*/
|
*/
|
||||||
rc += iwatch_add(&iw_conf, FINIT_RCSD, IN_ONLYDIR);
|
rc += iwatch_add(&iw_conf, finit_rcsd, IN_ONLYDIR);
|
||||||
rc += iwatch_add(&iw_conf, FINIT_RCSD "/available/", IN_ONLYDIR | IN_DONT_FOLLOW);
|
snprintf(path, sizeof(path), "%s/available/", finit_rcsd);
|
||||||
rc += iwatch_add(&iw_conf, FINIT_RCSD "/enabled/", IN_ONLYDIR | IN_DONT_FOLLOW);
|
rc += iwatch_add(&iw_conf, path, IN_ONLYDIR | IN_DONT_FOLLOW);
|
||||||
rc += iwatch_add(&iw_conf, FINIT_CONF, 0);
|
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);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Systems with /etc/default, /etc/conf.d, or similar, can also
|
* Systems with /etc/default, /etc/conf.d, or similar, can also
|
||||||
@@ -1126,8 +1398,6 @@ int conf_monitor(void)
|
|||||||
*/
|
*/
|
||||||
int conf_init(uev_ctx_t *ctx)
|
int conf_init(uev_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
int fd;
|
|
||||||
|
|
||||||
/* default hostname */
|
/* default hostname */
|
||||||
hostname = strdup(DEFHOST);
|
hostname = strdup(DEFHOST);
|
||||||
|
|
||||||
@@ -1145,17 +1415,35 @@ int conf_init(uev_ctx_t *ctx)
|
|||||||
/* Initialize global rlimits, e.g. for built-in services */
|
/* Initialize global rlimits, e.g. for built-in services */
|
||||||
memcpy(global_rlimit, initial_rlimit, sizeof(global_rlimit));
|
memcpy(global_rlimit, initial_rlimit, sizeof(global_rlimit));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start built-in watchdogd as soon as possible, if enabled
|
||||||
|
*/
|
||||||
|
#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");
|
||||||
|
}
|
||||||
|
#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);
|
||||||
|
|
||||||
|
dbg("Allow plugins to register early runlevel 1 run/task/services ...");
|
||||||
|
plugin_run_hooks(HOOK_SVC_PLUGIN);
|
||||||
|
|
||||||
/* Read global rlimits and global cgroup setup from /etc/finit.conf */
|
/* Read global rlimits and global cgroup setup from /etc/finit.conf */
|
||||||
parse_conf(FINIT_CONF, 0);
|
parse_conf(finit_conf, 0);
|
||||||
|
|
||||||
/* prepare /etc watcher */
|
/* prepare /etc watcher */
|
||||||
fd = iwatch_init(&iw_conf);
|
iwatch_fd = iwatch_init(&iw_conf);
|
||||||
if (fd < 0)
|
if (iwatch_fd < 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (uev_io_init(ctx, &etcw, conf_cb, NULL, fd, UEV_READ)) {
|
if (uev_io_init(ctx, &etcw, conf_cb, NULL, iwatch_fd, UEV_READ)) {
|
||||||
_pe("Failed setting up I/O callback for /etc watcher");
|
err(1, "Failed setting up I/O callback for /etc watcher");
|
||||||
close(fd);
|
close(iwatch_fd);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -1,6 +1,6 @@
|
|||||||
/* Parser for /etc/finit.conf and /etc/finit.d/<SVC>.conf
|
/* Parser for /etc/finit.conf and /etc/finit.d/<SVC>.conf
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -43,6 +43,7 @@ int conf_changed (char *file);
|
|||||||
int conf_monitor (void);
|
int conf_monitor (void);
|
||||||
|
|
||||||
void conf_reset_env (void);
|
void conf_reset_env (void);
|
||||||
|
void conf_saverc (void);
|
||||||
void conf_parse_cmdline (int argc, char *argv[]);
|
void conf_parse_cmdline (int argc, char *argv[]);
|
||||||
int conf_parse_runlevels (char *runlevels);
|
int conf_parse_runlevels (char *runlevels);
|
||||||
void conf_parse_cond (svc_t *svc, char *cond);
|
void conf_parse_cond (svc_t *svc, char *cond);
|
||||||
|
|||||||
+275
@@ -0,0 +1,275 @@
|
|||||||
|
/* Device node monitor for the Finit condition engine
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fnmatch.h>
|
||||||
|
#include <glob.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <paths.h>
|
||||||
|
|
||||||
|
#include "finit.h"
|
||||||
|
#include "cond.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
#include "pid.h"
|
||||||
|
#include "plugin.h"
|
||||||
|
#include "service.h"
|
||||||
|
#include "iwatch.h"
|
||||||
|
|
||||||
|
static struct iwatch iw_devmon;
|
||||||
|
static uev_t devw;
|
||||||
|
static int fd;
|
||||||
|
|
||||||
|
struct dev_node {
|
||||||
|
TAILQ_ENTRY(dev_node) link;
|
||||||
|
char *name;
|
||||||
|
size_t refcnt;
|
||||||
|
};
|
||||||
|
|
||||||
|
static TAILQ_HEAD(, dev_node) dev_node_list = TAILQ_HEAD_INITIALIZER(dev_node_list);
|
||||||
|
|
||||||
|
static struct dev_node *find_node(const char *cond)
|
||||||
|
{
|
||||||
|
struct dev_node *node, *tmp;
|
||||||
|
|
||||||
|
TAILQ_FOREACH_SAFE(node, &dev_node_list, link, tmp) {
|
||||||
|
if (string_compare(node->name, cond))
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void drop_node(struct dev_node *node)
|
||||||
|
{
|
||||||
|
if (!node)
|
||||||
|
return;
|
||||||
|
|
||||||
|
node->refcnt--;
|
||||||
|
if (node->refcnt)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TAILQ_REMOVE(&dev_node_list, node, link);
|
||||||
|
free(node->name);
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void devmon_add_cond(const char *cond)
|
||||||
|
{
|
||||||
|
struct dev_node *node;
|
||||||
|
|
||||||
|
if (!cond || strncmp(cond, "dev/", 4)) {
|
||||||
|
dbg("no match");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dbg("%s", cond);
|
||||||
|
node = find_node(cond);
|
||||||
|
if (node) {
|
||||||
|
node->refcnt++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = malloc(sizeof(*node));
|
||||||
|
if (!node) {
|
||||||
|
fail:
|
||||||
|
warn("failed allocating node %s", cond);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->name = strdup(cond);
|
||||||
|
if (!node->name) {
|
||||||
|
free(node);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
node->refcnt = 1;
|
||||||
|
|
||||||
|
TAILQ_INSERT_TAIL(&dev_node_list, node, link);
|
||||||
|
}
|
||||||
|
|
||||||
|
void devmon_del_cond(const char *cond)
|
||||||
|
{
|
||||||
|
if (!cond || strcmp(cond, "dev/"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
drop_node(find_node(cond));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int devmon_add_path(struct iwatch *iw, char *path)
|
||||||
|
{
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
ptr = strstr(path, "dev/");
|
||||||
|
if (ptr) {
|
||||||
|
char *slash;
|
||||||
|
|
||||||
|
ptr += 4;
|
||||||
|
slash = strchr(ptr, '/');
|
||||||
|
if (slash) {
|
||||||
|
ptr = slash++;
|
||||||
|
slash = strchr(ptr, '/');
|
||||||
|
if (slash) {
|
||||||
|
dbg("Path too deep, skipping.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return iwatch_add1(iw, path, IN_CREATE | IN_DELETE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void devmon_update_conds(char *dir, char *name, uint32_t mask)
|
||||||
|
{
|
||||||
|
char fn[PATH_MAX];
|
||||||
|
char *cond;
|
||||||
|
|
||||||
|
paste(fn, sizeof(fn), dir, name);
|
||||||
|
cond = &fn[1];
|
||||||
|
|
||||||
|
// dbg("path: %s, mask: %08x, cond: %s", fn, mask, cond);
|
||||||
|
if (!find_node(cond)) {
|
||||||
|
// dbg("unregistered, skipping %s", cond);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mask & IN_CREATE)
|
||||||
|
cond_set(cond);
|
||||||
|
else if (mask & IN_DELETE)
|
||||||
|
cond_clear(cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* synthesize events in case of new run dirs */
|
||||||
|
static void devmon_scandir(struct iwatch *iw, char *dir, int len)
|
||||||
|
{
|
||||||
|
char path[len + 6];
|
||||||
|
glob_t gl;
|
||||||
|
size_t i;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "%s/*", dir);
|
||||||
|
rc = glob(path, GLOB_NOSORT, NULL, &gl);
|
||||||
|
if (rc && rc != GLOB_NOMATCH)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < gl.gl_pathc; i++) {
|
||||||
|
// dbg("scan found %s", gl.gl_pathv[i]);
|
||||||
|
devmon_update_conds(dir, gl.gl_pathv[i], IN_CREATE);
|
||||||
|
}
|
||||||
|
globfree(&gl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* create/remove sub-directory in monitored directory
|
||||||
|
*/
|
||||||
|
static void devmon_handle_dir(struct iwatch *iw, char *dir, char *name, int mask)
|
||||||
|
{
|
||||||
|
char path[strlen(dir) + strlen(name) + 2];
|
||||||
|
struct iwatch_path *iwp;
|
||||||
|
|
||||||
|
paste(path, sizeof(path), dir, name);
|
||||||
|
dbg("path: %s", path);
|
||||||
|
|
||||||
|
iwp = iwatch_find_by_path(iw, path);
|
||||||
|
|
||||||
|
if (mask & IN_CREATE) {
|
||||||
|
if (!iwp) {
|
||||||
|
if (!devmon_add_path(iw, path))
|
||||||
|
devmon_scandir(iw, path, sizeof(path));
|
||||||
|
}
|
||||||
|
} else if (mask & IN_DELETE) {
|
||||||
|
if (iwp)
|
||||||
|
iwatch_del(&iw_devmon, iwp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void devmon_cb(uev_t *w, void *arg, int events)
|
||||||
|
{
|
||||||
|
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
||||||
|
struct inotify_event *ev;
|
||||||
|
ssize_t sz;
|
||||||
|
size_t off;
|
||||||
|
|
||||||
|
sz = read(w->fd, ev_buf, sizeof(ev_buf) - 1);
|
||||||
|
if (sz <= 0) {
|
||||||
|
err(1, "invalid inotify event");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ev_buf[sz] = 0;
|
||||||
|
|
||||||
|
for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) {
|
||||||
|
struct iwatch_path *iwp;
|
||||||
|
|
||||||
|
if (off + sizeof(*ev) > (size_t)sz)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ev = (struct inotify_event *)&ev_buf[off];
|
||||||
|
if (off + sizeof(*ev) + ev->len > (size_t)sz)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!ev->mask)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Find base path for this event */
|
||||||
|
iwp = iwatch_find_by_wd(&iw_devmon, ev->wd);
|
||||||
|
if (!iwp)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ev->mask & IN_ISDIR) {
|
||||||
|
devmon_handle_dir(&iw_devmon, iwp->path, ev->name, ev->mask);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
char dir[MAX_ARG_LEN];
|
||||||
|
|
||||||
|
fd = iwatch_init(&iw_devmon);
|
||||||
|
if (fd < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mkpath(pid_runpath(_PATH_CONDDEV, dir, sizeof(dir)), 0755) && errno != EEXIST) {
|
||||||
|
err(1, "Failed creating %s condition directory, %s", COND_DEV, _PATH_CONDDEV);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uev_io_init(ctx, &devw, devmon_cb, NULL, fd, UEV_READ)) {
|
||||||
|
err(1, "Failed setting up I/O callback for /dev watcher");
|
||||||
|
close(fd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
strlcpy(dir, _PATH_DEV, sizeof(dir));
|
||||||
|
if (devmon_add_path(&iw_devmon, dir))
|
||||||
|
iwatch_exit(&iw_devmon);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Variables:
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/* Device node monitor for the Finit condition engine
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FINIT_DEVMON_H_
|
||||||
|
#define FINIT_DEVMON_H_
|
||||||
|
|
||||||
|
void devmon_add_cond(const char *cond);
|
||||||
|
void devmon_del_cond(const char *cond);
|
||||||
|
|
||||||
|
void devmon_init(void);
|
||||||
|
|
||||||
|
#endif /* FINIT_DEVMON_H_ */
|
||||||
+47
-24
@@ -1,7 +1,7 @@
|
|||||||
/* Functions for exec'ing processes
|
/* Functions for exec'ing processes
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||||
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -59,11 +59,11 @@ int complete(char *cmd, int pid)
|
|||||||
|
|
||||||
if (waitpid(pid, &status, 0) == -1) {
|
if (waitpid(pid, &status, 0) == -1) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
_e("Caught unblocked signal waiting for %s, aborting", cmd);
|
errx(1, "Caught unblocked signal waiting for %s, aborting", cmd);
|
||||||
else if (errno == ECHILD)
|
else if (errno == ECHILD)
|
||||||
_e("Caught SIGCHLD waiting for %s, aborting", cmd);
|
errx(1, "Caught SIGCHLD waiting for %s, aborting", cmd);
|
||||||
else
|
else
|
||||||
_e("Failed starting %s, error %d: %s", cmd, errno, strerror (errno));
|
errx(1, "Failed starting %s, error %d: %s", cmd, errno, strerror (errno));
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -131,7 +131,7 @@ int run(char *cmd, char *log)
|
|||||||
args[i] = NULL;
|
args[i] = NULL;
|
||||||
|
|
||||||
if (i == NUM_ARGS && arg) {
|
if (i == NUM_ARGS && arg) {
|
||||||
_e("Command too long: %s", cmd);
|
errx(1, "Command too long: %s", cmd);
|
||||||
free(backup);
|
free(backup);
|
||||||
errno = EOVERFLOW;
|
errno = EOVERFLOW;
|
||||||
return 1;
|
return 1;
|
||||||
@@ -166,7 +166,7 @@ int run(char *cmd, char *log)
|
|||||||
|
|
||||||
_exit(rc);
|
_exit(rc);
|
||||||
} else if (-1 == pid) {
|
} else if (-1 == pid) {
|
||||||
_pe("%s", !log ? args[0] : cmd);
|
err(1, "%s", !log ? args[0] : cmd);
|
||||||
if (backup)
|
if (backup)
|
||||||
free(backup);
|
free(backup);
|
||||||
|
|
||||||
@@ -182,9 +182,9 @@ int run(char *cmd, char *log)
|
|||||||
|
|
||||||
result = WEXITSTATUS(status);
|
result = WEXITSTATUS(status);
|
||||||
if (WIFEXITED(status)) {
|
if (WIFEXITED(status)) {
|
||||||
_d("Started '%s' and exit without signal, status: %d", cmd, result);
|
dbg("Started '%s' and exit without signal, status: %d", cmd, result);
|
||||||
} else if (WIFSIGNALED(status)) {
|
} else if (WIFSIGNALED(status)) {
|
||||||
_d("Process '%s' terminated by signal %d", cmd, WTERMSIG(status));
|
dbg("Process '%s' terminated by signal %d", cmd, WTERMSIG(status));
|
||||||
if (!result)
|
if (!result)
|
||||||
result = 1; /* Must alert callee that the command did complete successfully.
|
result = 1; /* Must alert callee that the command did complete successfully.
|
||||||
* This is necessary since not all programs trap signals and
|
* This is necessary since not all programs trap signals and
|
||||||
@@ -277,7 +277,7 @@ int exec_runtask(char *cmd, char *args[])
|
|||||||
strlcat(buf, args[i], sizeof(buf));
|
strlcat(buf, args[i], sizeof(buf));
|
||||||
}
|
}
|
||||||
logit(LOG_DEBUG, "Calling %s %s", _PATH_BSHELL, buf);
|
logit(LOG_DEBUG, "Calling %s %s", _PATH_BSHELL, buf);
|
||||||
_d("Calling %s %s", _PATH_BSHELL, buf);
|
dbg("Calling %s %s", _PATH_BSHELL, buf);
|
||||||
|
|
||||||
return execvp(_PATH_BSHELL, argv);
|
return execvp(_PATH_BSHELL, argv);
|
||||||
}
|
}
|
||||||
@@ -329,7 +329,7 @@ static int activate_console(int noclear, int nowait)
|
|||||||
static const char clr[] = "\r\e[K";
|
static const char clr[] = "\r\e[K";
|
||||||
static const char cup[] = "\e[A";
|
static const char cup[] = "\e[A";
|
||||||
struct termios orig;
|
struct termios orig;
|
||||||
char c;
|
char ch;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (nowait || rescue)
|
if (nowait || rescue)
|
||||||
@@ -351,7 +351,7 @@ static int activate_console(int noclear, int nowait)
|
|||||||
|
|
||||||
dprint(STDERR_FILENO, clr, strlen(clr));
|
dprint(STDERR_FILENO, clr, strlen(clr));
|
||||||
dprint(STDERR_FILENO, msg, strlen(msg));
|
dprint(STDERR_FILENO, msg, strlen(msg));
|
||||||
while ((rc = read(STDIN_FILENO, &c, 1)) > 0 && c != '\r' && c != '\n')
|
while ((rc = read(STDIN_FILENO, &ch, 1)) > 0 && ch != '\r' && ch != '\n')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* On any error (likely EINTR), we avoid starting getty */
|
/* On any error (likely EINTR), we avoid starting getty */
|
||||||
@@ -419,8 +419,10 @@ int sh(char *tty)
|
|||||||
/* Start /bin/sh as a login shell, i.e. with a prefix '-' */
|
/* Start /bin/sh as a login shell, i.e. with a prefix '-' */
|
||||||
len = strlen(_PATH_BSHELL) + 2;
|
len = strlen(_PATH_BSHELL) + 2;
|
||||||
arg0 = malloc(len);
|
arg0 = malloc(len);
|
||||||
if (!arg0)
|
if (!arg0) {
|
||||||
err(1, "Failed allocating memory");
|
err(1, "Failed allocating memory");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
snprintf(arg0, len, "-%s", _PATH_BSHELL);
|
snprintf(arg0, len, "-%s", _PATH_BSHELL);
|
||||||
args[0] = arg0;
|
args[0] = arg0;
|
||||||
|
|
||||||
@@ -441,14 +443,32 @@ pid_t run_sh(char *tty, int noclear, int nowait, struct rlimit rlimit[])
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int run_parts(char *dir, char *cmd)
|
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)
|
||||||
{
|
{
|
||||||
struct dirent **e;
|
struct dirent **e;
|
||||||
int i, num;
|
int i, num;
|
||||||
|
|
||||||
num = scandir(dir, &e, NULL, alphasort);
|
num = scandir(dir, &e, NULL, alphasort);
|
||||||
if (num < 0) {
|
if (num < 0) {
|
||||||
_d("No files found in %s, skipping ...", dir);
|
dbg("No files found in %s, skipping ...", dir);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,23 +484,23 @@ int run_parts(char *dir, char *cmd)
|
|||||||
};
|
};
|
||||||
pid_t pid = 0;
|
pid_t pid = 0;
|
||||||
int status;
|
int status;
|
||||||
int exit_status;
|
|
||||||
|
|
||||||
paste(path, sizeof(path), dir, name);
|
paste(path, sizeof(path), dir, name);
|
||||||
if (stat(path, &st)) {
|
if (stat(path, &st)) {
|
||||||
_d("Failed stat(%s): %s", path, strerror(errno));
|
dbg("Failed stat(%s): %s", path, strerror(errno));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!S_ISEXEC(st.st_mode) || S_ISDIR(st.st_mode)) {
|
if (!S_ISEXEC(st.st_mode) || S_ISDIR(st.st_mode)) {
|
||||||
_d("Skipping %s ...", path);
|
if (strcmp(name, ".") && strcmp(name, ".."))
|
||||||
|
dbg("Skipping %s ...", path);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the callee didn't supply a run_parts() argument */
|
/* If the callee didn't supply a run_parts() argument */
|
||||||
if (!cmd) {
|
if (!cmd) {
|
||||||
/* Check if S<NUM>service or K<NUM>service notation is used */
|
/* Check if S<NUM>service or K<NUM>service notation is used */
|
||||||
_d("Checking if %s is a sysvinit startstop script ...", name);
|
// dbg("Checking if %s is a sysvinit startstop script ...", name);
|
||||||
if (name[0] == 'S' && isdigit(name[1]))
|
if (name[0] == 'S' && isdigit(name[1]))
|
||||||
strlcat(path, " start", sizeof(path));
|
strlcat(path, " start", sizeof(path));
|
||||||
else if (name[0] == 'K' && isdigit(name[1]))
|
else if (name[0] == 'K' && isdigit(name[1]))
|
||||||
@@ -489,20 +509,23 @@ int run_parts(char *dir, char *cmd)
|
|||||||
strlcat(path, cmd, sizeof(path));
|
strlcat(path, cmd, sizeof(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
print_desc("Calling ", path);
|
if (progress)
|
||||||
|
print_desc("Calling ", path);
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
sig_unblock();
|
sig_unblock();
|
||||||
|
run_env(env);
|
||||||
|
|
||||||
return execvp(_PATH_BSHELL, argv);
|
return execvp(_PATH_BSHELL, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
status = complete(path, pid);
|
status = complete(path, pid);
|
||||||
exit_status = WEXITSTATUS(status);
|
if (WIFEXITED(status))
|
||||||
if (WIFEXITED(status) && exit_status)
|
warnx("%s exited with status %d", path, WEXITSTATUS(status));
|
||||||
_w("%s exited with status %d", path, exit_status);
|
|
||||||
else if (WIFSIGNALED(status))
|
else if (WIFSIGNALED(status))
|
||||||
_w("%s terminated by signad %d", path, WTERMSIG(status));
|
warnx("%s terminated by signad %d", path, WTERMSIG(status));
|
||||||
print_result(status);
|
if (progress)
|
||||||
|
print_result(WEXITSTATUS(status));
|
||||||
}
|
}
|
||||||
|
|
||||||
while (num--)
|
while (num--)
|
||||||
|
|||||||
+70
-65
@@ -1,7 +1,7 @@
|
|||||||
/* Finit - Fast /sbin/init replacement w/ I/O, hook & service plugins
|
/* Finit - Fast /sbin/init replacement w/ I/O, hook & service plugins
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||||
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -48,6 +48,7 @@
|
|||||||
#include "cgroup.h"
|
#include "cgroup.h"
|
||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
#include "devmon.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "private.h"
|
#include "private.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
@@ -58,9 +59,8 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "utmp-api.h"
|
#include "utmp-api.h"
|
||||||
#include "schedule.h"
|
#include "schedule.h"
|
||||||
#include "watchdog.h"
|
|
||||||
|
|
||||||
int runlevel = 0; /* Bootstrap 'S' */
|
int runlevel = INIT_LEVEL; /* Bootstrap 'S' */
|
||||||
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
|
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
|
||||||
int cmdlevel = 0; /* runlevel override from cmdline */
|
int cmdlevel = 0; /* runlevel override from cmdline */
|
||||||
int prevlevel = -1;
|
int prevlevel = -1;
|
||||||
@@ -69,11 +69,13 @@ int rescue = 0; /* rescue mode from kernel cmdline */
|
|||||||
int single = 0; /* single user mode from kernel cmdline */
|
int single = 0; /* single user mode from kernel cmdline */
|
||||||
int bootstrap = 1; /* set while bootrapping (for TTYs) */
|
int bootstrap = 1; /* set while bootrapping (for TTYs) */
|
||||||
int kerndebug = 0; /* set if /proc/sys/kernel/printk > 7 */
|
int kerndebug = 0; /* set if /proc/sys/kernel/printk > 7 */
|
||||||
char *fstab = FINIT_FSTAB;
|
int syncsec = 0; /* reboot delay */
|
||||||
|
char *finit_conf= NULL;
|
||||||
|
char *finit_rcsd= NULL;
|
||||||
|
char *fstab = NULL;
|
||||||
char *sdown = NULL;
|
char *sdown = NULL;
|
||||||
char *network = NULL;
|
char *network = NULL;
|
||||||
char *hostname = NULL;
|
char *hostname = NULL;
|
||||||
char *rcsd = FINIT_RCSD;
|
|
||||||
char *runparts = NULL;
|
char *runparts = NULL;
|
||||||
char *osheading = NULL;
|
char *osheading = NULL;
|
||||||
|
|
||||||
@@ -114,14 +116,17 @@ static int sulogin(int do_reboot)
|
|||||||
{
|
{
|
||||||
int rc = EX_OSFILE;
|
int rc = EX_OSFILE;
|
||||||
char *cmd[] = {
|
char *cmd[] = {
|
||||||
_PATH_SULOGIN,
|
|
||||||
"sulogin",
|
"sulogin",
|
||||||
|
_PATH_SULOGIN,
|
||||||
};
|
};
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < NELEMS(cmd); i++) {
|
for (i = 0; i < NELEMS(cmd); i++) {
|
||||||
char *path = which(cmd[i]);
|
char *path = which(cmd[i]);
|
||||||
|
|
||||||
|
if (!path)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (access(path, X_OK)) {
|
if (access(path, X_OK)) {
|
||||||
free(path);
|
free(path);
|
||||||
continue;
|
continue;
|
||||||
@@ -201,17 +206,17 @@ static int fsck(int pass)
|
|||||||
|
|
||||||
fp = setmntent(fstab, "r");
|
fp = setmntent(fstab, "r");
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
_pe("Failed opening fstab: %s", fstab);
|
err(1, "Failed opening fstab: %s", fstab);
|
||||||
sulogin(1);
|
sulogin(1);
|
||||||
}
|
}
|
||||||
_d("Opened %s, pass %d", fstab, pass);
|
dbg("Opened %s, pass %d", fstab, pass);
|
||||||
while ((mnt = getmntent_r(fp, &mount, buf, sizeof(buf)))) {
|
while ((mnt = getmntent_r(fp, &mount, buf, sizeof(buf)))) {
|
||||||
int fsck_rc = 0;
|
int fsck_rc = 0;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
char cmd[256];
|
char cmd[256];
|
||||||
char *dev;
|
char *dev;
|
||||||
|
|
||||||
_d("got: fsname '%s' dir '%s' type '%s' opts '%s' freq '%d' passno '%d'",
|
dbg("got: fsname '%s' dir '%s' type '%s' opts '%s' freq '%d' passno '%d'",
|
||||||
mnt->mnt_fsname, mnt->mnt_dir, mnt->mnt_type, mnt->mnt_opts,
|
mnt->mnt_fsname, mnt->mnt_dir, mnt->mnt_type, mnt->mnt_opts,
|
||||||
mnt->mnt_freq, mnt->mnt_passno);
|
mnt->mnt_freq, mnt->mnt_passno);
|
||||||
|
|
||||||
@@ -241,22 +246,22 @@ static int fsck(int pass)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (skip) {
|
if (skip) {
|
||||||
_d("Cannot fsck %s, not a block device: %s", dev, strerror(errno));
|
dbg("Cannot fsck %s, not a block device: %s", dev, strerror(errno));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ismnt("/proc/mounts", mnt->mnt_dir, "rw")) {
|
if (ismnt("/proc/mounts", mnt->mnt_dir, "rw")) {
|
||||||
_d("Skipping fsck of %s, already mounted rw on %s.", dev, mnt->mnt_dir);
|
dbg("Skipping fsck of %s, already mounted rw on %s.", dev, mnt->mnt_dir);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FSCK_FIX
|
#ifdef FSCK_FIX
|
||||||
snprintf(cmd, sizeof(cmd), "fsck -yf %s", dev);
|
snprintf(cmd, sizeof(cmd), "fsck -yf %s", dev);
|
||||||
#else
|
#else
|
||||||
snprintf(cmd, sizeof(cmd), "fsck -a %s", dev);
|
snprintf(cmd, sizeof(cmd), "fsck %s %s %s", fsck_mode, fsck_repair, dev);
|
||||||
#endif
|
#endif
|
||||||
_d("Running pass %d fsck command %s", pass, cmd);
|
dbg("Running pass %d fsck command %s", pass, cmd);
|
||||||
fsck_rc = run_interactive(cmd, "Checking filesystem %s", dev);
|
fsck_rc = run_interactive(cmd, "Checking filesystem %s", dev);
|
||||||
/*
|
/*
|
||||||
* "failure" is defined as exiting with a return code of
|
* "failure" is defined as exiting with a return code of
|
||||||
@@ -281,6 +286,9 @@ static int fsck_all(void)
|
|||||||
#ifndef FAST_BOOT
|
#ifndef FAST_BOOT
|
||||||
int pass;
|
int pass;
|
||||||
|
|
||||||
|
if (!fsck_mode)
|
||||||
|
return 0;
|
||||||
|
|
||||||
for (pass = 1; pass < 10; pass++) {
|
for (pass = 1; pass < 10; pass++) {
|
||||||
rc = fsck(pass);
|
rc = fsck(pass);
|
||||||
if (rc)
|
if (rc)
|
||||||
@@ -299,7 +307,7 @@ static void fs_mount(const char *src, const char *tgt, const char *fstype,
|
|||||||
|
|
||||||
rc = mount(src, tgt, fstype, flags, data);
|
rc = mount(src, tgt, fstype, flags, data);
|
||||||
if (rc && errno != EBUSY)
|
if (rc && errno != EBUSY)
|
||||||
_pe("Failed %s %s on %s", msg, src, tgt);
|
err(1, "Failed %s %s on %s", msg, src, tgt);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SYSROOT
|
#ifndef SYSROOT
|
||||||
@@ -453,7 +461,7 @@ static void fs_mount_all(void)
|
|||||||
if (!rescue)
|
if (!rescue)
|
||||||
fs_remount_root(fsck_all());
|
fs_remount_root(fsck_all());
|
||||||
|
|
||||||
_d("Root FS up, calling hooks ...");
|
dbg("Root FS up, calling hooks ...");
|
||||||
plugin_run_hooks(HOOK_ROOTFS_UP);
|
plugin_run_hooks(HOOK_ROOTFS_UP);
|
||||||
|
|
||||||
if (fstab && strcmp(fstab, "/etc/fstab"))
|
if (fstab && strcmp(fstab, "/etc/fstab"))
|
||||||
@@ -462,14 +470,17 @@ static void fs_mount_all(void)
|
|||||||
if (run_interactive(cmd, "Mounting filesystems from %s", fstab))
|
if (run_interactive(cmd, "Mounting filesystems from %s", fstab))
|
||||||
plugin_run_hooks(HOOK_MOUNT_ERROR);
|
plugin_run_hooks(HOOK_MOUNT_ERROR);
|
||||||
|
|
||||||
_d("Calling extra mount hook, after mount -a ...");
|
dbg("Calling extra mount hook, after mount -a ...");
|
||||||
plugin_run_hooks(HOOK_MOUNT_POST);
|
plugin_run_hooks(HOOK_MOUNT_POST);
|
||||||
|
|
||||||
_d("Enable any swap ...");
|
dbg("Enable any swap ...");
|
||||||
fs_swapon(cmd, sizeof(cmd));
|
fs_swapon(cmd, sizeof(cmd));
|
||||||
|
|
||||||
_d("Finalize, ensure common file systems are available ...");
|
dbg("Finalize, ensure common file systems are available ...");
|
||||||
fs_finalize();
|
fs_finalize();
|
||||||
|
|
||||||
|
dbg("Base FS up, calling hooks ...");
|
||||||
|
plugin_run_hooks(HOOK_BASEFS_UP);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -524,11 +535,11 @@ static void fs_init(void)
|
|||||||
static void finalize(void *unused)
|
static void finalize(void *unused)
|
||||||
{
|
{
|
||||||
/* Clean up bootstrap-only tasks/services that never started */
|
/* Clean up bootstrap-only tasks/services that never started */
|
||||||
_d("Clean up all bootstrap-only tasks/services ...");
|
dbg("Clean up all bootstrap-only tasks/services ...");
|
||||||
svc_prune_bootstrap();
|
svc_prune_bootstrap();
|
||||||
|
|
||||||
/* All services/tasks/etc. in configure runlevel have started */
|
/* All services/tasks/etc. in configure runlevel have started */
|
||||||
_d("Running svc up hooks ...");
|
dbg("Running svc up hooks ...");
|
||||||
plugin_run_hooks(HOOK_SVC_UP);
|
plugin_run_hooks(HOOK_SVC_UP);
|
||||||
service_step_all(SVC_TYPE_ANY);
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
|
||||||
@@ -537,7 +548,7 @@ static void finalize(void *unused)
|
|||||||
run_interactive(FINIT_RC_LOCAL, "Calling %s", FINIT_RC_LOCAL);
|
run_interactive(FINIT_RC_LOCAL, "Calling %s", FINIT_RC_LOCAL);
|
||||||
|
|
||||||
/* Hooks that should run at the very end */
|
/* Hooks that should run at the very end */
|
||||||
_d("Calling all system up hooks ...");
|
dbg("Calling all system up hooks ...");
|
||||||
plugin_run_hooks(HOOK_SYSTEM_UP);
|
plugin_run_hooks(HOOK_SYSTEM_UP);
|
||||||
service_step_all(SVC_TYPE_ANY);
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
|
||||||
@@ -574,42 +585,45 @@ static void bootstrap_worker(void *work)
|
|||||||
.cb = finalize,
|
.cb = finalize,
|
||||||
.delay = 10
|
.delay = 10
|
||||||
};
|
};
|
||||||
static int cnt = 120;
|
static int cnt = 120 * 10; /* We run with 100ms period */
|
||||||
int level = cfglevel;
|
int level = cfglevel;
|
||||||
|
|
||||||
_d("Step all services ...");
|
dbg("Step all services ...");
|
||||||
service_step_all(SVC_TYPE_ANY);
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
|
||||||
if (cnt-- > 0 && !service_completed()) {
|
if (cnt-- > 0 && !service_completed()) {
|
||||||
_d("Not all bootstrap run/tasks have completed yet ... %d", cnt);
|
dbg("Not all bootstrap run/tasks have completed yet ... %d", cnt);
|
||||||
schedule_work(work);
|
schedule_work(work);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cnt > 0)
|
if (cnt > 0)
|
||||||
_d("All run/task have completed, resuming bootstrap.");
|
dbg("All run/task have completed, resuming bootstrap.");
|
||||||
else
|
else
|
||||||
_d("Timeout, resuming bootstrap.");
|
dbg("Timeout, resuming bootstrap.");
|
||||||
|
|
||||||
_d("Starting runlevel change finalize ...");
|
dbg("Starting runlevel change finalize ...");
|
||||||
schedule_work(&final);
|
schedule_work(&final);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Run startup scripts in the runparts directory, if any.
|
* Run startup scripts in the runparts directory, if any.
|
||||||
*/
|
*/
|
||||||
if (runparts && fisdir(runparts) && !rescue)
|
if (runparts && fisdir(runparts) && !rescue)
|
||||||
run_parts(runparts, NULL);
|
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
|
* Start all tasks/services in the configured runlevel, or jump
|
||||||
* into the runlevel selected from the command line.
|
* into the runlevel selected from the command line.
|
||||||
*/
|
*/
|
||||||
if (cmdlevel) {
|
if (cmdlevel) {
|
||||||
_d("Runlevel %d requested from command line, starting all services ...", cmdlevel);
|
dbg("Runlevel %d requested from command line, starting all services ...", cmdlevel);
|
||||||
level = cmdlevel;
|
level = cmdlevel;
|
||||||
} else
|
} else
|
||||||
_d("Change to default runlevel(%d), starting all services ...", cfglevel);
|
dbg("Change to default runlevel(%d), starting all services ...", cfglevel);
|
||||||
|
|
||||||
service_runlevel(level);
|
service_runlevel(level);
|
||||||
}
|
}
|
||||||
@@ -689,12 +703,6 @@ static int telinit(int argc, char *argv[])
|
|||||||
return systemf("initctl -b runlevel %c", req);
|
return systemf("initctl -b runlevel %c", req);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: add non-pid1 process monitor here
|
|
||||||
*
|
|
||||||
* finit -f ~/.config/finit.conf &
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
return usage(1);
|
return usage(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -711,8 +719,18 @@ int main(int argc, char *argv[])
|
|||||||
uev_ctx_t loop;
|
uev_ctx_t loop;
|
||||||
|
|
||||||
/* user calling telinit or init */
|
/* user calling telinit or init */
|
||||||
if (getpid() != 1)
|
if (getpid() != 1) {
|
||||||
return telinit(argc, argv);
|
if (geteuid() == 0)
|
||||||
|
return telinit(argc, argv);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Issue #301: add non-pid1 process monitor here.
|
||||||
|
* Default to read ~/.config/finit.conf with the
|
||||||
|
* API socket in /run/user/$UID/. Lot of things
|
||||||
|
* to refactor before then though.
|
||||||
|
*/
|
||||||
|
return EX_NOPERM;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Need /dev, /proc, and /sys for console=, remount and cgroups
|
* Need /dev, /proc, and /sys for console=, remount and cgroups
|
||||||
@@ -742,7 +760,7 @@ int main(int argc, char *argv[])
|
|||||||
conf_reset_env();
|
conf_reset_env();
|
||||||
|
|
||||||
if (chdir("/"))
|
if (chdir("/"))
|
||||||
_pe("Failed cd /");
|
err(1, "Failed cd /");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In case of emergency.
|
* In case of emergency.
|
||||||
@@ -783,7 +801,11 @@ int main(int argc, char *argv[])
|
|||||||
*/
|
*/
|
||||||
fs_mount_all();
|
fs_mount_all();
|
||||||
|
|
||||||
/* Bootstrap conditions, needed for hooks */
|
/*
|
||||||
|
* Base FS up, enable standard SysV init signals and
|
||||||
|
* Bootstrap conditions, needed for hooks
|
||||||
|
*/
|
||||||
|
sig_setup(&loop);
|
||||||
cond_init();
|
cond_init();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -794,29 +816,12 @@ int main(int argc, char *argv[])
|
|||||||
cond_set_oneshot(plugin_hook_str(HOOK_ROOTFS_UP));
|
cond_set_oneshot(plugin_hook_str(HOOK_ROOTFS_UP));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize .conf system and load static /etc/finit.conf.
|
* Initialize .conf system and load static /etc/finit.conf then
|
||||||
|
* tell the world what we used.
|
||||||
*/
|
*/
|
||||||
|
devmon_init();
|
||||||
conf_init(&loop);
|
conf_init(&loop);
|
||||||
|
conf_saverc();
|
||||||
/*
|
|
||||||
* Start built-in watchdogd as soon as possible, if enabled
|
|
||||||
*/
|
|
||||||
if (whichp(FINIT_LIBPATH_ "/watchdogd") && fexist(WDT_DEVNODE)) {
|
|
||||||
service_register(SVC_TYPE_SERVICE, "[123456789] cgroup.init name:watchdog :finit " FINIT_LIBPATH_ "/watchdogd -- Finit watchdog daemon", global_rlimit, NULL);
|
|
||||||
wdog = svc_find("watchdog", "finit");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Start kernel event daemon as soon as possible, if enabled
|
|
||||||
*/
|
|
||||||
if (whichp(FINIT_LIBPATH_ "/keventd"))
|
|
||||||
service_register(SVC_TYPE_SERVICE, "[123456789] cgroup.init " FINIT_LIBPATH_ "/keventd -- Finit kernel event daemon", global_rlimit, NULL);
|
|
||||||
|
|
||||||
/* Base FS up, enable standard SysV init signals */
|
|
||||||
sig_setup(&loop);
|
|
||||||
|
|
||||||
_d("Base FS up, calling hooks ...");
|
|
||||||
plugin_run_hooks(HOOK_BASEFS_UP);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up inotify watcher for /etc/finit.conf, /etc/finit.d, and
|
* Set up inotify watcher for /etc/finit.conf, /etc/finit.d, and
|
||||||
@@ -824,13 +829,13 @@ int main(int argc, char *argv[])
|
|||||||
*/
|
*/
|
||||||
conf_monitor();
|
conf_monitor();
|
||||||
|
|
||||||
_d("Starting initctl API responder ...");
|
dbg("Starting initctl API responder ...");
|
||||||
api_init(&loop);
|
api_init(&loop);
|
||||||
|
|
||||||
_d("Starting the big state machine ...");
|
dbg("Starting the big state machine ...");
|
||||||
schedule_work(&crank_work);
|
schedule_work(&crank_work);
|
||||||
|
|
||||||
_d("Starting bootstrap finalize timer ...");
|
dbg("Starting bootstrap finalize timer ...");
|
||||||
schedule_work(&bootstrap_work);
|
schedule_work(&bootstrap_work);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -841,7 +846,7 @@ int main(int argc, char *argv[])
|
|||||||
/*
|
/*
|
||||||
* Enter main loop to monitor /dev/initctl and services
|
* Enter main loop to monitor /dev/initctl and services
|
||||||
*/
|
*/
|
||||||
_d("Entering main loop ...");
|
dbg("Entering main loop ...");
|
||||||
return uev_run(&loop, 0);
|
return uev_run(&loop, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-9
@@ -1,7 +1,7 @@
|
|||||||
/* Finit - Fast /sbin/init replacement w/ I/O, hook & service plugins
|
/* Finit - Fast /sbin/init replacement w/ I/O, hook & service plugins
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||||
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -54,19 +54,20 @@
|
|||||||
#define FINIT_CGPATH "/sys/fs/cgroup"
|
#define FINIT_CGPATH "/sys/fs/cgroup"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* To use these, include config.h, or define FINIT_LIBPATH_ */
|
/* To use these, include config.h, or define FINIT_EXECPATH_ */
|
||||||
#define _PATH_LOGIT FINIT_LIBPATH_ "/logit"
|
#define _PATH_LOGIT FINIT_EXECPATH_ "/logit"
|
||||||
#define _PATH_SULOGIN FINIT_LIBPATH_ "/sulogin"
|
#define _PATH_SULOGIN FINIT_EXECPATH_ "/sulogin"
|
||||||
#define _PATH_GETTY FINIT_LIBPATH_ "/getty"
|
#define _PATH_GETTY FINIT_EXECPATH_ "/getty"
|
||||||
|
|
||||||
#define CMD_SIZE 256
|
#define CMD_SIZE 256
|
||||||
#define LINE_SIZE 1024
|
#define LINE_SIZE 1024
|
||||||
#define BUF_SIZE 4096
|
#define BUF_SIZE 4096
|
||||||
|
|
||||||
/* We extend the INIT_CMD_ range for the new initctl tool. */
|
|
||||||
#define INIT_SOCKET _PATH_VARRUN "finit/socket"
|
#define INIT_SOCKET _PATH_VARRUN "finit/socket"
|
||||||
#define INIT_MAGIC 0x03091969
|
#define INIT_MAGIC 0x03091969
|
||||||
|
#define INIT_LEVEL 10
|
||||||
|
|
||||||
|
/* We extend the INIT_CMD_ range for the new initctl tool. */
|
||||||
#define INIT_CMD_START 0
|
#define INIT_CMD_START 0
|
||||||
#define INIT_CMD_RUNLVL 1
|
#define INIT_CMD_RUNLVL 1
|
||||||
#define INIT_CMD_POWERFAIL 2
|
#define INIT_CMD_POWERFAIL 2
|
||||||
@@ -83,8 +84,8 @@
|
|||||||
#define INIT_CMD_STOP_SVC 11
|
#define INIT_CMD_STOP_SVC 11
|
||||||
#define INIT_CMD_RELOAD_SVC 12 /* SIGHUP service */
|
#define INIT_CMD_RELOAD_SVC 12 /* SIGHUP service */
|
||||||
#define INIT_CMD_RESTART_SVC 13 /* START service, clearing blocks */
|
#define INIT_CMD_RESTART_SVC 13 /* START service, clearing blocks */
|
||||||
#define INIT_CMD_UNUSED2 14 /* Unused, was INIT_CMD_QUERY_INETD */
|
#define INIT_CMD_GET_PLUGINS 14 /* Fill data[] with loaded plugins */
|
||||||
#define INIT_CMD_UNUSED1 15 /* Unused, was INIT_CMD_EMIT */
|
#define INIT_CMD_PLUGIN_DEPS 15 /* Fill data[] with plugin deps */
|
||||||
#define INIT_CMD_GET_RUNLEVEL 16
|
#define INIT_CMD_GET_RUNLEVEL 16
|
||||||
#define INIT_CMD_REBOOT 20
|
#define INIT_CMD_REBOOT 20
|
||||||
#define INIT_CMD_HALT 21
|
#define INIT_CMD_HALT 21
|
||||||
@@ -96,6 +97,7 @@
|
|||||||
#define INIT_CMD_SVC_FIND 131
|
#define INIT_CMD_SVC_FIND 131
|
||||||
#define INIT_CMD_SVC_FIND_BYC 132
|
#define INIT_CMD_SVC_FIND_BYC 132
|
||||||
#define INIT_CMD_SIGNAL 133
|
#define INIT_CMD_SIGNAL 133
|
||||||
|
#define INIT_CMD_NOTIFY_SOCKET 200 /* For readiness notification socket */
|
||||||
#define INIT_CMD_NACK 254
|
#define INIT_CMD_NACK 254
|
||||||
#define INIT_CMD_ACK 255
|
#define INIT_CMD_ACK 255
|
||||||
|
|
||||||
@@ -117,11 +119,11 @@ extern int rescue;
|
|||||||
extern int single;
|
extern int single;
|
||||||
extern int bootstrap;
|
extern int bootstrap;
|
||||||
extern int kerndebug;
|
extern int kerndebug;
|
||||||
|
extern int syncsec;
|
||||||
extern char *fstab;
|
extern char *fstab;
|
||||||
extern char *sdown;
|
extern char *sdown;
|
||||||
extern char *network;
|
extern char *network;
|
||||||
extern char *hostname;
|
extern char *hostname;
|
||||||
extern char *rcsd;
|
|
||||||
extern char *runparts;
|
extern char *runparts;
|
||||||
extern char *osheading;
|
extern char *osheading;
|
||||||
extern uev_ctx_t *ctx;
|
extern uev_ctx_t *ctx;
|
||||||
|
|||||||
+147
-18
@@ -1,6 +1,6 @@
|
|||||||
/* Initialize and serve a login terminal
|
/* Initialize and serve a login terminal
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -34,6 +34,7 @@
|
|||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
|
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
|
#include <time.h>
|
||||||
#include <unistd.h> /* sysconf() */
|
#include <unistd.h> /* sysconf() */
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
@@ -48,7 +49,80 @@
|
|||||||
#define LOGIN_NAME_MIN 64
|
#define LOGIN_NAME_MIN 64
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct osrel {
|
||||||
|
char name[32];
|
||||||
|
char pretty[64];
|
||||||
|
char id[32];
|
||||||
|
char version[32];
|
||||||
|
char version_id[32];
|
||||||
|
char home_url[128];
|
||||||
|
char doc_url[128];
|
||||||
|
char bug_url[128];
|
||||||
|
char support_url[128];
|
||||||
|
};
|
||||||
|
|
||||||
static long logname_len = 32; /* useradd(1) limit at 32 chars */
|
static long logname_len = 32; /* useradd(1) limit at 32 chars */
|
||||||
|
static int passenv = 0; /* Set /bin/login -p or not */
|
||||||
|
|
||||||
|
static void get_val(char *line, const char *key, char *buf, size_t len)
|
||||||
|
{
|
||||||
|
char *val;
|
||||||
|
|
||||||
|
if ((val = fgetval(line, key, "="))) {
|
||||||
|
strlcpy(buf, val, len);
|
||||||
|
free(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse os-release
|
||||||
|
*/
|
||||||
|
static int osrel(struct osrel *rel)
|
||||||
|
{
|
||||||
|
char codename[30];
|
||||||
|
char *line;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopen("/etc/os-release", "r");
|
||||||
|
if (!fp) {
|
||||||
|
fp = fopen("/usr/lib/os-release", "r");
|
||||||
|
if (!fp)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(rel->version, 0, sizeof(rel->version));
|
||||||
|
memset(codename, 0, sizeof(codename));
|
||||||
|
|
||||||
|
while ((line = fparseln(fp, NULL, NULL, NULL, 0))) {
|
||||||
|
get_val(line, "NAME", rel->name, sizeof(rel->name));
|
||||||
|
get_val(line, "PRETTY_NAME", rel->pretty, sizeof(rel->pretty));
|
||||||
|
get_val(line, "ID", rel->id, sizeof(rel->id));
|
||||||
|
get_val(line, "VERSION", rel->version, sizeof(rel->version));
|
||||||
|
get_val(line, "VERSION_ID", rel->version_id, sizeof(rel->version_id));
|
||||||
|
get_val(line, "VERSION_CODENAME", codename, sizeof(codename));
|
||||||
|
get_val(line, "HOME_URL", rel->home_url, sizeof(rel->home_url));
|
||||||
|
get_val(line, "DOCUMENTATION_URL", rel->doc_url, sizeof(rel->doc_url));
|
||||||
|
get_val(line, "SUPPORT_URL", rel->support_url, sizeof(rel->support_url));
|
||||||
|
get_val(line, "BUG_REPORT_URL", rel->bug_url, sizeof(rel->bug_url));
|
||||||
|
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Many distros don't set VERSION or VERSION_ID for their
|
||||||
|
* rolling, or unstable, branches. However, most set the
|
||||||
|
* version code name, so we use that as VERSION.
|
||||||
|
*/
|
||||||
|
if (!rel->version[0] && codename[0]) {
|
||||||
|
if (codename[0] == '(')
|
||||||
|
strlcpy(rel->version, codename, sizeof(rel->version));
|
||||||
|
else
|
||||||
|
snprintf(rel->version, sizeof(rel->version), "(%s)", codename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read one character from stdin.
|
* Read one character from stdin.
|
||||||
@@ -67,10 +141,19 @@ static int readch(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse and display a line from /etc/issue
|
* Parse and display a line from /etc/issue
|
||||||
|
*
|
||||||
|
* Includes Finit-specific extensions to display information from
|
||||||
|
* /etc/os-release instead of relying on legacy uname. Activated
|
||||||
|
* only if /etc/os-release or /usr/lib/os-release exist.
|
||||||
|
*
|
||||||
|
* https://www.unix.com/man-page/Linux/8/getty/
|
||||||
|
* https://www.systutorials.com/docs/linux/man/8-mingetty/
|
||||||
*/
|
*/
|
||||||
static void do_parse(char *line, struct utsname *uts, char *tty)
|
static void parseln(char *line, struct utsname *uts, struct osrel *rel, char *tty, int compat)
|
||||||
{
|
{
|
||||||
|
char buf[32] = { 0 };
|
||||||
char *s, *s0;
|
char *s, *s0;
|
||||||
|
time_t now;
|
||||||
|
|
||||||
s0 = line;
|
s0 = line;
|
||||||
for (s = line; *s != 0; s++) {
|
for (s = line; *s != 0; s++) {
|
||||||
@@ -79,12 +162,32 @@ static void do_parse(char *line, struct utsname *uts, char *tty)
|
|||||||
dprint(STDOUT_FILENO, s0, s - s0);
|
dprint(STDOUT_FILENO, s0, s - s0);
|
||||||
s0 = s + 2;
|
s0 = s + 2;
|
||||||
switch (*++s) {
|
switch (*++s) {
|
||||||
|
case 'B':
|
||||||
|
if (!compat)
|
||||||
|
dprint(STDOUT_FILENO, rel->bug_url, 0);
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
if (!compat)
|
||||||
|
dprint(STDOUT_FILENO, rel->doc_url, 0);
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
if (!compat)
|
||||||
|
dprint(STDOUT_FILENO, rel->home_url, 0);
|
||||||
|
break;
|
||||||
|
case 'I':
|
||||||
|
if (!compat)
|
||||||
|
dprint(STDOUT_FILENO, rel->id, 0);
|
||||||
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
dprint(STDOUT_FILENO, tty, 0);
|
dprint(STDOUT_FILENO, tty, 0);
|
||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
dprint(STDOUT_FILENO, uts->machine, 0);
|
dprint(STDOUT_FILENO, uts->machine, 0);
|
||||||
break;
|
break;
|
||||||
|
case 'N':
|
||||||
|
if (!compat)
|
||||||
|
dprint(STDOUT_FILENO, rel->name, 0);
|
||||||
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
dprint(STDOUT_FILENO, uts->nodename, 0);
|
dprint(STDOUT_FILENO, uts->nodename, 0);
|
||||||
break;
|
break;
|
||||||
@@ -94,13 +197,31 @@ static void do_parse(char *line, struct utsname *uts, char *tty)
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case 'r':
|
case 'r':
|
||||||
dprint(STDOUT_FILENO, uts->release, 0);
|
if (compat)
|
||||||
|
dprint(STDOUT_FILENO, uts->release, 0);
|
||||||
|
else
|
||||||
|
dprint(STDOUT_FILENO, rel->version_id, 0);
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
if (!compat)
|
||||||
|
dprint(STDOUT_FILENO, rel->support_url, 0);
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
dprint(STDOUT_FILENO, uts->sysname, 0);
|
if (compat)
|
||||||
|
dprint(STDOUT_FILENO, uts->sysname, 0);
|
||||||
|
else
|
||||||
|
dprint(STDOUT_FILENO, rel->pretty, 0);
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
now = time(NULL);
|
||||||
|
ctime_r(&now, buf);
|
||||||
|
dprint(STDOUT_FILENO, chomp(buf), 0);
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
dprint(STDOUT_FILENO, uts->version, 0);
|
if (compat)
|
||||||
|
dprint(STDOUT_FILENO, uts->version, 0);
|
||||||
|
else
|
||||||
|
dprint(STDOUT_FILENO, rel->version, 0);
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
goto leave;
|
goto leave;
|
||||||
@@ -118,28 +239,31 @@ leave:
|
|||||||
/*
|
/*
|
||||||
* Parse and display /etc/issue
|
* Parse and display /etc/issue
|
||||||
*/
|
*/
|
||||||
static void do_issue(char *tty)
|
static void issue(char *tty)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
|
||||||
char buf[BUFSIZ] = "Welcome to \\s \\v \\n \\l\n\n";
|
char buf[BUFSIZ] = "Welcome to \\s \\v \\n \\l\n\n";
|
||||||
struct utsname uts;
|
struct utsname uts;
|
||||||
|
struct osrel rel;
|
||||||
|
int compat;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get data about this machine.
|
* Get data about this machine.
|
||||||
*/
|
*/
|
||||||
uname(&uts);
|
uname(&uts);
|
||||||
|
compat = osrel(&rel);
|
||||||
|
|
||||||
fp = fopen("/etc/issue", "r");
|
fp = fopen("/etc/issue", "r");
|
||||||
if (fp) {
|
if (fp) {
|
||||||
while (fgets(buf, sizeof(buf), fp))
|
while (fgets(buf, sizeof(buf), fp))
|
||||||
do_parse(buf, &uts, tty);
|
parseln(buf, &uts, &rel, tty, compat);
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
} else {
|
} else {
|
||||||
do_parse(buf, &uts, tty);
|
parseln(buf, &uts, &rel, tty, compat);
|
||||||
}
|
}
|
||||||
|
|
||||||
do_parse("\\n login: ", &uts, tty);
|
parseln("\\n login: ", &uts, &rel, tty, compat);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -156,7 +280,7 @@ static int get_logname(char *tty, char *name, size_t len)
|
|||||||
ch = ' ';
|
ch = ' ';
|
||||||
*name = '\0';
|
*name = '\0';
|
||||||
while (ch != '\n') {
|
while (ch != '\n') {
|
||||||
do_issue(tty);
|
issue(tty);
|
||||||
|
|
||||||
np = name;
|
np = name;
|
||||||
while ((ch = readch()) != '\n') {
|
while ((ch = readch()) != '\n') {
|
||||||
@@ -177,15 +301,17 @@ static int get_logname(char *tty, char *name, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Execute the login(1) command with the current
|
* Start login(1) with the current username as its argument. It replies
|
||||||
* username as its argument. It will reply to the
|
* to the calling user by typing "Password: " ...
|
||||||
* calling user by typing "Password: "...
|
|
||||||
*/
|
*/
|
||||||
static int do_login(char *name)
|
static int exec_login(char *name)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
execl(_PATH_LOGIN, _PATH_LOGIN, name, NULL);
|
if (passenv)
|
||||||
|
execl(_PATH_LOGIN, _PATH_LOGIN, "-p", name, NULL);
|
||||||
|
else
|
||||||
|
execl(_PATH_LOGIN, _PATH_LOGIN, name, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Failed to exec login, should not happen on normal systems.
|
* Failed to exec login, should not happen on normal systems.
|
||||||
@@ -238,7 +364,7 @@ restart:
|
|||||||
if (term && term[0])
|
if (term && term[0])
|
||||||
setenv("TERM", term, 1);
|
setenv("TERM", term, 1);
|
||||||
|
|
||||||
return do_login(name);
|
return exec_login(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int usage(int rc)
|
static int usage(int rc)
|
||||||
@@ -252,11 +378,14 @@ int main(int argc, char *argv[])
|
|||||||
char *tty, *speed = "0", *term = NULL;
|
char *tty, *speed = "0", *term = NULL;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, "h?")) != EOF) {
|
while ((c = getopt(argc, argv, "h?p")) != EOF) {
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case 'h':
|
case 'h':
|
||||||
case '?':
|
case '?':
|
||||||
return usage(0);
|
return usage(0);
|
||||||
|
case 'p':
|
||||||
|
passenv = 1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return usage(1);
|
return usage(1);
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-8
@@ -1,7 +1,7 @@
|
|||||||
/* Misc. utility functions for finit and its plugins
|
/* Misc. utility functions for finit and its plugins
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||||
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -42,6 +42,7 @@
|
|||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
#include "log.h"
|
||||||
#include "private.h"
|
#include "private.h"
|
||||||
#include "sig.h"
|
#include "sig.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@@ -366,7 +367,8 @@ int print_result(int fail)
|
|||||||
int getuser(char *username, char **home)
|
int getuser(char *username, char **home)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_STATIC
|
#ifdef ENABLE_STATIC
|
||||||
*home = "/"; /* XXX: Fixme */
|
if (home)
|
||||||
|
*home = "/"; /* XXX: Fixme */
|
||||||
return fgetint("/etc/passwd", "x:\n", username);
|
return fgetint("/etc/passwd", "x:\n", username);
|
||||||
#else
|
#else
|
||||||
struct passwd *usr;
|
struct passwd *usr;
|
||||||
@@ -443,8 +445,10 @@ int mksubsys(const char *dir, mode_t mode, char *user, char *group)
|
|||||||
gid = 0;
|
gid = 0;
|
||||||
|
|
||||||
rc = makedir(dir, mode);
|
rc = makedir(dir, mode);
|
||||||
|
if (rc && errno == EEXIST)
|
||||||
|
rc = chmod(dir, mode);
|
||||||
if (chown(dir, uid, gid))
|
if (chown(dir, uid, gid))
|
||||||
_pe("Failed chown(%s, %d, %d)", dir, uid, gid);
|
err(1, "Failed chown(%s, %d, %d)", dir, uid, gid);
|
||||||
}
|
}
|
||||||
|
|
||||||
umask(omask);
|
umask(omask);
|
||||||
@@ -482,7 +486,7 @@ void set_hostname(char **hostname)
|
|||||||
done:
|
done:
|
||||||
if (*hostname) {
|
if (*hostname) {
|
||||||
if (sethostname(*hostname, strlen(*hostname)))
|
if (sethostname(*hostname, strlen(*hostname)))
|
||||||
_pe("Failed sethostnaem(%s)", *hostname);
|
err(1, "Failed sethostname(%s)", *hostname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -496,9 +500,9 @@ void networking(int updown)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (updown)
|
if (updown)
|
||||||
_d("Setting up networking ...");
|
dbg("Setting up networking ...");
|
||||||
else
|
else
|
||||||
_d("Taking down networking ...");
|
dbg("Taking down networking ...");
|
||||||
|
|
||||||
/* Run user network start script if enabled */
|
/* Run user network start script if enabled */
|
||||||
if (updown && network) {
|
if (updown && network) {
|
||||||
@@ -536,7 +540,7 @@ void networking(int updown)
|
|||||||
char buf[256];
|
char buf[256];
|
||||||
|
|
||||||
while (fgets(buf, sizeof(buf), pp))
|
while (fgets(buf, sizeof(buf), pp))
|
||||||
logit(LOG_NOTICE, "network: %s", buf);
|
logit(LOG_NOTICE, "network: %s", chomp(buf));
|
||||||
|
|
||||||
rc = pclose(pp);
|
rc = pclose(pp);
|
||||||
}
|
}
|
||||||
@@ -557,8 +561,11 @@ done:
|
|||||||
|
|
||||||
/* Hooks that rely on loopback, or basic networking being up. */
|
/* Hooks that rely on loopback, or basic networking being up. */
|
||||||
if (updown) {
|
if (updown) {
|
||||||
_d("Calling all network up hooks ...");
|
dbg("Calling all network up hooks ...");
|
||||||
plugin_run_hooks(HOOK_NETWORK_UP);
|
plugin_run_hooks(HOOK_NETWORK_UP);
|
||||||
|
} else {
|
||||||
|
dbg("Calling all network down hooks ...");
|
||||||
|
plugin_run_hooks(HOOK_NETWORK_DN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+95
-5
@@ -1,7 +1,7 @@
|
|||||||
/* Misc. utility functions and C-library extensions for finit and its plugins
|
/* Misc. utility functions and C-library extensions for finit and its plugins
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||||
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -25,8 +25,12 @@
|
|||||||
#ifndef FINIT_HELPERS_H_
|
#ifndef FINIT_HELPERS_H_
|
||||||
#define FINIT_HELPERS_H_
|
#define FINIT_HELPERS_H_
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
|
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
@@ -84,18 +88,58 @@ int run_interactive (char *cmd, char *fmt, ...) __attribute__ ((format (prin
|
|||||||
int exec_runtask (char *cmd, char *args[]);
|
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_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[]);
|
pid_t run_sh (char *tty, int noclear, int nowait, struct rlimit rlimit[]);
|
||||||
int run_parts (char *dir, char *cmd);
|
int run_parts (char *dir, char *cmd, const char *env[], int progress);
|
||||||
|
|
||||||
static inline int create(char *path, mode_t mode, uid_t uid, gid_t gid)
|
/*
|
||||||
|
* Defaults to user "root" and group "wheel" (root) if:
|
||||||
|
* 1) the user is missing
|
||||||
|
* 2) the group or the file /etc/group is missing
|
||||||
|
*/
|
||||||
|
static inline int create(char *path, mode_t mode, char *user, char *group)
|
||||||
{
|
{
|
||||||
if (touch(path) || chmod(path, mode) || chown(path, uid, gid)) {
|
int fd, uid, gid;
|
||||||
_w("Failed creating %s properly.", path);
|
|
||||||
|
if (!path) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uid = getuser(user, NULL);
|
||||||
|
if (uid < 0)
|
||||||
|
uid = 0;
|
||||||
|
gid = getgroup(group);
|
||||||
|
if (gid < 0)
|
||||||
|
gid = 0;
|
||||||
|
|
||||||
|
fd = creat(path, mode);
|
||||||
|
if (fd == -1) {
|
||||||
|
warn("Failed creating %s properly", path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
if (chown(path, uid, gid)) {
|
||||||
|
warn("Failed chowning %s properly", path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int ln(const char *target, const char *linkpath)
|
||||||
|
{
|
||||||
|
if (!target || !linkpath) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symlink(target, linkpath)) {
|
||||||
|
if (errno != EEXIST)
|
||||||
|
warn("Failed creating %s -> %s symlink", target, linkpath);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
static inline int dprint(int fd, const char *s, size_t len)
|
static inline int dprint(int fd, const char *s, size_t len)
|
||||||
{
|
{
|
||||||
size_t loop = 3;
|
size_t loop = 3;
|
||||||
@@ -114,6 +158,52 @@ static inline int dprint(int fd, const char *s, size_t len)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline char *fgetval(char *line, const char *key, char *sep)
|
||||||
|
{
|
||||||
|
char *ptr, *str, *copy;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
str = copy = strdup(line);
|
||||||
|
if (!copy)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ptr = strsep(&str, sep);
|
||||||
|
if (ptr && strcmp(ptr, key)) {
|
||||||
|
fail:
|
||||||
|
free(copy);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if we should strip optional separator, e.g.,
|
||||||
|
* 'foo = bar' => '= bar' should be stripped to 'bar'
|
||||||
|
*/
|
||||||
|
while (str && strchr(sep, str[0])) {
|
||||||
|
ptr = strsep(&str, sep);
|
||||||
|
if (!ptr)
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
ptr = str;
|
||||||
|
|
||||||
|
if (*ptr == '"' || *ptr == '\'') {
|
||||||
|
char *end = &ptr[strlen(ptr) - 1];
|
||||||
|
char q = *ptr;
|
||||||
|
|
||||||
|
while (end > ptr && isspace(*end))
|
||||||
|
*end-- = 0;
|
||||||
|
|
||||||
|
if (*end == q) {
|
||||||
|
*end = 0;
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
len = strlen(ptr) + 1;
|
||||||
|
memmove(copy, ptr, len);
|
||||||
|
|
||||||
|
return realloc(copy, len);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* FINIT_HELPERS_H_ */
|
#endif /* FINIT_HELPERS_H_ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+497
-135
File diff suppressed because it is too large
Load Diff
+6
-1
@@ -1,6 +1,6 @@
|
|||||||
/* New client tool, replaces old /dev/initctl API and telinit tool
|
/* New client tool, replaces old /dev/initctl API and telinit tool
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2015-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -29,10 +29,15 @@
|
|||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
extern char *finit_conf;
|
||||||
|
extern char *finit_rcsd;
|
||||||
|
|
||||||
extern int icreate; /* initctl -c */
|
extern int icreate; /* initctl -c */
|
||||||
extern int iforce; /* initctl -f */
|
extern int iforce; /* initctl -f */
|
||||||
extern int ionce; /* initctl -1 */
|
extern int ionce; /* initctl -1 */
|
||||||
extern int heading; /* initctl -t */
|
extern int heading; /* initctl -t */
|
||||||
|
extern int json; /* initctl -j */
|
||||||
|
extern int noerr; /* initctl -n */
|
||||||
extern int verbose; /* initctl -v */
|
extern int verbose; /* initctl -v */
|
||||||
extern int plain; /* initctl -p */
|
extern int plain; /* initctl -p */
|
||||||
extern int quiet; /* initctl -q */
|
extern int quiet; /* initctl -q */
|
||||||
|
|||||||
+16
-11
@@ -1,7 +1,7 @@
|
|||||||
/* inotify watcher for files or directories
|
/* inotify watcher for files or directories
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
|
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
|
||||||
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -52,7 +52,7 @@ int iwatch_init(struct iwatch *iw)
|
|||||||
|
|
||||||
iw->fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
iw->fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
||||||
if (iw->fd < 0) {
|
if (iw->fd < 0) {
|
||||||
_pe("Failed creating inotify descriptor");
|
warn("Failed creating inotify descriptor");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ int iwatch_init(struct iwatch *iw)
|
|||||||
len = sizeof(sz);
|
len = sizeof(sz);
|
||||||
if (!getsockopt(iw->fd, SOL_SOCKET, SO_RCVBUF, &sz, &len)) {
|
if (!getsockopt(iw->fd, SOL_SOCKET, SO_RCVBUF, &sz, &len)) {
|
||||||
if (setsockopt(iw->fd, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)))
|
if (setsockopt(iw->fd, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)))
|
||||||
_pe("Failed increasing size of inotify socket");
|
warn("Failed increasing size of inotify socket");
|
||||||
}
|
}
|
||||||
|
|
||||||
initialized = 1;
|
initialized = 1;
|
||||||
@@ -87,7 +87,7 @@ void iwatch_exit(struct iwatch *iw)
|
|||||||
initialized = 0;
|
initialized = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int iwatch_add(struct iwatch *iw, char *file, uint32_t mask)
|
int iwatch_add1(struct iwatch *iw, char *file, uint32_t mask)
|
||||||
{
|
{
|
||||||
struct iwatch_path *iwp;
|
struct iwatch_path *iwp;
|
||||||
char *path;
|
char *path;
|
||||||
@@ -97,18 +97,18 @@ int iwatch_add(struct iwatch *iw, char *file, uint32_t mask)
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (!fexist(file)) {
|
if (!fexist(file)) {
|
||||||
_d("skipping %s: no such file or directory", file);
|
dbg("skipping %s: no such file or directory", file);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
_d("adding new watcher for path %s", file);
|
dbg("adding new watcher for path %s", file);
|
||||||
|
|
||||||
path = strdup(file);
|
path = strdup(file);
|
||||||
if (!path) {
|
if (!path) {
|
||||||
_pe("Out of memory");
|
warn("Out of memory");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
wd = inotify_add_watch(iw->fd, path, IWATCH_MASK | mask);
|
wd = inotify_add_watch(iw->fd, path, mask);
|
||||||
if (wd < 0) {
|
if (wd < 0) {
|
||||||
switch (errno) {
|
switch (errno) {
|
||||||
case EEXIST:
|
case EEXIST:
|
||||||
@@ -124,7 +124,7 @@ int iwatch_add(struct iwatch *iw, char *file, uint32_t mask)
|
|||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_pe("Failed adding watcher for %s", path);
|
warn("Failed adding watcher for %s", path);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +134,7 @@ int iwatch_add(struct iwatch *iw, char *file, uint32_t mask)
|
|||||||
|
|
||||||
iwp = malloc(sizeof(struct iwatch_path));
|
iwp = malloc(sizeof(struct iwatch_path));
|
||||||
if (!iwp) {
|
if (!iwp) {
|
||||||
_pe("Failed allocating new `struct iwatch_path`");
|
warn("Failed allocating new `struct iwatch_path`");
|
||||||
inotify_rm_watch(iw->fd, wd);
|
inotify_rm_watch(iw->fd, wd);
|
||||||
free(path);
|
free(path);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -147,12 +147,17 @@ int iwatch_add(struct iwatch *iw, char *file, uint32_t mask)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int iwatch_add(struct iwatch *iw, char *file, uint32_t mask)
|
||||||
|
{
|
||||||
|
return iwatch_add1(iw, file, IWATCH_MASK | mask);
|
||||||
|
}
|
||||||
|
|
||||||
int iwatch_del(struct iwatch *iw, struct iwatch_path *iwp)
|
int iwatch_del(struct iwatch *iw, struct iwatch_path *iwp)
|
||||||
{
|
{
|
||||||
if (!initialized)
|
if (!initialized)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
_d("Removing watcher for removed path %s", iwp->path);
|
dbg("Removing watcher for removed path %s", iwp->path);
|
||||||
|
|
||||||
TAILQ_REMOVE(&iw->iwp_list, iwp, link);
|
TAILQ_REMOVE(&iw->iwp_list, iwp, link);
|
||||||
inotify_rm_watch(iw->fd, iwp->wd);
|
inotify_rm_watch(iw->fd, iwp->wd);
|
||||||
|
|||||||
+2
-1
@@ -1,7 +1,7 @@
|
|||||||
/* inotify watcher for files or directories
|
/* inotify watcher for files or directories
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
|
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
|
||||||
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -59,6 +59,7 @@ struct iwatch {
|
|||||||
int iwatch_init (struct iwatch *iw);
|
int iwatch_init (struct iwatch *iw);
|
||||||
void iwatch_exit (struct iwatch *iw);
|
void iwatch_exit (struct iwatch *iw);
|
||||||
|
|
||||||
|
int iwatch_add1 (struct iwatch *iw, char *file, uint32_t mask);
|
||||||
int iwatch_add (struct iwatch *iw, char *file, uint32_t mask);
|
int iwatch_add (struct iwatch *iw, char *file, uint32_t mask);
|
||||||
int iwatch_del (struct iwatch *iw, struct iwatch_path *iwp);
|
int iwatch_del (struct iwatch *iw, struct iwatch_path *iwp);
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
/* Listens to kernel events like AC power status and manages sys/ conditions
|
/* Listens to kernel events like AC power status and manages sys/ conditions
|
||||||
*
|
*
|
||||||
* Copyright (c) 2021-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2021-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -152,7 +152,7 @@ static void init(void)
|
|||||||
|
|
||||||
for (i = 0; i < (int)NELEMS(cond_dirs); i++) {
|
for (i = 0; i < (int)NELEMS(cond_dirs); i++) {
|
||||||
if (mkpath(cond_dirs[i], 0755) && errno != EEXIST) {
|
if (mkpath(cond_dirs[i], 0755) && errno != EEXIST) {
|
||||||
_pe("Failed creating %s condition directory, %s", COND_SYS,
|
warn("Failed creating %s condition directory, %s", COND_SYS,
|
||||||
cond_dirs[i]);
|
cond_dirs[i]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* Finit daemon log functions
|
/* Finit daemon log functions
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <time.h>
|
||||||
#ifdef _LIBITE_LITE
|
#ifdef _LIBITE_LITE
|
||||||
# include <libite/lite.h>
|
# include <libite/lite.h>
|
||||||
#else
|
#else
|
||||||
@@ -99,6 +100,21 @@ void log_debug(void)
|
|||||||
logit(LOG_NOTICE, "Debug mode %s", debug ? "enabled" : "disabled");
|
logit(LOG_NOTICE, "Debug mode %s", debug ? "enabled" : "disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *l2s(int prio)
|
||||||
|
{
|
||||||
|
int level = prio & ~LOG_CONSOLE;
|
||||||
|
|
||||||
|
switch (level) {
|
||||||
|
case LOG_ERR: return "ERR";
|
||||||
|
case LOG_WARNING: return "WRN";
|
||||||
|
case LOG_NOTICE: return "NOT";
|
||||||
|
case LOG_INFO: return "NFO";
|
||||||
|
case LOG_DEBUG: return "DBG";
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return "UNK";
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Log to /dev/kmsg until syslogd has started, then openlog()
|
* Log to /dev/kmsg until syslogd has started, then openlog()
|
||||||
* and continue logging as a regular daemon.
|
* and continue logging as a regular daemon.
|
||||||
@@ -119,8 +135,16 @@ void logit(int prio, const char *fmt, ...)
|
|||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (in_container() || !(fp = fopen("/dev/kmsg", "w"))) {
|
if (in_container() || !(fp = fopen("/dev/kmsg", "w"))) {
|
||||||
vfprintf(stderr, fmt, ap);
|
static char buf[512];
|
||||||
fputs("\n", stderr);
|
time_t now;
|
||||||
|
size_t pos;
|
||||||
|
|
||||||
|
now = time(NULL);
|
||||||
|
pos = (int)strftime(buf, sizeof(buf), "%FT%T", localtime(&now));
|
||||||
|
pos += snprintf(&buf[pos], sizeof(buf) - pos, " [%s]: ", l2s(prio));
|
||||||
|
vsnprintf(&buf[pos], sizeof(buf) - pos, fmt, ap);
|
||||||
|
strlcat(buf, "\n", sizeof(buf));
|
||||||
|
fputs(buf, stderr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* Finit daemon log functions
|
/* Finit daemon log functions
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -31,26 +31,55 @@
|
|||||||
#define LOG_CONSOLE (14<<3)
|
#define LOG_CONSOLE (14<<3)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef __FINIT__
|
||||||
|
#include <err.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
extern int debug;
|
||||||
|
|
||||||
|
static __attribute__ ((format (printf, 1, 2))) inline void dbg(char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
if (!debug)
|
||||||
|
return;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
#define info(fmt, args...) warnx(fmt, ##args)
|
||||||
|
#define note(fmt, args...) warnx(fmt, ##args)
|
||||||
|
#else
|
||||||
/*
|
/*
|
||||||
* Developer error and debug messages, otherwise --> use logit() <--
|
* General log macros, similar to those used by initctl. Initially intended
|
||||||
* ~~~~~~~~~~~
|
* only for bridging client.c in Finit and initctl.
|
||||||
* All of these prepend the function, so only use for critical warnings
|
*/
|
||||||
* errors and debug messages. For all other user messages, see logit()
|
#define dbg(fmt, args...) logit(LOG_DEBUG, "%s():" fmt, __func__, ##args)
|
||||||
*
|
#define info(fmt, args...) logit(LOG_INFO, "%s():" fmt, __func__, ##args)
|
||||||
* The default log level is LOG_NOTICE. To toggle LOG_DEBUG messages,
|
#define note(fmt, args...) logit(LOG_NOTICE, "%s():" fmt, __func__, ##args)
|
||||||
* use `initctl debug` or add `debug` to the kernel cmdline.
|
#define warnx(fmt, args...) logit(LOG_WARNING, "%s():" fmt, __func__, ##args)
|
||||||
|
#define warn(fmt, args...) logit(LOG_WARNING, "%s():" fmt ": %s", __func__, ##args, strerror(errno))
|
||||||
|
#define errx(rc, fmt, args...) logit(LOG_ERR, "%s():" fmt, __func__, ##args)
|
||||||
|
#define err(rc, fmt, args...) logit(LOG_ERR, "%s():" fmt ": %s", __func__, ##args, strerror(errno))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DEPRECATED developer error and debug messages, please migrate to above!
|
||||||
|
* Will be removed without further warning in a future Finit release.
|
||||||
*/
|
*/
|
||||||
#define _d(fmt, args...) logit(LOG_DEBUG, "%s():" fmt, __func__, ##args)
|
#define _d(fmt, args...) logit(LOG_DEBUG, "%s():" fmt, __func__, ##args)
|
||||||
#define _w(fmt, args...) logit(LOG_WARNING, "%s():" fmt, __func__, ##args)
|
#define _w(fmt, args...) logit(LOG_WARNING, "%s():" fmt, __func__, ##args)
|
||||||
#define _e(fmt, args...) logit(LOG_ERR, "%s():" fmt, __func__, ##args)
|
#define _e(fmt, args...) logit(LOG_ERR, "%s():" fmt, __func__, ##args)
|
||||||
#define _pe(fmt, args...) logit(LOG_ERR, "%s():" fmt ": %s", __func__, ##args, strerror(errno))
|
#define _pe(fmt, args...) logit(LOG_ERR, "%s():" fmt ": %s", __func__, ##args, strerror(errno))
|
||||||
|
|
||||||
void log_init (void);
|
void log_init (void);
|
||||||
void log_exit (void);
|
void log_exit (void);
|
||||||
|
|
||||||
void log_debug (void);
|
void log_debug(void);
|
||||||
|
|
||||||
void logit (int prio, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
void logit (int prio, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
void flog (char *file, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
void flog (char *file, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* FINIT_LOG_H_ */
|
#endif /* FINIT_LOG_H_ */
|
||||||
|
|||||||
+8
-3
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2018-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -208,8 +208,13 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ident)
|
if (!ident) {
|
||||||
ident = getenv("LOGNAME") ?: getenv("USER");
|
ident = getenv("LOGNAME");
|
||||||
|
if (!ident)
|
||||||
|
ident = getenv("USER");
|
||||||
|
if (!ident)
|
||||||
|
ident = PACKAGE_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
if (optind < argc) {
|
if (optind < argc) {
|
||||||
size_t pos = 0, len = sizeof(buf);
|
size_t pos = 0, len = sizeof(buf);
|
||||||
|
|||||||
+3
-4
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2018-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -49,7 +49,6 @@ static int recreate(char *path, mode_t mode, uid_t uid, gid_t gid)
|
|||||||
*/
|
*/
|
||||||
int logrotate(char *file, int num, off_t sz)
|
int logrotate(char *file, int num, off_t sz)
|
||||||
{
|
{
|
||||||
int cnt;
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if (stat(file, &st))
|
if (stat(file, &st))
|
||||||
@@ -60,6 +59,7 @@ int logrotate(char *file, int num, off_t sz)
|
|||||||
size_t len = strlen(file) + 10 + 1;
|
size_t len = strlen(file) + 10 + 1;
|
||||||
char ofile[len];
|
char ofile[len];
|
||||||
char nfile[len];
|
char nfile[len];
|
||||||
|
int cnt;
|
||||||
|
|
||||||
/* First age zipped log files */
|
/* First age zipped log files */
|
||||||
for (cnt = num; cnt > 2; cnt--) {
|
for (cnt = num; cnt > 2; cnt--) {
|
||||||
@@ -97,8 +97,7 @@ int logrotate(char *file, int num, off_t sz)
|
|||||||
} else {
|
} else {
|
||||||
fallback:
|
fallback:
|
||||||
if (truncate(file, 0))
|
if (truncate(file, 0))
|
||||||
syslog(LOG_ERR, "Failed truncating %s during logrotate: %s",
|
syslog(LOG_ERR, "Failed truncating %s: %s", file, strerror(errno));
|
||||||
file, strerror(errno));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
/* Handle MD arrays
|
/* Handle MD arrays
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
+3
-2
@@ -1,6 +1,6 @@
|
|||||||
/* Mount and unmount helpers
|
/* Mount and unmount helpers
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -97,13 +97,14 @@ static int unmount(const char *target)
|
|||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
dbg("Unmounting %s", target);
|
||||||
|
|
||||||
rc = umount(target);
|
rc = umount(target);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
if (errno != EBUSY)
|
if (errno != EBUSY)
|
||||||
print(2, "Failed unmounting %s, error %d: %s", target, errno, strerror(errno));
|
print(2, "Failed unmounting %s, error %d: %s", target, errno, strerror(errno));
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
print(0, "Unmounting %s", target);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* PID and PID file helpers
|
/* PID and PID file helpers
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||||
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -149,6 +149,8 @@ int pid_file_create(svc_t *svc)
|
|||||||
|
|
||||||
int pid_file_set(svc_t *svc, char *file, int not)
|
int pid_file_set(svc_t *svc, char *file, int not)
|
||||||
{
|
{
|
||||||
|
char buf[sizeof(svc->pidfile)];
|
||||||
|
|
||||||
if (!file) {
|
if (!file) {
|
||||||
file = pid_file(svc);
|
file = pid_file(svc);
|
||||||
if (!file)
|
if (!file)
|
||||||
@@ -165,7 +167,9 @@ int pid_file_set(svc_t *svc, char *file, int not)
|
|||||||
not = 1;
|
not = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_runpath(file, &svc->pidfile[not], sizeof(svc->pidfile) - not);
|
de_dotdot(file);
|
||||||
|
pid_runpath(file, buf, sizeof(buf));
|
||||||
|
strlcpy(&svc->pidfile[not], buf, sizeof(svc->pidfile) - not);
|
||||||
if (not)
|
if (not)
|
||||||
svc->pidfile[0] = '!';
|
svc->pidfile[0] = '!';
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* PID and PID file helpers
|
/* PID and PID file helpers
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||||
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -51,6 +51,7 @@ static inline char *pid_runpath(const char *file, char *path, size_t len)
|
|||||||
{
|
{
|
||||||
static char *prefix = "/var/run";
|
static char *prefix = "/var/run";
|
||||||
static int unknown = 1;
|
static int unknown = 1;
|
||||||
|
char *ptr;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (unknown) {
|
if (unknown) {
|
||||||
@@ -59,14 +60,13 @@ static inline char *pid_runpath(const char *file, char *path, size_t len)
|
|||||||
unknown = 0;
|
unknown = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strncmp(file, "/var/run/", 9))
|
ptr = strstr(file, "/run/");
|
||||||
file += 9;
|
if (ptr)
|
||||||
else if (!strncmp(file, "/run/", 5))
|
file = ptr + 5;
|
||||||
file += 5;
|
|
||||||
|
|
||||||
rc = paste(path, len, prefix, file);
|
rc = paste(path, len, prefix, file);
|
||||||
if (rc < 0 || (size_t)rc >= len)
|
if (rc < 0 || (size_t)rc >= len)
|
||||||
_e("File path '%s' truncated, should end with '%s'", path, file);
|
err(1, "File path '%s' truncated, should end with '%s'", path, file);
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|||||||
+144
-27
@@ -1,6 +1,6 @@
|
|||||||
/* Plugin based services architecture for finit
|
/* Plugin based services architecture for finit
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -42,6 +42,7 @@
|
|||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
#include "private.h"
|
#include "private.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
|
#include "sig.h"
|
||||||
|
|
||||||
#define is_io_plugin(p) ((p)->io.cb && (p)->io.fd > 0)
|
#define is_io_plugin(p) ((p)->io.cb && (p)->io.fd > 0)
|
||||||
#define SEARCH_PLUGIN(str) \
|
#define SEARCH_PLUGIN(str) \
|
||||||
@@ -50,7 +51,8 @@
|
|||||||
return p; \
|
return p; \
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *plugpath = NULL; /* Set by first load. */
|
static int plugloaded = 0; /* Set while plugins are loaded */
|
||||||
|
static char *plugpath = NULL; /* Set by first load. */
|
||||||
static TAILQ_HEAD(plugin_head, plugin) plugins = TAILQ_HEAD_INITIALIZER(plugins);
|
static TAILQ_HEAD(plugin_head, plugin) plugins = TAILQ_HEAD_INITIALIZER(plugins);
|
||||||
|
|
||||||
#ifndef ENABLE_STATIC
|
#ifndef ENABLE_STATIC
|
||||||
@@ -95,7 +97,7 @@ int plugin_register(plugin_t *plugin)
|
|||||||
|
|
||||||
/* Already registered? */
|
/* Already registered? */
|
||||||
if (plugin_find(plugin->name)) {
|
if (plugin_find(plugin->name)) {
|
||||||
_d("... %s already loaded", plugin->name);
|
dbg("... %s already loaded", plugin->name);
|
||||||
free(plugin->name);
|
free(plugin->name);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -120,10 +122,10 @@ int plugin_unregister(plugin_t *plugin)
|
|||||||
#ifndef ENABLE_STATIC
|
#ifndef ENABLE_STATIC
|
||||||
TAILQ_REMOVE(&plugins, plugin, link);
|
TAILQ_REMOVE(&plugins, plugin, link);
|
||||||
|
|
||||||
_d("%s exiting ...", plugin->name);
|
dbg("%s exiting ...", plugin->name);
|
||||||
free(plugin->name);
|
free(plugin->name);
|
||||||
#else
|
#else
|
||||||
_d("Finit built statically, cannot unload %s ...", plugin->name);
|
dbg("Finit built statically, cannot unload %s ...", plugin->name);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -158,8 +160,8 @@ plugin_t *plugin_find(char *name)
|
|||||||
SEARCH_PLUGIN(name);
|
SEARCH_PLUGIN(name);
|
||||||
|
|
||||||
if (plugpath && name[0] != '/') {
|
if (plugpath && name[0] != '/') {
|
||||||
int noext;
|
|
||||||
char path[CMD_SIZE];
|
char path[CMD_SIZE];
|
||||||
|
int noext;
|
||||||
|
|
||||||
noext = strcmp(name + strlen(name) - 3, ".so");
|
noext = strcmp(name + strlen(name) - 3, ".so");
|
||||||
snprintf(path, sizeof(path), "%s%s%s%s", plugpath,
|
snprintf(path, sizeof(path), "%s%s%s%s", plugpath,
|
||||||
@@ -195,22 +197,73 @@ int plugin_exists(hook_point_t no)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(HAVE_HOOK_SCRIPTS_PLUGIN) && defined(PLUGIN_HOOK_SCRIPTS_PATH)
|
||||||
|
#define CHOOSE(x, y) y
|
||||||
|
static const char *hscript_paths[] = HOOK_TYPES;
|
||||||
|
#undef CHOOSE
|
||||||
|
|
||||||
|
void plugin_script_run(hook_point_t no)
|
||||||
|
{
|
||||||
|
const char *hook_name = hscript_paths[no];
|
||||||
|
const char *env[] = {
|
||||||
|
"FINIT_HOOK_NAME", hook_name,
|
||||||
|
"FINIT_SHUTDOWN", NULL,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
char path[CMD_SIZE] = "";
|
||||||
|
|
||||||
|
strlcat(path, PLUGIN_HOOK_SCRIPTS_PATH, sizeof(path));
|
||||||
|
strlcat(path, hook_name + 4, sizeof(path));
|
||||||
|
|
||||||
|
if (no >= HOOK_SHUTDOWN) {
|
||||||
|
switch (halt) {
|
||||||
|
case SHUT_OFF:
|
||||||
|
env[3] = "poweroff";
|
||||||
|
break;
|
||||||
|
case SHUT_HALT:
|
||||||
|
env[3] = "halt";
|
||||||
|
break;
|
||||||
|
case SHUT_REBOOT:
|
||||||
|
env[3] = "reboot";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
env[2] = NULL;
|
||||||
|
|
||||||
|
run_parts(path, NULL, env, 0);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void plugin_script_run(hook_point_t no)
|
||||||
|
{
|
||||||
|
(void)no;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Some hooks are called with a fixed argument */
|
/* Some hooks are called with a fixed argument */
|
||||||
void plugin_run_hook(hook_point_t no, void *arg)
|
void plugin_run_hook(hook_point_t no, void *arg)
|
||||||
{
|
{
|
||||||
plugin_t *p, *tmp;
|
plugin_t *p, *tmp;
|
||||||
|
|
||||||
|
#ifdef HAVE_HOOK_SCRIPTS_PLUGIN
|
||||||
|
if (!cond_is_available() && !plugloaded) {
|
||||||
|
dbg("conditions not available, calling script based hooks only!");
|
||||||
|
plugin_script_run(no);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
PLUGIN_ITERATOR(p, tmp) {
|
PLUGIN_ITERATOR(p, tmp) {
|
||||||
if (p->hook[no].cb) {
|
if (p->hook[no].cb) {
|
||||||
_d("Calling %s hook n:o %d (arg: %p) ...", basename(p->name), no, arg ?: "NIL");
|
dbg("Calling %s hook n:o %d (arg: %p) ...", basename(p->name), no, arg ?: "NIL");
|
||||||
p->hook[no].cb(arg ? arg : p->hook[no].arg);
|
p->hook[no].cb(arg ? arg : p->hook[no].arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Conditions are stored in /run, so don't try to signal
|
/*
|
||||||
|
* Conditions are stored in /run, so don't try to signal
|
||||||
* conditions for any hooks before filesystems have been
|
* conditions for any hooks before filesystems have been
|
||||||
* mounted. */
|
* mounted.
|
||||||
if (no >= HOOK_MOUNT_ERROR)
|
*/
|
||||||
|
if (cond_is_available() && no >= HOOK_BASEFS_UP && no <= HOOK_SHUTDOWN)
|
||||||
cond_set_oneshot(hook_cond[no]);
|
cond_set_oneshot(hook_cond[no]);
|
||||||
|
|
||||||
service_step_all(SVC_TYPE_RUNTASK);
|
service_step_all(SVC_TYPE_RUNTASK);
|
||||||
@@ -235,7 +288,7 @@ static void generic_io_cb(uev_t *w, void *arg, int events)
|
|||||||
/* Stop watcher, callback may close descriptor on us ... */
|
/* Stop watcher, callback may close descriptor on us ... */
|
||||||
uev_io_stop(w);
|
uev_io_stop(w);
|
||||||
|
|
||||||
_d("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);
|
p->io.cb(p->io.arg, w->fd, events);
|
||||||
|
|
||||||
/* Update fd, may be changed by plugin callback, e.g., if FIFO */
|
/* Update fd, may be changed by plugin callback, e.g., if FIFO */
|
||||||
@@ -248,9 +301,9 @@ int plugin_io_init(plugin_t *p)
|
|||||||
if (!is_io_plugin(p))
|
if (!is_io_plugin(p))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
_d("Initializing plugin %s for I/O", basename(p->name));
|
dbg("Initializing plugin %s for I/O", basename(p->name));
|
||||||
if (uev_io_init(ctx, &p->watcher, generic_io_cb, p, p->io.fd, p->io.flags)) {
|
if (uev_io_init(ctx, &p->watcher, generic_io_cb, p, p->io.fd, p->io.flags)) {
|
||||||
_e("Failed setting up I/O plugin %s", basename(p->name));
|
warn("Failed setting up I/O plugin %s", basename(p->name));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,8 +313,8 @@ int plugin_io_init(plugin_t *p)
|
|||||||
/* Setup any I/O callbacks for plugins that use them */
|
/* Setup any I/O callbacks for plugins that use them */
|
||||||
static int init_plugins(uev_ctx_t *ctx)
|
static int init_plugins(uev_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
int fail = 0;
|
|
||||||
plugin_t *p, *tmp;
|
plugin_t *p, *tmp;
|
||||||
|
int fail = 0;
|
||||||
|
|
||||||
PLUGIN_ITERATOR(p, tmp) {
|
PLUGIN_ITERATOR(p, tmp) {
|
||||||
if (plugin_io_init(p))
|
if (plugin_io_init(p))
|
||||||
@@ -302,16 +355,18 @@ static int load_one(char *path, char *name)
|
|||||||
noext = strcmp(name + strlen(name) - 3, ".so");
|
noext = strcmp(name + strlen(name) - 3, ".so");
|
||||||
snprintf(sofile, sizeof(sofile), "%s/%s%s", path, name, noext ? ".so" : "");
|
snprintf(sofile, sizeof(sofile), "%s/%s%s", path, name, noext ? ".so" : "");
|
||||||
|
|
||||||
_d("Loading plugin %s ...", basename(sofile));
|
dbg("Loading plugin %s ...", sofile);
|
||||||
handle = dlopen(sofile, RTLD_LAZY | RTLD_LOCAL);
|
handle = dlopen(sofile, RTLD_LAZY | RTLD_LOCAL);
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
_e("Failed loading plugin %s: %s", sofile, dlerror());
|
char *error = dlerror();
|
||||||
|
|
||||||
|
warn("Failed loading plugin %s: %s", sofile, error ? error : "unknown error");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
plugin = TAILQ_LAST(&plugins, plugin_head);
|
plugin = TAILQ_LAST(&plugins, plugin_head);
|
||||||
if (!plugin) {
|
if (!plugin) {
|
||||||
_e("Plugin %s failed to register, unloading from memory", sofile);
|
warn("Plugin %s failed to register, unloading from memory", sofile);
|
||||||
dlclose(handle);
|
dlclose(handle);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -338,9 +393,9 @@ static void check_plugin_depends(plugin_t *plugin)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < PLUGIN_DEP_MAX && plugin->depends[i]; i++) {
|
for (i = 0; i < PLUGIN_DEP_MAX && plugin->depends[i]; i++) {
|
||||||
// _d("Plugin %s depends on %s ...", plugin->name, plugin->depends[i]);
|
// dbg("Plugin %s depends on %s ...", plugin->name, plugin->depends[i]);
|
||||||
if (plugin_find(plugin->depends[i])) {
|
if (plugin_find(plugin->depends[i])) {
|
||||||
// _d("OK plugin %s was already loaded.", plugin->depends[i]);
|
// dbg("OK plugin %s was already loaded.", plugin->depends[i]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,13 +405,15 @@ static void check_plugin_depends(plugin_t *plugin)
|
|||||||
|
|
||||||
static int load_plugins(char *path)
|
static int load_plugins(char *path)
|
||||||
{
|
{
|
||||||
|
struct dirent *entry;
|
||||||
int fail = 0;
|
int fail = 0;
|
||||||
DIR *dp;
|
DIR *dp;
|
||||||
struct dirent *entry;
|
|
||||||
|
|
||||||
dp = opendir(path);
|
dp = opendir(path);
|
||||||
if (!dp) {
|
if (!dp) {
|
||||||
_e("Failed, cannot open plugin directory %s: %s", path, strerror(errno));
|
if (errno == ENOENT)
|
||||||
|
return 0;
|
||||||
|
warn("Failed, cannot open plugin directory %s: %s", path, strerror(errno));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
plugpath = path;
|
plugpath = path;
|
||||||
@@ -381,14 +438,70 @@ static int load_plugins(char *path)
|
|||||||
}
|
}
|
||||||
#endif /* ENABLE_STATIC */
|
#endif /* ENABLE_STATIC */
|
||||||
|
|
||||||
|
int plugin_list(char *buf, size_t len)
|
||||||
|
{
|
||||||
|
#ifndef ENABLE_STATIC
|
||||||
|
plugin_t *p, *tmp;
|
||||||
|
|
||||||
|
buf[0] = 0;
|
||||||
|
PLUGIN_ITERATOR(p, tmp) {
|
||||||
|
if (buf[0])
|
||||||
|
strlcat(buf, " ", len);
|
||||||
|
strlcat(buf, p->name, len);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
buf[0] = 0;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int plugin_deps(char *buf, size_t len)
|
||||||
|
{
|
||||||
|
#ifndef ENABLE_STATIC
|
||||||
|
plugin_t *p;
|
||||||
|
|
||||||
|
p = plugin_find(buf);
|
||||||
|
buf[0] = 0;
|
||||||
|
if (p) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < PLUGIN_DEP_MAX; i++) {
|
||||||
|
if (!p->depends[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (buf[0])
|
||||||
|
strlcat(buf, " ", len);
|
||||||
|
strlcat(buf, p->depends[i], len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
buf[0] = 0;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int plugin_init(uev_ctx_t *ctx)
|
int plugin_init(uev_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
int fail = 1;
|
load_plugins(PLUGIN_PATH);
|
||||||
|
|
||||||
if (!load_plugins(PLUGIN_PATH))
|
#ifdef EXTERNAL_PLUGIN_PATH
|
||||||
fail = init_plugins(ctx);
|
char *paths = strdup(EXTERNAL_PLUGIN_PATH);
|
||||||
|
char *path;
|
||||||
|
|
||||||
return fail;
|
if (paths) {
|
||||||
|
dbg("Loading external plugins from %s ...", paths);
|
||||||
|
path = strtok(paths, ":");
|
||||||
|
while (path) {
|
||||||
|
load_plugins(path);
|
||||||
|
path = strtok(NULL, ":");
|
||||||
|
}
|
||||||
|
free(paths);
|
||||||
|
}
|
||||||
|
|
||||||
|
plugloaded = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return init_plugins(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void plugin_exit(void)
|
void plugin_exit(void)
|
||||||
@@ -397,9 +510,13 @@ void plugin_exit(void)
|
|||||||
plugin_t *p, *tmp;
|
plugin_t *p, *tmp;
|
||||||
|
|
||||||
PLUGIN_ITERATOR(p, tmp) {
|
PLUGIN_ITERATOR(p, tmp) {
|
||||||
if (dlclose(p->handle))
|
if (dlclose(p->handle)) {
|
||||||
_e("Failed: unloading plugin %s: %s", p->name, dlerror());
|
char *error = dlerror();
|
||||||
|
warn("Failed unloading plugin %s: %s", p->name, error ? error : "unknown error");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
plugloaded = 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-1
@@ -1,6 +1,6 @@
|
|||||||
/* Plugin based services architecture for finit
|
/* Plugin based services architecture for finit
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -72,6 +72,7 @@
|
|||||||
CHOOSE(HOOK_MOUNT_ERROR, "hook/mount/error"), \
|
CHOOSE(HOOK_MOUNT_ERROR, "hook/mount/error"), \
|
||||||
CHOOSE(HOOK_MOUNT_POST, "hook/mount/post"), \
|
CHOOSE(HOOK_MOUNT_POST, "hook/mount/post"), \
|
||||||
CHOOSE(HOOK_BASEFS_UP, "hook/mount/all"), \
|
CHOOSE(HOOK_BASEFS_UP, "hook/mount/all"), \
|
||||||
|
CHOOSE(HOOK_SVC_PLUGIN, "hook/svc/plugin"), \
|
||||||
CHOOSE(HOOK_NETWORK_UP, "hook/net/up"), \
|
CHOOSE(HOOK_NETWORK_UP, "hook/net/up"), \
|
||||||
CHOOSE(HOOK_SVC_UP, "hook/svc/up"), \
|
CHOOSE(HOOK_SVC_UP, "hook/svc/up"), \
|
||||||
CHOOSE(HOOK_SYSTEM_UP, "hook/sys/up"), \
|
CHOOSE(HOOK_SYSTEM_UP, "hook/sys/up"), \
|
||||||
@@ -81,7 +82,10 @@
|
|||||||
CHOOSE(HOOK_RUNLEVEL_CHANGE, "nop"), \
|
CHOOSE(HOOK_RUNLEVEL_CHANGE, "nop"), \
|
||||||
\
|
\
|
||||||
/* Shutdown hooks, runlevel [06] */ \
|
/* Shutdown hooks, runlevel [06] */ \
|
||||||
|
CHOOSE(HOOK_NETWORK_DN, "hook/net/down"), \
|
||||||
CHOOSE(HOOK_SHUTDOWN, "hook/sys/shutdown"), \
|
CHOOSE(HOOK_SHUTDOWN, "hook/sys/shutdown"), \
|
||||||
|
CHOOSE(HOOK_SVC_DN, "hook/svc/down"), \
|
||||||
|
CHOOSE(HOOK_SYS_DN, "hook/sys/down"), \
|
||||||
CHOOSE(HOOK_MAX_NUM, "nop") \
|
CHOOSE(HOOK_MAX_NUM, "nop") \
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,6 +150,9 @@ typedef struct plugin {
|
|||||||
/* Public plugin API */
|
/* Public plugin API */
|
||||||
int plugin_io_init (plugin_t *plugin);
|
int plugin_io_init (plugin_t *plugin);
|
||||||
|
|
||||||
|
int plugin_list (char *buf, size_t len);
|
||||||
|
int plugin_deps (char *buf, size_t len);
|
||||||
|
|
||||||
int plugin_register (plugin_t *plugin);
|
int plugin_register (plugin_t *plugin);
|
||||||
int plugin_unregister (plugin_t *plugin);
|
int plugin_unregister (plugin_t *plugin);
|
||||||
|
|
||||||
|
|||||||
+25
-11
@@ -1,7 +1,7 @@
|
|||||||
/* Private header file for main finit daemon, not for plugins
|
/* Private header file for main finit daemon, not for plugins
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||||
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -29,20 +29,34 @@
|
|||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
|
||||||
#define SERVICE_INTERVAL_DEFAULT 300000 /* 5 mins */
|
#define SERVICE_INTERVAL_DEFAULT 300000 /* 5 mins */
|
||||||
extern int service_interval;
|
#define MATCH_CMD(l, c, x) \
|
||||||
|
(!strncasecmp(l, c, strlen(c)) && (x = (l) + strlen(c)))
|
||||||
|
|
||||||
int api_init (uev_ctx_t *ctx);
|
#define IS_RESERVED_RUNLEVEL(l) (l == 0 || l == 6 || l == INIT_LEVEL)
|
||||||
int api_exit (void);
|
|
||||||
|
|
||||||
void service_monitor (pid_t lost, int status);
|
extern char *finit_conf;
|
||||||
|
extern char *finit_rcsd;
|
||||||
|
extern svc_t *wdog;
|
||||||
|
extern int service_interval;
|
||||||
|
extern char *fsck_mode;
|
||||||
|
extern char *fsck_repair;
|
||||||
|
|
||||||
const char *plugin_hook_str(hook_point_t no);
|
int api_init (uev_ctx_t *ctx);
|
||||||
int plugin_exists (hook_point_t no);
|
int api_exit (void);
|
||||||
void plugin_run_hook (hook_point_t no, void *arg);
|
void conf_flush_events(void);
|
||||||
void plugin_run_hooks (hook_point_t no);
|
|
||||||
|
|
||||||
int plugin_init (uev_ctx_t *ctx);
|
void service_monitor (pid_t lost, int status);
|
||||||
void plugin_exit (void);
|
void service_notify_cb(uev_t *w, void *arg, int events);
|
||||||
|
|
||||||
|
const char *plugin_hook_str (hook_point_t no);
|
||||||
|
int plugin_exists (hook_point_t no);
|
||||||
|
|
||||||
|
void plugin_run_hook (hook_point_t no, void *arg);
|
||||||
|
void plugin_run_hooks (hook_point_t no);
|
||||||
|
void plugin_script_run(hook_point_t no);
|
||||||
|
|
||||||
|
int plugin_init (uev_ctx_t *ctx);
|
||||||
|
void plugin_exit (void);
|
||||||
|
|
||||||
#endif /* FINIT_PRIVATE_H_ */
|
#endif /* FINIT_PRIVATE_H_ */
|
||||||
|
|
||||||
|
|||||||
+22
-10
@@ -1,6 +1,6 @@
|
|||||||
/* reboot, halt, poweroff, shutdown, suspend for finit
|
/* reboot, halt, poweroff, shutdown, suspend for finit
|
||||||
*
|
*
|
||||||
* Copyright (c) 2009-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2009-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -43,6 +43,8 @@ static cmd_t cmd = CMD_UNKNOWN;
|
|||||||
static char *msg = NULL;
|
static char *msg = NULL;
|
||||||
|
|
||||||
/* initctl API */
|
/* initctl API */
|
||||||
|
extern int timeout;
|
||||||
|
|
||||||
extern int do_reboot (char *arg);
|
extern int do_reboot (char *arg);
|
||||||
extern int do_halt (char *arg);
|
extern int do_halt (char *arg);
|
||||||
extern int do_poweroff(char *arg);
|
extern int do_poweroff(char *arg);
|
||||||
@@ -103,12 +105,13 @@ static int usage(int rc)
|
|||||||
{
|
{
|
||||||
fprintf(stderr, "Usage: %s [OPTIONS]\n\n"
|
fprintf(stderr, "Usage: %s [OPTIONS]\n\n"
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
" --help This help text\n"
|
" -?, --help This help text\n"
|
||||||
" -f, --force Force unsafe %s now, do not contact the init system.\n"
|
" -f, --force Force unsafe %s now, do not contact the init system.\n"
|
||||||
" --halt Halt system, regardless of how the command is called.\n"
|
" --halt Halt system, regardless of how the command is called.\n"
|
||||||
" -h Halt or power off after shutdown.\n"
|
" -h Halt or power off after shutdown.\n"
|
||||||
" -P, --poweroff Power-off system, regardless of how the command is called.\n"
|
" -P, --poweroff Power-off system, regardless of how the command is called.\n"
|
||||||
" -r, --reboot Reboot system, regardless of how the command is called.\n"
|
" -r, --reboot Reboot system, regardless of how the command is called.\n"
|
||||||
|
" -t, --timeout=SEC Force reboot/shutdown after a given timeout\n"
|
||||||
"\n", prognm, msg);
|
"\n", prognm, msg);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
@@ -116,20 +119,22 @@ static int usage(int rc)
|
|||||||
|
|
||||||
int reboot_main(int argc, char *argv[])
|
int reboot_main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int c, force = 0;
|
|
||||||
struct option long_options[] = {
|
struct option long_options[] = {
|
||||||
{"help", 0, NULL, 'h'},
|
{"help", 0, NULL, '?'},
|
||||||
{"force", 0, NULL, 'f'},
|
{"force", 0, NULL, 'f'},
|
||||||
{"halt", 0, NULL, 'H'},
|
{"halt", 0, NULL, 'H'},
|
||||||
{"poweroff", 0, NULL, 'p'},
|
{"poweroff", 0, NULL, 'p'},
|
||||||
{"reboot", 0, NULL, 'r'},
|
{"reboot", 0, NULL, 'r'},
|
||||||
|
{"timeout", 1, NULL, 't'},
|
||||||
{NULL, 0, NULL, 0}
|
{NULL, 0, NULL, 0}
|
||||||
};
|
};
|
||||||
|
int c, force = 0;
|
||||||
|
int tmp;
|
||||||
|
|
||||||
/* Initial command taken from program name */
|
/* Initial command taken from program name */
|
||||||
transform(prognm);
|
transform(prognm);
|
||||||
|
|
||||||
while ((c = getopt_long(argc, argv, "h?fHPpr", long_options, NULL)) != EOF) {
|
while ((c = getopt_long(argc, argv, "h?fHPprt:", long_options, NULL)) != EOF) {
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case '?':
|
case '?':
|
||||||
return usage(0);
|
return usage(0);
|
||||||
@@ -152,6 +157,13 @@ int reboot_main(int argc, char *argv[])
|
|||||||
cmd = CMD_REBOOT;
|
cmd = CMD_REBOOT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 't':
|
||||||
|
tmp = atoi(optarg);
|
||||||
|
if (tmp < 1)
|
||||||
|
errx(1, "Invalid forced timeout value.");
|
||||||
|
timeout = tmp;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return usage(1);
|
return usage(1);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
/* Work queue helper functions
|
/* Work queue helper functions
|
||||||
*
|
*
|
||||||
* Copyright (c) 2018-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2018-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
/* Work queue helper functions
|
/* Work queue helper functions
|
||||||
*
|
*
|
||||||
* Copyright (c) 2018-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2018-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
+113
-55
@@ -1,6 +1,6 @@
|
|||||||
/* List and enable/disable service configurations
|
/* List and enable/disable service configurations
|
||||||
*
|
*
|
||||||
* Copyright (c) 2017-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2017-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -66,7 +66,7 @@ static int calc_width(char *arr[], size_t len)
|
|||||||
return width;
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_list(const char *path)
|
static void do_list(const char *path, char *title, int comma)
|
||||||
{
|
{
|
||||||
static int once = 0;
|
static int once = 0;
|
||||||
int width, num, prev;
|
int width, num, prev;
|
||||||
@@ -78,6 +78,7 @@ static void do_list(const char *path)
|
|||||||
|
|
||||||
if (!fexist(path))
|
if (!fexist(path))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dir = strdupa(path);
|
dir = strdupa(path);
|
||||||
if (!dir)
|
if (!dir)
|
||||||
return;
|
return;
|
||||||
@@ -88,6 +89,11 @@ static void do_list(const char *path)
|
|||||||
else
|
else
|
||||||
ptr = dir;
|
ptr = dir;
|
||||||
|
|
||||||
|
if (json) {
|
||||||
|
printf("%s\"%s\": \"%s\"", comma ? "," :"", title, path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (heading)
|
if (heading)
|
||||||
print_header("%s%s ", once ? "\n" : "", dir);
|
print_header("%s%s ", once ? "\n" : "", dir);
|
||||||
puts(ptr);
|
puts(ptr);
|
||||||
@@ -101,7 +107,7 @@ static void do_list(const char *path)
|
|||||||
if (gl.gl_pathc <= 0)
|
if (gl.gl_pathc <= 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (plain) {
|
if (plain && !json) {
|
||||||
if (heading)
|
if (heading)
|
||||||
print_header("%s%s ", once ? "\n" : "", path);
|
print_header("%s%s ", once ? "\n" : "", path);
|
||||||
once++;
|
once++;
|
||||||
@@ -119,8 +125,10 @@ static void do_list(const char *path)
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (heading)
|
if (heading && !json)
|
||||||
print_header("%s ", path);
|
print_header("%s ", path);
|
||||||
|
if (json)
|
||||||
|
printf("%s\"%s\": [", comma ? "," : "", title);
|
||||||
|
|
||||||
width = calc_width(gl.gl_pathv, gl.gl_pathc);
|
width = calc_width(gl.gl_pathv, gl.gl_pathc);
|
||||||
if (width <= 0)
|
if (width <= 0)
|
||||||
@@ -132,17 +140,24 @@ static void do_list(const char *path)
|
|||||||
|
|
||||||
prev = 0;
|
prev = 0;
|
||||||
for (i = 0; i < gl.gl_pathc; i++) {
|
for (i = 0; i < gl.gl_pathc; i++) {
|
||||||
if (i > 0 && !(i % num)) {
|
if (i > 0 && !(i % num) && !json) {
|
||||||
puts("");
|
puts("");
|
||||||
prev = 0;
|
prev = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prev)
|
if (prev)
|
||||||
printf(" ");
|
printf("%s", json ? "," : " ");
|
||||||
printf("%-*s", width, gl.gl_pathv[i]);
|
if (json)
|
||||||
|
printf("\"%s\"", gl.gl_pathv[i]);
|
||||||
|
else
|
||||||
|
printf("%-*s", width, gl.gl_pathv[i]);
|
||||||
prev++;
|
prev++;
|
||||||
}
|
}
|
||||||
puts("\n");
|
|
||||||
|
if (json)
|
||||||
|
fputs("]", stdout);
|
||||||
|
else
|
||||||
|
puts("\n");
|
||||||
|
|
||||||
done:
|
done:
|
||||||
globfree(&gl);
|
globfree(&gl);
|
||||||
@@ -151,29 +166,40 @@ done:
|
|||||||
int serv_list(char *arg)
|
int serv_list(char *arg)
|
||||||
{
|
{
|
||||||
char path[256];
|
char path[256];
|
||||||
|
int pre = 0;
|
||||||
|
|
||||||
if (arg && arg[0]) {
|
if (arg && arg[0]) {
|
||||||
paste(path, sizeof(path), FINIT_RCSD, arg);
|
paste(path, sizeof(path), finit_rcsd, arg);
|
||||||
if (fisdir(path)) {
|
if (fisdir(path)) {
|
||||||
do_list(path);
|
if (json)
|
||||||
|
fputs("[", stdout);
|
||||||
|
do_list(path, NULL, 0);
|
||||||
|
if (json)
|
||||||
|
fputs("]\n", stdout);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* fall back to list all */
|
/* fall back to list all */
|
||||||
}
|
}
|
||||||
|
|
||||||
paste(path, sizeof(path), FINIT_RCSD, "available");
|
if (json)
|
||||||
|
fputs("{", stdout);
|
||||||
|
|
||||||
|
paste(path, sizeof(path), finit_rcsd, "available");
|
||||||
if (fisdir(path))
|
if (fisdir(path))
|
||||||
do_list(path);
|
do_list(path, "available", pre++);
|
||||||
|
|
||||||
paste(path, sizeof(path), FINIT_RCSD, "enabled");
|
paste(path, sizeof(path), finit_rcsd, "enabled");
|
||||||
if (fisdir(path))
|
if (fisdir(path))
|
||||||
do_list(path);
|
do_list(path, "enabled", pre++);
|
||||||
|
|
||||||
if (fisdir(FINIT_RCSD))
|
if (fisdir(finit_rcsd))
|
||||||
do_list(FINIT_RCSD);
|
do_list(finit_rcsd, "static", pre++);
|
||||||
|
|
||||||
if (fexist(FINIT_CONF))
|
if (fexist(finit_conf))
|
||||||
do_list(FINIT_CONF);
|
do_list(finit_conf, "finit.conf", pre++);
|
||||||
|
|
||||||
|
if (json)
|
||||||
|
fputs("}\n", stdout);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -197,7 +223,7 @@ static char *conf(char *path, size_t len, char *name, int creat)
|
|||||||
char corr[40];
|
char corr[40];
|
||||||
|
|
||||||
if (!name || !name[0] || !strcmp(name, "finit") || !strcmp(name, "finit.conf")) {
|
if (!name || !name[0] || !strcmp(name, "finit") || !strcmp(name, "finit.conf")) {
|
||||||
strlcpy(path, FINIT_CONF, len);
|
strlcpy(path, finit_conf, len);
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,85 +232,117 @@ static char *conf(char *path, size_t len, char *name, int creat)
|
|||||||
name = corr;
|
name = corr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fisdir(FINIT_RCSD))
|
if (!fisdir(finit_rcsd))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
paste(path, len, FINIT_RCSD, "available/");
|
paste(path, len, finit_rcsd, "available/");
|
||||||
if (!fisdir(path)) {
|
if (!fisdir(path)) {
|
||||||
if (creat && mkdir(path, 0755) && errno != EEXIST)
|
if (creat && mkdir(path, 0755) && errno != EEXIST)
|
||||||
return NULL;
|
return NULL;
|
||||||
else
|
else
|
||||||
paste(path, len, FINIT_RCSD, name);
|
paste(path, len, finit_rcsd, name);
|
||||||
} else
|
} else
|
||||||
strlcat(path, name, len);
|
strlcat(path, name, len);
|
||||||
|
|
||||||
/* fall back to static service unless edit/create */
|
/* fall back to static service unless edit/create */
|
||||||
if (!creat && !fexist(path))
|
if (!creat && !fexist(path))
|
||||||
paste(path, len, FINIT_RCSD, name);
|
paste(path, len, finit_rcsd, name);
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
int serv_enable(char *arg)
|
int serv_enable(char *arg)
|
||||||
{
|
{
|
||||||
char corr[40];
|
char *serv, *ptr, *src, *dst;
|
||||||
char path[256];
|
size_t len;
|
||||||
int ena;
|
int rc;
|
||||||
|
|
||||||
if (!arg || !arg[0]) {
|
if (!arg || !arg[0]) {
|
||||||
WARNX("missing argument to enable, may be one of:");
|
WARNX("missing argument to enable, may be one of:");
|
||||||
return serv_list("available");
|
return serv_list("available");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strstr(arg, ".conf")) {
|
len = strlen(arg);
|
||||||
snprintf(corr, sizeof(corr), "%s.conf", arg);
|
serv = alloca(len + 6);
|
||||||
arg = corr;
|
if (!serv)
|
||||||
}
|
ERR(71, "failed allocating stack");
|
||||||
|
|
||||||
if (chdir(FINIT_RCSD))
|
strlcpy(serv, arg, len + 6);
|
||||||
ERR(72, "failed cd %s", FINIT_RCSD);
|
if (len < 6 || strcmp(&serv[len - 5], ".conf"))
|
||||||
|
strlcat(serv, ".conf", len + 6);
|
||||||
|
|
||||||
|
if (chdir(finit_rcsd))
|
||||||
|
ERR(72, "failed cd %s", finit_rcsd);
|
||||||
|
|
||||||
if (icreate && mkdir("enabled", 0755) && EEXIST != errno)
|
if (icreate && mkdir("enabled", 0755) && EEXIST != errno)
|
||||||
ERR(73, "failed creating %s/enabled directory", FINIT_RCSD);
|
ERR(73, "failed creating %s/enabled directory", finit_rcsd);
|
||||||
ena = !chdir("enabled"); /* System *may* have enabled/ dir. */
|
|
||||||
|
|
||||||
snprintf(path, sizeof(path), "%savailable/%s", ena ? "../" : "", arg);
|
if (asprintf(&src, "%s/available/%s", finit_rcsd, serv) == -1)
|
||||||
if (!fexist(path))
|
goto fail;
|
||||||
ERRX(72, "cannot find %s", conf(path, sizeof(path), arg, 0));
|
if (asprintf(&dst, "%s/enabled/%s", finit_rcsd, serv) == -1) {
|
||||||
|
free(src);
|
||||||
|
fail:
|
||||||
|
ERR(71, "failed allocating memory");
|
||||||
|
}
|
||||||
|
|
||||||
if (fexist(arg))
|
if (fexist(dst)) {
|
||||||
ERRX(1, "%s already enabled", arg);
|
WARNX("%s already enabled", arg);
|
||||||
|
rc = noerr ? 0 : 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
return symlink(path, arg) != 0;
|
/* check for template instantiation */
|
||||||
|
ptr = strchr(src, '@');
|
||||||
|
if (ptr)
|
||||||
|
strcpy(++ptr, ".conf");
|
||||||
|
|
||||||
|
if (!fexist(src)) {
|
||||||
|
WARNX("cannot find %s%s", ptr ? "template ": "", src);
|
||||||
|
rc = 72;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = symlink(src, dst);
|
||||||
|
if (rc)
|
||||||
|
WARN("failed enabling %s", arg);
|
||||||
|
done:
|
||||||
|
free(src);
|
||||||
|
free(dst);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int do_disable(char *arg, int check)
|
int do_disable(char *arg, int check)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
char corr[40];
|
size_t len;
|
||||||
|
char *serv;
|
||||||
|
|
||||||
if (!arg || !arg[0]) {
|
if (!arg || !arg[0]) {
|
||||||
WARNX("missing argument to disable, may be one of:");
|
WARNX("missing argument to disable, may be one of:");
|
||||||
return serv_list("enabled");
|
return serv_list("enabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strstr(arg, ".conf")) {
|
len = strlen(arg);
|
||||||
snprintf(corr, sizeof(corr), "%s.conf", arg);
|
serv = alloca(len + 6);
|
||||||
arg = corr;
|
if (!serv)
|
||||||
}
|
ERR(71, "failed allocating stack");
|
||||||
|
|
||||||
if (chdir(FINIT_RCSD))
|
strlcpy(serv, arg, len + 6);
|
||||||
ERR(72, "failed cd %s", FINIT_RCSD);
|
if (len < 6 || strcmp(&serv[len - 5], ".conf"))
|
||||||
|
strlcat(serv, ".conf", len + 6);
|
||||||
|
|
||||||
|
if (chdir(finit_rcsd))
|
||||||
|
ERR(72, "failed cd %s", finit_rcsd);
|
||||||
if (chdir("enabled")) /* System *may* have enabled/ dir. */
|
if (chdir("enabled")) /* System *may* have enabled/ dir. */
|
||||||
dbg("Failed changing to %s/enabled/: %s", FINIT_RCSD, strerror(errno));
|
dbg("Failed changing to %s/enabled/: %s", finit_rcsd, strerror(errno));
|
||||||
|
|
||||||
if (check && stat(arg, &st))
|
if (check && stat(serv, &st))
|
||||||
ERRX(6, "%s not (an) enabled (service).", arg);
|
ERRX(noerr ? 0 : 6, "%s not (an) enabled (service).", serv);
|
||||||
|
|
||||||
if (check && (st.st_mode & S_IFMT) == S_IFLNK)
|
if (check && (st.st_mode & S_IFMT) == S_IFLNK)
|
||||||
ERRX(1, "cannot disable %s, not a symlink.", arg);
|
ERRX(noerr ? 0 : 1, "cannot disable %s, not a symlink.", serv);
|
||||||
|
|
||||||
return remove(arg) != 0;
|
return remove(serv) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int serv_disable(char *arg)
|
int serv_disable(char *arg)
|
||||||
@@ -309,7 +367,7 @@ int serv_touch(char *arg)
|
|||||||
if (is_builtin(arg))
|
if (is_builtin(arg))
|
||||||
ERRX(4, "%s is a built-in service.", arg);
|
ERRX(4, "%s is a built-in service.", arg);
|
||||||
|
|
||||||
strlcpy(path, FINIT_CONF, sizeof(path));
|
strlcpy(path, finit_conf, sizeof(path));
|
||||||
fn = path;
|
fn = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,7 +449,7 @@ static int do_edit(char *arg, int creat)
|
|||||||
int serv_edit(char *arg)
|
int serv_edit(char *arg)
|
||||||
{
|
{
|
||||||
if (!arg || !arg[0]) {
|
if (!arg || !arg[0]) {
|
||||||
if (!yorn("Do you want to edit %s (y/N)? ", FINIT_CONF))
|
if (!yorn("Do you want to edit %s (y/N)? ", finit_conf))
|
||||||
return 0;
|
return 0;
|
||||||
arg = "";
|
arg = "";
|
||||||
}
|
}
|
||||||
@@ -449,7 +507,7 @@ int serv_delete(char *arg)
|
|||||||
if (!fn) {
|
if (!fn) {
|
||||||
if (is_builtin(arg))
|
if (is_builtin(arg))
|
||||||
ERRX(4, "%s is a built-in service.", arg);
|
ERRX(4, "%s is a built-in service.", arg);
|
||||||
ERRX(72, FINIT_RCSD " missing on system.");
|
ERRX(72, "%s missing on system.", finit_rcsd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fexist(fn))
|
if (!fexist(fn))
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
/* List and enable/disable service configurations
|
/* List and enable/disable service configurations
|
||||||
*
|
*
|
||||||
* Copyright (c) 2017-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2017-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
+666
-181
File diff suppressed because it is too large
Load Diff
+7
-1
@@ -1,7 +1,7 @@
|
|||||||
/* Finit service monitor, task starter and generic API for managing svc_t
|
/* Finit service monitor, task starter and generic API for managing svc_t
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||||
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -34,17 +34,23 @@ void service_unregister (svc_t *svc);
|
|||||||
void service_runtask_clean (void);
|
void service_runtask_clean (void);
|
||||||
void service_reload_dynamic (void);
|
void service_reload_dynamic (void);
|
||||||
void service_update_rdeps (void);
|
void service_update_rdeps (void);
|
||||||
|
void service_mark_unavail (void);
|
||||||
|
|
||||||
|
void service_ready_script (svc_t *svc); /* XXX: only for pidfile plugin before notify framework */
|
||||||
|
|
||||||
int service_timeout_after (svc_t *svc, int timeout, void (*cb)(svc_t *svc));
|
int service_timeout_after (svc_t *svc, int timeout, void (*cb)(svc_t *svc));
|
||||||
int service_timeout_cancel (svc_t *svc);
|
int service_timeout_cancel (svc_t *svc);
|
||||||
|
|
||||||
void service_forked (svc_t *svc);
|
void service_forked (svc_t *svc);
|
||||||
|
void service_ready (svc_t *svc);
|
||||||
|
|
||||||
|
int service_stop (svc_t *svc);
|
||||||
int service_step (svc_t *svc);
|
int service_step (svc_t *svc);
|
||||||
void service_step_all (int types);
|
void service_step_all (int types);
|
||||||
void service_worker (void *unused);
|
void service_worker (void *unused);
|
||||||
|
|
||||||
int service_completed (void);
|
int service_completed (void);
|
||||||
|
void service_notify_reconf (void);
|
||||||
|
|
||||||
void service_init (void);
|
void service_init (void);
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* Signal management - Be conservative with what finit responds to!
|
/* Signal management - Be conservative with what finit responds to!
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||||
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -97,8 +97,6 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "utmp-api.h"
|
#include "utmp-api.h"
|
||||||
|
|
||||||
extern svc_t *wdog;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Old-style SysV shutdown sends a setenv cmd INIT_HALT with "=HALT",
|
* Old-style SysV shutdown sends a setenv cmd INIT_HALT with "=HALT",
|
||||||
* "=POWERDOWN", or "" to cancel shutdown, before requesting change to
|
* "=POWERDOWN", or "" to cancel shutdown, before requesting change to
|
||||||
@@ -231,12 +229,12 @@ void do_iterate_proc(int (*cb)(int, void *), void *data)
|
|||||||
|
|
||||||
if (fgets(file, sizeof(file), fp)) {
|
if (fgets(file, sizeof(file), fp)) {
|
||||||
if (strstr(file, "gdbserver"))
|
if (strstr(file, "gdbserver"))
|
||||||
_d("Skipping %s ...", file);
|
dbg("Skipping %s ...", file);
|
||||||
else if (file[0] == '@')
|
else if (file[0] == '@')
|
||||||
_d("Skipping %s ...", &file[1]);
|
dbg("Skipping %s ...", &file[1]);
|
||||||
else
|
else
|
||||||
if (cb(pid, data)) {
|
if (cb(pid, data)) {
|
||||||
_d("PID %d is still alive (%s)", pid, file);
|
dbg("PID %d is still alive (%s)", pid, file);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -302,6 +300,7 @@ void do_shutdown(shutop_t op)
|
|||||||
sched_setscheduler(1, SCHED_RR, &sched_param);
|
sched_setscheduler(1, SCHED_RR, &sched_param);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
halt = op;
|
||||||
if (sdown)
|
if (sdown)
|
||||||
run_interactive(sdown, "Calling shutdown hook: %s", sdown);
|
run_interactive(sdown, "Calling shutdown hook: %s", sdown);
|
||||||
|
|
||||||
@@ -318,14 +317,19 @@ void do_shutdown(shutop_t op)
|
|||||||
do_iterate_proc(kill_cb, &signo);
|
do_iterate_proc(kill_cb, &signo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Exit plugins and API gracefully */
|
/* Exit plugins gracefully */
|
||||||
plugin_exit();
|
plugin_exit();
|
||||||
api_exit();
|
|
||||||
|
/* We can no longer act on conditions, activate script runner */
|
||||||
|
cond_exit();
|
||||||
|
|
||||||
/* Reap 'em */
|
/* Reap 'em */
|
||||||
while (waitpid(-1, NULL, WNOHANG) > 0)
|
while (waitpid(-1, NULL, WNOHANG) > 0)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
/* All services and (non-critical) processes have stopped. */
|
||||||
|
plugin_script_run(HOOK_SVC_DN);
|
||||||
|
|
||||||
if (in_cont) {
|
if (in_cont) {
|
||||||
if (osheading)
|
if (osheading)
|
||||||
logit(LOG_CONSOLE | LOG_NOTICE, "%s, shutting down container.", osheading);
|
logit(LOG_CONSOLE | LOG_NOTICE, "%s, shutting down container.", osheading);
|
||||||
@@ -351,6 +355,7 @@ void do_shutdown(shutop_t op)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Unmount any tmpfs before unmounting swap ... */
|
/* Unmount any tmpfs before unmounting swap ... */
|
||||||
|
print(0, "Unmounting filesystems ...");
|
||||||
unmount_tmpfs();
|
unmount_tmpfs();
|
||||||
fs_swapoff();
|
fs_swapoff();
|
||||||
|
|
||||||
@@ -371,8 +376,27 @@ void do_shutdown(shutop_t op)
|
|||||||
/* Call mdadm to mark any RAID array(s) as clean before halting. */
|
/* Call mdadm to mark any RAID array(s) as clean before halting. */
|
||||||
mdadm_wait();
|
mdadm_wait();
|
||||||
|
|
||||||
|
/* Last chance to run scripts (all .so plugins have exited already) */
|
||||||
|
print(0, "Calling hook/svc/down scripts ...");
|
||||||
|
plugin_script_run(HOOK_SYS_DN);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Optional reboot-delay, needed on systems running ubifs, jffs,
|
||||||
|
* or similar. From fileutils-4.0, sync(8); "On Linux, sync is
|
||||||
|
* only guaranteed to schedule the dirty blocks for writing; it
|
||||||
|
* can actually take a short time before all the blocks are
|
||||||
|
* finally written." -- https://linux.die.net/man/8/sync
|
||||||
|
*/
|
||||||
|
sync();
|
||||||
|
if (syncsec > 0) {
|
||||||
|
print(-1, "Reboot delay, waiting for filesystem sync, %d sec", syncsec);
|
||||||
|
do_sleep(syncsec);
|
||||||
|
print(0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* Reboot via watchdog or kernel, or shutdown? */
|
/* Reboot via watchdog or kernel, or shutdown? */
|
||||||
if (op == SHUT_REBOOT) {
|
if (op == SHUT_REBOOT) {
|
||||||
|
print(0, "Rebooting ...");
|
||||||
if (wdog && wdog->pid > 1) {
|
if (wdog && wdog->pid > 1) {
|
||||||
int timeout = 10;
|
int timeout = 10;
|
||||||
|
|
||||||
@@ -382,15 +406,15 @@ void do_shutdown(shutop_t op)
|
|||||||
do_sleep(1);
|
do_sleep(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("Rebooting ...");
|
dbg("Rebooting ...");
|
||||||
reboot(RB_AUTOBOOT);
|
reboot(RB_AUTOBOOT);
|
||||||
} else if (op == SHUT_OFF) {
|
} else if (op == SHUT_OFF) {
|
||||||
_d("Powering down ...");
|
print(0, "Powering down ...");
|
||||||
reboot(RB_POWER_OFF);
|
reboot(RB_POWER_OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Also fallback if any of the other two fails */
|
/* Also fallback if any of the other two fails */
|
||||||
_d("Halting ...");
|
print(0, "Halting ...");
|
||||||
reboot(RB_HALT_SYSTEM);
|
reboot(RB_HALT_SYSTEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,9 +423,14 @@ void do_shutdown(shutop_t op)
|
|||||||
*/
|
*/
|
||||||
static void sighup_cb(uev_t *w, void *arg, int events)
|
static void sighup_cb(uev_t *w, void *arg, int events)
|
||||||
{
|
{
|
||||||
_d("...");
|
dbg("...");
|
||||||
if (UEV_ERROR == events) {
|
if (UEV_ERROR == events) {
|
||||||
_e("Unrecoverable error in signal watcher");
|
errx(1, "Unrecoverable error in signal watcher");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_RESERVED_RUNLEVEL(runlevel)) {
|
||||||
|
warnx("SIGHUP ignored in runlevel S and 6.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,9 +449,9 @@ static void sighup_cb(uev_t *w, void *arg, int events)
|
|||||||
*/
|
*/
|
||||||
static void sigint_cb(uev_t *w, void *arg, int events)
|
static void sigint_cb(uev_t *w, void *arg, int events)
|
||||||
{
|
{
|
||||||
_d("...");
|
dbg("...");
|
||||||
if (UEV_ERROR == events) {
|
if (UEV_ERROR == events) {
|
||||||
_e("Unrecoverable error in signal watcher");
|
errx(1, "Unrecoverable error in signal watcher");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -436,9 +465,9 @@ static void sigint_cb(uev_t *w, void *arg, int events)
|
|||||||
*/
|
*/
|
||||||
static void sigpwr_cb(uev_t *w, void *arg, int events)
|
static void sigpwr_cb(uev_t *w, void *arg, int events)
|
||||||
{
|
{
|
||||||
_d("...");
|
dbg("...");
|
||||||
if (UEV_ERROR == events) {
|
if (UEV_ERROR == events) {
|
||||||
_e("Unrecoverable error in signal watcher");
|
errx(1, "Unrecoverable error in signal watcher");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,9 +479,14 @@ static void sigpwr_cb(uev_t *w, void *arg, int events)
|
|||||||
*/
|
*/
|
||||||
static void sigusr1_cb(uev_t *w, void *arg, int events)
|
static void sigusr1_cb(uev_t *w, void *arg, int events)
|
||||||
{
|
{
|
||||||
_d("...");
|
dbg("...");
|
||||||
if (UEV_ERROR == events) {
|
if (UEV_ERROR == events) {
|
||||||
_e("Unrecoverable error in signal watcher");
|
errx(1, "Unrecoverable error in signal watcher");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_RESERVED_RUNLEVEL(runlevel)) {
|
||||||
|
warnx("SIGUSR1 ignored in runlevel S and 6.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,9 +500,14 @@ static void sigusr1_cb(uev_t *w, void *arg, int events)
|
|||||||
*/
|
*/
|
||||||
static void sigusr2_cb(uev_t *w, void *arg, int events)
|
static void sigusr2_cb(uev_t *w, void *arg, int events)
|
||||||
{
|
{
|
||||||
_d("...");
|
dbg("...");
|
||||||
if (UEV_ERROR == events) {
|
if (UEV_ERROR == events) {
|
||||||
_e("Unrecoverable error in signal watcher");
|
errx(1, "Unrecoverable error in signal watcher");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_RESERVED_RUNLEVEL(runlevel)) {
|
||||||
|
warnx("SIGUSR2 ignored in runlevel S and 6.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -481,9 +520,14 @@ static void sigusr2_cb(uev_t *w, void *arg, int events)
|
|||||||
*/
|
*/
|
||||||
static void sigterm_cb(uev_t *w, void *arg, int events)
|
static void sigterm_cb(uev_t *w, void *arg, int events)
|
||||||
{
|
{
|
||||||
_d("...");
|
dbg("...");
|
||||||
if (UEV_ERROR == events) {
|
if (UEV_ERROR == events) {
|
||||||
_e("Unrecoverable error in signal watcher");
|
errx(1, "Unrecoverable error in signal watcher");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_RESERVED_RUNLEVEL(runlevel)) {
|
||||||
|
warnx("SIGTERM ignored in runlevel S and 6.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -500,7 +544,7 @@ static void sigchld_cb(uev_t *w, void *arg, int events)
|
|||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
if (UEV_ERROR == events) {
|
if (UEV_ERROR == events) {
|
||||||
_e("Unrecoverable error in signal watcher");
|
errx(1, "Unrecoverable error in signal watcher");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -513,7 +557,7 @@ static void sigchld_cb(uev_t *w, void *arg, int events)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("Collected child %d", pid);
|
dbg("Collected child PID %d, status: %d", pid, status);
|
||||||
service_monitor(pid, status);
|
service_monitor(pid, status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -603,7 +647,7 @@ void sig_setup(uev_ctx_t *ctx)
|
|||||||
{
|
{
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
|
|
||||||
_d("Setup signals");
|
dbg("Setup signals");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Standard SysV init calls ctrl-alt-delete handler
|
* Standard SysV init calls ctrl-alt-delete handler
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* Signal management - Be conservative with what finit responds to!
|
/* Signal management - Be conservative with what finit responds to!
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||||
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@@ -77,6 +77,13 @@ static char *sm_status(sm_state_t state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char sm_runlevel(int lvl)
|
||||||
|
{
|
||||||
|
if (lvl == INIT_LEVEL)
|
||||||
|
return 'S';
|
||||||
|
return lvl + '0';
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Disable login in single user mode and shutdown/reboot
|
* Disable login in single user mode and shutdown/reboot
|
||||||
*
|
*
|
||||||
@@ -86,10 +93,10 @@ static char *sm_status(sm_state_t state)
|
|||||||
*/
|
*/
|
||||||
static void nologin(void)
|
static void nologin(void)
|
||||||
{
|
{
|
||||||
if (runlevel == 1 || runlevel == 0 || runlevel == 6)
|
if (runlevel == 1 || IS_RESERVED_RUNLEVEL(runlevel))
|
||||||
touch(FINIT_NOLOGIN_PATH);
|
touch(FINIT_NOLOGIN_PATH);
|
||||||
|
|
||||||
if (prevlevel == 1 || prevlevel == 0 || prevlevel == 6)
|
if (prevlevel == 1 || IS_RESERVED_RUNLEVEL(prevlevel))
|
||||||
erase(FINIT_NOLOGIN_PATH);
|
erase(FINIT_NOLOGIN_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,12 +123,12 @@ void sm_step(sm_t *sm)
|
|||||||
restart:
|
restart:
|
||||||
old_state = sm->state;
|
old_state = sm->state;
|
||||||
|
|
||||||
_d("state: %s, runlevel: %d, newlevel: %d, teardown: %d, reload: %d",
|
dbg("state: %s, runlevel: %c, newlevel: %d, teardown: %d, reload: %d",
|
||||||
sm_status(sm->state), runlevel, sm->newlevel, sm->in_teardown, sm->reload);
|
sm_status(sm->state), sm_runlevel(runlevel), sm->newlevel, sm->in_teardown, sm->reload);
|
||||||
|
|
||||||
switch (sm->state) {
|
switch (sm->state) {
|
||||||
case SM_BOOTSTRAP_STATE:
|
case SM_BOOTSTRAP_STATE:
|
||||||
_d("Bootstrapping all services in runlevel S from %s", FINIT_CONF);
|
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);
|
||||||
sm->state = SM_RUNNING_STATE;
|
sm->state = SM_RUNNING_STATE;
|
||||||
break;
|
break;
|
||||||
@@ -150,15 +157,16 @@ restart:
|
|||||||
|
|
||||||
/* Restore terse mode and run hooks before shutdown */
|
/* Restore terse mode and run hooks before shutdown */
|
||||||
if (runlevel == 0 || runlevel == 6) {
|
if (runlevel == 0 || runlevel == 6) {
|
||||||
|
api_exit();
|
||||||
log_exit();
|
log_exit();
|
||||||
plugin_run_hooks(HOOK_SHUTDOWN);
|
plugin_run_hooks(HOOK_SHUTDOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("Setting new runlevel --> %d <-- previous %d", runlevel, prevlevel);
|
dbg("Setting new runlevel --> %c <-- previous %c", sm_runlevel(runlevel), sm_runlevel(prevlevel));
|
||||||
if (osheading)
|
if (osheading)
|
||||||
logit(LOG_CONSOLE | LOG_NOTICE, "%s, entering runlevel %d", osheading, runlevel);
|
logit(LOG_CONSOLE | LOG_NOTICE, "%s, entering runlevel %c", osheading, sm_runlevel(runlevel));
|
||||||
else
|
else
|
||||||
logit(LOG_CONSOLE | LOG_NOTICE, "Entering runlevel %d", runlevel);
|
logit(LOG_CONSOLE | LOG_NOTICE, "Entering runlevel %c", sm_runlevel(runlevel));
|
||||||
runlevel_set(prevlevel, runlevel);
|
runlevel_set(prevlevel, runlevel);
|
||||||
|
|
||||||
/* Disable login in single-user mode as well as shutdown/reboot */
|
/* Disable login in single-user mode as well as shutdown/reboot */
|
||||||
@@ -173,7 +181,7 @@ restart:
|
|||||||
/* Reset once flag of runtasks */
|
/* Reset once flag of runtasks */
|
||||||
service_runtask_clean();
|
service_runtask_clean();
|
||||||
|
|
||||||
_d("Stopping services not allowed in new runlevel ...");
|
dbg("Stopping services not allowed in new runlevel ...");
|
||||||
sm->in_teardown = 1;
|
sm->in_teardown = 1;
|
||||||
service_step_all(SVC_TYPE_ANY);
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
|
||||||
@@ -187,15 +195,15 @@ restart:
|
|||||||
*/
|
*/
|
||||||
svc = svc_stop_completed();
|
svc = svc_stop_completed();
|
||||||
if (svc) {
|
if (svc) {
|
||||||
_d("Waiting to collect %s, cmd %s(%d) ...", svc_ident(svc, NULL, 0), svc->cmd, svc->pid);
|
dbg("Waiting to collect %s, cmd %s(%d) ...", svc_ident(svc, NULL, 0), svc->cmd, svc->pid);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prev runlevel services stopped, call hooks before starting new runlevel ... */
|
/* Prev runlevel services stopped, call hooks before starting new runlevel ... */
|
||||||
_d("All services have been stopped, calling runlevel change hooks ...");
|
dbg("All services have been stopped, calling runlevel change hooks ...");
|
||||||
plugin_run_hooks(HOOK_RUNLEVEL_CHANGE); /* Reconfigure HW/VLANs/etc here */
|
plugin_run_hooks(HOOK_RUNLEVEL_CHANGE); /* Reconfigure HW/VLANs/etc here */
|
||||||
|
|
||||||
_d("Starting services new to this runlevel ...");
|
dbg("Starting services new to this runlevel ...");
|
||||||
sm->in_teardown = 0;
|
sm->in_teardown = 0;
|
||||||
service_step_all(SVC_TYPE_ANY);
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
|
||||||
@@ -225,7 +233,7 @@ restart:
|
|||||||
* Then, mark all affected service conditions as in-flux and
|
* Then, mark all affected service conditions as in-flux and
|
||||||
* let all affected services move to WAITING/HALTED
|
* let all affected services move to WAITING/HALTED
|
||||||
*/
|
*/
|
||||||
_d("Stopping services not allowed after reconf ...");
|
dbg("Stopping services not allowed after reconf ...");
|
||||||
sm->in_teardown = 1;
|
sm->in_teardown = 1;
|
||||||
cond_reload();
|
cond_reload();
|
||||||
service_step_all(SVC_TYPE_ANY);
|
service_step_all(SVC_TYPE_ANY);
|
||||||
@@ -240,23 +248,26 @@ restart:
|
|||||||
*/
|
*/
|
||||||
svc = svc_stop_completed();
|
svc = svc_stop_completed();
|
||||||
if (svc) {
|
if (svc) {
|
||||||
_d("Waiting to collect %s, cmd %s(%d) ...", svc_ident(svc, NULL, 0), svc->cmd, svc->pid);
|
dbg("Waiting to collect %s, cmd %s(%d) ...", svc_ident(svc, NULL, 0), svc->cmd, svc->pid);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
sm->in_teardown = 0;
|
sm->in_teardown = 0;
|
||||||
|
|
||||||
_d("Starting services after reconf ...");
|
dbg("Starting services after reconf ...");
|
||||||
service_step_all(SVC_TYPE_ANY);
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
|
||||||
/* Cleanup stale services */
|
/* Cleanup stale services */
|
||||||
svc_clean_dynamic(service_unregister);
|
svc_clean_dynamic(service_unregister);
|
||||||
|
|
||||||
_d("Calling reconf hooks ...");
|
dbg("Calling reconf hooks ...");
|
||||||
plugin_run_hooks(HOOK_SVC_RECONF);
|
plugin_run_hooks(HOOK_SVC_RECONF);
|
||||||
|
|
||||||
|
dbg("Update configuration generation of unmodified non-native services ...");
|
||||||
|
service_notify_reconf();
|
||||||
|
|
||||||
service_step_all(SVC_TYPE_ANY);
|
service_step_all(SVC_TYPE_ANY);
|
||||||
_d("Reconfiguration done");
|
dbg("Reconfiguration done");
|
||||||
|
|
||||||
sm->state = SM_RUNNING_STATE;
|
sm->state = SM_RUNNING_STATE;
|
||||||
break;
|
break;
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
/* Reset terminal line settings (stty sane)
|
/* Reset terminal line settings (stty sane)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
/* poor man's sulogin, may be statically linked
|
/* poor man's sulogin, may be statically linked
|
||||||
*
|
*
|
||||||
* Copyright (c) 2021-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2021-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* Low-level service primitives and generic API for managing svc_t structures
|
/* Low-level service primitives and generic API for managing svc_t structures
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||||
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -70,12 +70,12 @@ static void maybe_clear_cond(svc_t *svc)
|
|||||||
if (!string_compare(cond, c))
|
if (!string_compare(cond, c))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_d("Not clearing cond %s from gc svc %s, provided by new active service %s",
|
dbg("Not clearing cond %s from gc svc %s, provided by new active service %s",
|
||||||
cond, ident, svc_ident(s, NULL, 0));
|
cond, ident, svc_ident(s, NULL, 0));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("Cleaning out %s, clearing any conditions ...", svc->name);
|
dbg("Cleaning out %s, clearing any conditions ...", svc->name);
|
||||||
cond_clear(mkcond(svc, cond, sizeof(cond)));
|
cond_clear(mkcond(svc, cond, sizeof(cond)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,7 +372,33 @@ svc_t *svc_find(char *name, char *id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* svc_find_by_pid - Find an service object by its PID
|
* svc_find_by_str - Find a service object by name:id
|
||||||
|
* @str: name[:id]
|
||||||
|
*
|
||||||
|
* Like svc_find() but takes 'name[:id]' argument
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* A pointer to an &svc_t object, or %NULL if not found.
|
||||||
|
*/
|
||||||
|
svc_t *svc_find_by_str(const char *str)
|
||||||
|
{
|
||||||
|
char *name, *id;
|
||||||
|
|
||||||
|
if (!str)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
name = strdupa(str);
|
||||||
|
id = strchr(name, ':');
|
||||||
|
if (id)
|
||||||
|
*id++ = 0;
|
||||||
|
else
|
||||||
|
id = "";
|
||||||
|
|
||||||
|
return svc_find(name, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* svc_find_by_pid - Find a service object by its PID
|
||||||
* @pid: Process ID to match
|
* @pid: Process ID to match
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
@@ -391,7 +417,29 @@ svc_t *svc_find_by_pid(pid_t pid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* svc_find_by_jobid - Find an service object by its JOB:ID
|
* svc_find_by_cond - Find a service object by its pid/foo condition
|
||||||
|
* @cond: Full "pid/foo" condition
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* A pointer to an &svc_t object, or %NULL if not found.
|
||||||
|
*/
|
||||||
|
svc_t *svc_find_by_cond(const char *cond)
|
||||||
|
{
|
||||||
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
|
char buf[MAX_COND_LEN];
|
||||||
|
|
||||||
|
mkcond(svc, buf, sizeof(buf));
|
||||||
|
if (string_compare(buf, cond))
|
||||||
|
return svc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* svc_find_by_jobid - Find a service object by its JOB:ID
|
||||||
* @job: Job n:o
|
* @job: Job n:o
|
||||||
* @id: Optional instance id
|
* @id: Optional instance id
|
||||||
*
|
*
|
||||||
@@ -478,6 +526,14 @@ svc_t *svc_find_by_pidfile(char *fn)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void svc_mark(svc_t *svc)
|
||||||
|
{
|
||||||
|
if (!svc || svc->protect)
|
||||||
|
return;
|
||||||
|
|
||||||
|
*((int *)&svc->removed) = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* svc_mark_dynamic - Mark dynamically loaded services for deletion.
|
* svc_mark_dynamic - Mark dynamically loaded services for deletion.
|
||||||
*
|
*
|
||||||
@@ -492,12 +548,8 @@ void svc_mark_dynamic(void)
|
|||||||
{
|
{
|
||||||
svc_t *svc, *iter = NULL;
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0))
|
||||||
if (svc->protect)
|
svc_mark(svc);
|
||||||
continue;
|
|
||||||
|
|
||||||
*((int *)&svc->removed) = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void svc_mark_dirty(svc_t *svc)
|
void svc_mark_dirty(svc_t *svc)
|
||||||
@@ -542,7 +594,7 @@ void svc_clean_dynamic(void (*cb)(svc_t *))
|
|||||||
*/
|
*/
|
||||||
int svc_clean_bootstrap(svc_t *svc)
|
int svc_clean_bootstrap(svc_t *svc)
|
||||||
{
|
{
|
||||||
if (!ISOTHER(svc->runlevels, 0)) {
|
if (!ISOTHER(svc->runlevels, INIT_LEVEL)) {
|
||||||
svc->pid = 0;
|
svc->pid = 0;
|
||||||
svc_del(svc);
|
svc_del(svc);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -597,6 +649,103 @@ int svc_enabled(svc_t *svc)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* svc_conflicts - Check if svc conflicts with any other running svc
|
||||||
|
* @svc:
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* %TRUE(1) or %FALSE(0)
|
||||||
|
*/
|
||||||
|
int svc_conflicts(svc_t *svc)
|
||||||
|
{
|
||||||
|
char *ptr, *nm;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (!svc->conflict[0])
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ptr = strdup(svc->conflict);
|
||||||
|
if (!ptr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
nm = strtok(ptr, ",");
|
||||||
|
while (nm) {
|
||||||
|
svc_t *s;
|
||||||
|
|
||||||
|
s = svc_find_by_str(nm);
|
||||||
|
if (s) {
|
||||||
|
if (s->state >= SVC_STOPPING_STATE)
|
||||||
|
rc = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
nm = strtok(NULL, ",");
|
||||||
|
}
|
||||||
|
|
||||||
|
free(ptr);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* svc_ifthen - Check if: statement in declaration
|
||||||
|
* @ident: svc_t identififcation (name:id)
|
||||||
|
* @stmt: if: statement from .conf file
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* %TRUE(1) yes, use this svc_t, %FALSE(0) prune
|
||||||
|
*/
|
||||||
|
int svc_ifthen(const char *ident, char *stmt)
|
||||||
|
{
|
||||||
|
int not = 0;
|
||||||
|
svc_t *svc;
|
||||||
|
|
||||||
|
if (!stmt || !stmt[0])
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (stmt[0] == '<') {
|
||||||
|
enum cond_state cond;
|
||||||
|
char *ptr = ++stmt;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (stmt[0] == '!') {
|
||||||
|
stmt++;
|
||||||
|
not++;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stmt[0] == '!') {
|
||||||
|
stmt++;
|
||||||
|
not++;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* break up "job:id job:id job:id ..." into several "job:id" tokens */
|
/* break up "job:id job:id job:id ..." into several "job:id" tokens */
|
||||||
static char *tokstr(char *str, size_t len)
|
static char *tokstr(char *str, size_t len)
|
||||||
{
|
{
|
||||||
@@ -635,17 +784,17 @@ int svc_parse_jobstr(char *str, size_t len, void *user_data, int (*found)(svc_t
|
|||||||
char *input, *token;
|
char *input, *token;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
_d("Got str:'%s'", str);
|
dbg("Got str:'%s'", str);
|
||||||
input = tokstr(str, len);
|
input = tokstr(str, len);
|
||||||
while (input) {
|
while (input) {
|
||||||
char *id = NULL;
|
char *id = NULL;
|
||||||
svc_t *svc, *iter = NULL;
|
svc_t *svc, *iter = NULL;
|
||||||
char *ptr;
|
char *ptr;
|
||||||
|
|
||||||
_d("Got token:'%s'", input);
|
dbg("Got token:'%s'", input);
|
||||||
token = sanitize(input, strlen(input) + 1);
|
token = sanitize(input, strlen(input) + 1);
|
||||||
if (!token) {
|
if (!token) {
|
||||||
_d("Sanitation of token:'%s' failed", input);
|
dbg("Sanitation of token:'%s' failed", input);
|
||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
ptr = strchr(token, ':');
|
ptr = strchr(token, ':');
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* Low-level service primitives and generic API for managing svc_t structures
|
/* Low-level service primitives and generic API for managing svc_t structures
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||||
* Copyright (c) 2008-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -61,8 +61,9 @@ typedef enum {
|
|||||||
SVC_STOPPING_STATE, /* Waiting to collect the child process */
|
SVC_STOPPING_STATE, /* Waiting to collect the child process */
|
||||||
SVC_CLEANUP_STATE, /* Running post: script */
|
SVC_CLEANUP_STATE, /* Running post: script */
|
||||||
SVC_SETUP_STATE, /* Running pre: script */
|
SVC_SETUP_STATE, /* Running pre: script */
|
||||||
SVC_WAITING_STATE, /* Condition is in flux, process SIGSTOPed */
|
SVC_PAUSED_STATE, /* Condition is in flux, process SIGSTOPed */
|
||||||
SVC_READY_STATE, /* Enabled but condition not satisfied */
|
SVC_WAITING_STATE, /* Enabled but condition not satisfied */
|
||||||
|
SVC_STARTING_STATE, /* Conditions OK and pre: script done, start */
|
||||||
SVC_RUNNING_STATE, /* Process running */
|
SVC_RUNNING_STATE, /* Process running */
|
||||||
} svc_state_t;
|
} svc_state_t;
|
||||||
|
|
||||||
@@ -77,7 +78,8 @@ typedef enum {
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SVC_ONCRASH_IGNORE = 0,
|
SVC_ONCRASH_IGNORE = 0,
|
||||||
SVC_ONCRASH_REBOOT = 1,
|
SVC_ONCRASH_REBOOT,
|
||||||
|
SVC_ONCRASH_SCRIPT,
|
||||||
} svc_oncrash_action_t;
|
} svc_oncrash_action_t;
|
||||||
|
|
||||||
#define MAX_ID_LEN 16
|
#define MAX_ID_LEN 16
|
||||||
@@ -121,7 +123,8 @@ typedef struct svc {
|
|||||||
int status; /* From waitpid() when process is collected */
|
int status; /* From waitpid() when process is collected */
|
||||||
const svc_state_t state; /* Paused, Reloading, Restart, Running, ... */
|
const svc_state_t state; /* Paused, Reloading, Restart, Running, ... */
|
||||||
svc_type_t type; /* Service, run, task, ... */
|
svc_type_t type; /* Service, run, task, ... */
|
||||||
int protect; /* Services like dbus-daemon & udev by Finit */
|
char protect; /* Services like dbus-daemon & udev by Finit */
|
||||||
|
char manual; /* run/task that require `initctl start foo` */
|
||||||
const int dirty; /* 0: unmodified, 1: modified */
|
const int dirty; /* 0: unmodified, 1: modified */
|
||||||
const int removed;
|
const int removed;
|
||||||
int starting; /* ... waiting for pidfile to be re-asserted */
|
int starting; /* ... waiting for pidfile to be re-asserted */
|
||||||
@@ -135,12 +138,14 @@ typedef struct svc {
|
|||||||
int job; /* For intenal use only, canonical ref is NAME:ID */
|
int job; /* For intenal use only, canonical ref is NAME:ID */
|
||||||
char name[MAX_ARG_LEN];
|
char name[MAX_ARG_LEN];
|
||||||
char id[MAX_ID_LEN]; /* :ID */
|
char id[MAX_ID_LEN]; /* :ID */
|
||||||
|
char ifstmt[MAX_IDENT_LEN];
|
||||||
|
|
||||||
/* Counters */
|
/* Counters */
|
||||||
char once; /* run/task, (at least) once per runlevel */
|
char once; /* run/task, (at least) once per runlevel */
|
||||||
unsigned int restart_tot; /* Total restarts ever, summarized, including `initctl restart` */
|
unsigned int restart_tot; /* Total restarts ever, summarized, including `initctl restart` */
|
||||||
unsigned char restart_max; /* Maximum number of restarts allowed */
|
int restart_max; /* Maximum number of restarts allowed */
|
||||||
int restart_tmo; /* Time required for the service to start. */
|
int restart_saved; /* INTERNAL, saved copy of .conf value */
|
||||||
|
int restart_tmo; /* Time before restarting a crashing service */
|
||||||
unsigned char oncrash_action; /* Action to perform in crashed state. */
|
unsigned char oncrash_action; /* Action to perform in crashed state. */
|
||||||
char respawn; /* ttys, or services with `respawn`, never increment restart_cnt */
|
char respawn; /* ttys, or services with `respawn`, never increment restart_cnt */
|
||||||
const char restart_cnt; /* Incremented for each restart by service monitor. */
|
const char restart_cnt; /* Incremented for each restart by service monitor. */
|
||||||
@@ -177,10 +182,12 @@ typedef struct svc {
|
|||||||
char cmd[MAX_ARG_LEN];
|
char cmd[MAX_ARG_LEN];
|
||||||
char args[MAX_NUM_SVC_ARGS][MAX_ARG_LEN];
|
char args[MAX_NUM_SVC_ARGS][MAX_ARG_LEN];
|
||||||
int args_dirty;
|
int args_dirty;
|
||||||
|
char conflict[MAX_ARG_LEN];
|
||||||
char desc[MAX_STR_LEN];
|
char desc[MAX_STR_LEN];
|
||||||
char env[MAX_ARG_LEN];
|
char env[MAX_ARG_LEN];
|
||||||
char pre_script[MAX_ARG_LEN];
|
char pre_script[MAX_ARG_LEN];
|
||||||
char post_script[MAX_ARG_LEN];
|
char post_script[MAX_ARG_LEN];
|
||||||
|
char ready_script[MAX_ARG_LEN];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Used to forcefully kill services that won't shutdown on
|
* Used to forcefully kill services that won't shutdown on
|
||||||
@@ -189,6 +196,12 @@ typedef struct svc {
|
|||||||
uev_t timer;
|
uev_t timer;
|
||||||
void (*timer_cb)(struct svc *svc);
|
void (*timer_cb)(struct svc *svc);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Readiness notification socket: systemd, s6
|
||||||
|
*/
|
||||||
|
int notify; /* 0: none, 1: systemd, 2: s6 */
|
||||||
|
uev_t notify_watcher; /* i/o watcher */
|
||||||
|
|
||||||
/* time at svc_del(), used by gc timer */
|
/* time at svc_del(), used by gc timer */
|
||||||
struct timespec gc;
|
struct timespec gc;
|
||||||
} svc_t;
|
} svc_t;
|
||||||
@@ -198,7 +211,9 @@ int svc_del (svc_t *svc);
|
|||||||
void svc_validate (svc_t *svc);
|
void svc_validate (svc_t *svc);
|
||||||
|
|
||||||
svc_t *svc_find (char *name, char *id);
|
svc_t *svc_find (char *name, char *id);
|
||||||
|
svc_t *svc_find_by_str (const char *str);
|
||||||
svc_t *svc_find_by_pid (pid_t pid);
|
svc_t *svc_find_by_pid (pid_t pid);
|
||||||
|
svc_t *svc_find_by_cond (const char *cond);
|
||||||
svc_t *svc_find_by_jobid (int job, char *id);
|
svc_t *svc_find_by_jobid (int job, char *id);
|
||||||
svc_t *svc_find_by_tty (char *dev);
|
svc_t *svc_find_by_tty (char *dev);
|
||||||
svc_t *svc_find_by_pidfile (char *fn);
|
svc_t *svc_find_by_pidfile (char *fn);
|
||||||
@@ -212,6 +227,7 @@ void svc_foreach_type (int types, int (*cb)(svc_t *));
|
|||||||
|
|
||||||
svc_t *svc_stop_completed (void);
|
svc_t *svc_stop_completed (void);
|
||||||
|
|
||||||
|
void svc_mark (svc_t *svc);
|
||||||
void svc_mark_dynamic (void);
|
void svc_mark_dynamic (void);
|
||||||
void svc_mark_dirty (svc_t *svc);
|
void svc_mark_dirty (svc_t *svc);
|
||||||
void svc_mark_clean (svc_t *svc);
|
void svc_mark_clean (svc_t *svc);
|
||||||
@@ -221,6 +237,8 @@ void svc_prune_bootstrap (void);
|
|||||||
|
|
||||||
void svc_enable (svc_t *svc);
|
void svc_enable (svc_t *svc);
|
||||||
int svc_enabled (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_parse_jobstr (char *str, size_t len, void *user_data, int (*found)(svc_t *, void *), int (not_found)(char *, char *, void *));
|
int svc_parse_jobstr (char *str, size_t len, void *user_data, int (*found)(svc_t *, void *), int (not_found)(char *, char *, void *));
|
||||||
|
|
||||||
@@ -229,12 +247,14 @@ static inline int svc_is_sysv (svc_t *svc) { return svc && SVC_TYPE_SYSV
|
|||||||
static inline int svc_is_tty (svc_t *svc) { return svc && SVC_TYPE_TTY == svc->type; }
|
static inline int svc_is_tty (svc_t *svc) { return svc && SVC_TYPE_TTY == svc->type; }
|
||||||
static inline int svc_is_runtask (svc_t *svc) { return svc && (SVC_TYPE_RUNTASK & svc->type);}
|
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_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_in_runlevel (svc_t *svc, int runlevel) { return svc && ISSET(svc->runlevels, runlevel); }
|
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); }
|
static inline int svc_nohup (svc_t *svc) { return svc && (0 == svc->sighup || 0 != svc->args_dirty); }
|
||||||
static inline int svc_has_pidfile (svc_t *svc) { return svc_is_daemon(svc) && svc->pidfile[0] != 0 && svc->pidfile[0] != '!'; }
|
static inline int svc_has_pidfile (svc_t *svc) { return svc_is_daemon(svc) && svc->pidfile[0] != 0 && svc->pidfile[0] != '!'; }
|
||||||
static inline int svc_has_pre (svc_t *svc) { return svc->pre_script[0]; }
|
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_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 void svc_starting (svc_t *svc) { if (svc) svc->starting = 1; }
|
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 void svc_started (svc_t *svc) { if (svc) svc->starting = 0; }
|
||||||
@@ -248,6 +268,8 @@ static inline int svc_is_updated (svc_t *svc) { return svc && 1 == svc->dirty
|
|||||||
static inline int svc_is_blocked (svc_t *svc) { return svc && svc->block != SVC_BLOCK_NONE; }
|
static inline int svc_is_blocked (svc_t *svc) { return svc && svc->block != SVC_BLOCK_NONE; }
|
||||||
static inline int svc_is_busy (svc_t *svc) { return svc && svc->block == SVC_BLOCK_BUSY; }
|
static inline int svc_is_busy (svc_t *svc) { return svc && svc->block == SVC_BLOCK_BUSY; }
|
||||||
static inline int svc_is_missing (svc_t *svc) { return svc && svc->block == SVC_BLOCK_MISSING; }
|
static inline int svc_is_missing (svc_t *svc) { return svc && svc->block == SVC_BLOCK_MISSING; }
|
||||||
|
static inline int svc_is_crashing (svc_t *svc) { return svc && svc->block == SVC_BLOCK_CRASHING; }
|
||||||
|
static inline int svc_is_restart (svc_t *svc) { return svc && svc->block == SVC_BLOCK_RESTARTING; }
|
||||||
|
|
||||||
static inline void svc_unblock (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_NONE; }
|
static inline void svc_unblock (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_NONE; }
|
||||||
#define svc_start(svc) svc_unblock(svc)
|
#define svc_start(svc) svc_unblock(svc)
|
||||||
@@ -347,17 +369,20 @@ static inline char *svc_status(svc_t *svc)
|
|||||||
return "stopping";
|
return "stopping";
|
||||||
}
|
}
|
||||||
|
|
||||||
case SVC_WAITING_STATE:
|
|
||||||
return "waiting";
|
|
||||||
|
|
||||||
case SVC_CLEANUP_STATE:
|
case SVC_CLEANUP_STATE:
|
||||||
return "cleanup";
|
return "cleanup";
|
||||||
|
|
||||||
case SVC_SETUP_STATE:
|
case SVC_SETUP_STATE:
|
||||||
return "setup";
|
return "setup";
|
||||||
|
|
||||||
case SVC_READY_STATE:
|
case SVC_PAUSED_STATE:
|
||||||
return "ready";
|
return "paused";
|
||||||
|
|
||||||
|
case SVC_WAITING_STATE:
|
||||||
|
return "waiting";
|
||||||
|
|
||||||
|
case SVC_STARTING_STATE:
|
||||||
|
return "starting";
|
||||||
|
|
||||||
case SVC_RUNNING_STATE:
|
case SVC_RUNNING_STATE:
|
||||||
return "running";
|
return "running";
|
||||||
|
|||||||
+530
@@ -0,0 +1,530 @@
|
|||||||
|
/* Limited tmpfiles.d implementation
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h" /* Generated by configure script */
|
||||||
|
|
||||||
|
#include <sys/sysmacros.h>
|
||||||
|
#include "finit.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
#include "tmpfiles.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static int glob_do(const char *path, int (*cb)(const char *))
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
glob_t gl;
|
||||||
|
|
||||||
|
rc = glob(path, GLOB_NOESCAPE, NULL, &gl);
|
||||||
|
if (rc) {
|
||||||
|
if (rc == GLOB_NOMATCH) {
|
||||||
|
errno = ENOENT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < gl.gl_pathc; i++)
|
||||||
|
rc += cb(gl.gl_pathv[i]);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_mm(char *arg, int *major, int *minor)
|
||||||
|
{
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
if (!arg) {
|
||||||
|
inval:
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = strchr(arg, ':');
|
||||||
|
if (!ptr)
|
||||||
|
goto inval;
|
||||||
|
|
||||||
|
*ptr++ = 0;
|
||||||
|
*major = atoi(arg);
|
||||||
|
*minor = atoi(ptr);
|
||||||
|
|
||||||
|
if (!*major || !*minor)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_delete(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftw)
|
||||||
|
{
|
||||||
|
if (ftw->level == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (remove(fpath))
|
||||||
|
warn("Failed removing condition %s", fpath);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rmrf(const char *path)
|
||||||
|
{
|
||||||
|
if (!fisdir(path))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
nftw(path, do_delete, 20, FTW_DEPTH);
|
||||||
|
if (remove(path) && errno != ENOENT)
|
||||||
|
warn("Failed removing path %s", path);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mkparent(char *path, mode_t mode)
|
||||||
|
{
|
||||||
|
mkpath(dirname(strdupa(path)), mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *write_hex(FILE *fp, char *p)
|
||||||
|
{
|
||||||
|
unsigned char val;
|
||||||
|
char num[4], *ptr;
|
||||||
|
int i, len = 0;
|
||||||
|
|
||||||
|
for (i = 0; p[i] && len < 2; i++) {
|
||||||
|
char c = p[i];
|
||||||
|
|
||||||
|
if ((c >= '0' && c <= '7') ||
|
||||||
|
(c >= 'a' && c <= 'f') ||
|
||||||
|
(c >= 'A' && c <= 'F'))
|
||||||
|
num[len++] = c;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
num[len] = 0;
|
||||||
|
if (len == 0) {
|
||||||
|
fputs("x", fp);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
val = strtoul(num, &ptr, 16);
|
||||||
|
if (errno || ptr == num)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
fputc(val & 0xff, fp);
|
||||||
|
end:
|
||||||
|
return &p[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *write_num(FILE *fp, char *p)
|
||||||
|
{
|
||||||
|
unsigned char val;
|
||||||
|
char num[4], *ptr;
|
||||||
|
int i, len = 0;
|
||||||
|
|
||||||
|
for (i = 0; p[i] && len < 3; i++) {
|
||||||
|
char c = p[i];
|
||||||
|
|
||||||
|
if (c >= '0' && c <= '7')
|
||||||
|
num[len++] = c;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
num[len] = 0;
|
||||||
|
if (len == 0)
|
||||||
|
return p;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
val = strtoul(num, &ptr, 8);
|
||||||
|
if (errno || ptr == num)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
fputc(val & 0xff, fp);
|
||||||
|
end:
|
||||||
|
return &p[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_arg(FILE *fp, char *arg)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
if (!arg)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (*arg && (p = strchr(arg, '\\'))) {
|
||||||
|
fwrite(arg, sizeof(char), p - arg, fp);
|
||||||
|
|
||||||
|
*p++ = 0;
|
||||||
|
switch (*p) {
|
||||||
|
case '\\':
|
||||||
|
fputc('\\', fp);
|
||||||
|
arg = p + 1;
|
||||||
|
break;
|
||||||
|
case '\'':
|
||||||
|
fputc('\'', fp);
|
||||||
|
arg = p + 1;
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
fputc('"', fp);
|
||||||
|
arg = p + 1;
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
fputc('\a', fp);
|
||||||
|
arg = p + 1;
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
fputc('\b', fp);
|
||||||
|
arg = p + 1;
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
fputc('\e', fp);
|
||||||
|
arg = p + 1;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
fputc('\n', fp);
|
||||||
|
arg = p + 1;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
fputc('\t', fp);
|
||||||
|
arg = p + 1;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
arg = write_hex(fp, &p[1]);
|
||||||
|
break;
|
||||||
|
case '0' ... '7':
|
||||||
|
arg = write_num(fp, p);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fputc(*p, fp);
|
||||||
|
arg = p + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fputs(arg, fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The configuration format is one line per path, containing type, path,
|
||||||
|
* mode, ownership, age, and argument fields. The lines are separated by
|
||||||
|
* newlines, the fields by whitespace:
|
||||||
|
*
|
||||||
|
* #Type Path Mode User Group Age Argument…
|
||||||
|
* d /run/user 0755 root root 10d -
|
||||||
|
* L /tmp/foobar - - - - /dev/null
|
||||||
|
*
|
||||||
|
* https://www.freedesktop.org/software/systemd/man/tmpfiles.d.html
|
||||||
|
*/
|
||||||
|
static void tmpfiles(char *line)
|
||||||
|
{
|
||||||
|
char *type, *path, *token, *user, *group, *age, *arg;
|
||||||
|
char *dst = NULL, *opts = "";
|
||||||
|
struct stat st, ast;
|
||||||
|
int major, minor;
|
||||||
|
int strc, rc = 0;
|
||||||
|
mode_t mode = 0;
|
||||||
|
FILE *fp = NULL;
|
||||||
|
char buf[1024];
|
||||||
|
glob_t gl;
|
||||||
|
|
||||||
|
type = strtok(line, "\t ");
|
||||||
|
if (!type)
|
||||||
|
return;
|
||||||
|
|
||||||
|
path = strtok(NULL, "\t ");
|
||||||
|
if (!path)
|
||||||
|
return;
|
||||||
|
if (strchr(path, '%')) {
|
||||||
|
errx(1, "Path name specifiers unsupported, skipping.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
token = strtok(NULL, "\t ");
|
||||||
|
if (token) {
|
||||||
|
errno = 0;
|
||||||
|
mode = strtoul(token, &arg, 8);
|
||||||
|
if (errno || arg == token)
|
||||||
|
mode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
user = strtok(NULL, "\t ");
|
||||||
|
if (!user || !strcmp(user, "-"))
|
||||||
|
user = "root";
|
||||||
|
group = strtok(NULL, "\t ");
|
||||||
|
if (!group || !strcmp(group, "-"))
|
||||||
|
group = "root";
|
||||||
|
|
||||||
|
age = strtok(NULL, "\t ");
|
||||||
|
(void)age; /* unused atm. */
|
||||||
|
arg = strtok(NULL, "\n");
|
||||||
|
|
||||||
|
strc = stat(path, &st);
|
||||||
|
|
||||||
|
switch (type[0]) {
|
||||||
|
case 'b':
|
||||||
|
rc = parse_mm(arg, &major, &minor);
|
||||||
|
if (rc)
|
||||||
|
break;
|
||||||
|
if (!strc) {
|
||||||
|
if (type[1] != '+')
|
||||||
|
break;
|
||||||
|
erase(path);
|
||||||
|
}
|
||||||
|
mkparent(path, 0755);
|
||||||
|
rc = blkdev(path, mode ?: 0644, major, minor);
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
rc = parse_mm(arg, &major, &minor);
|
||||||
|
if (rc)
|
||||||
|
break;
|
||||||
|
if (!strc) {
|
||||||
|
if (type[1] != '+')
|
||||||
|
break;
|
||||||
|
erase(path);
|
||||||
|
}
|
||||||
|
mkparent(path, 0755);
|
||||||
|
rc = chardev(path, mode ?: 0644, major, minor);
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
if (!arg) {
|
||||||
|
paste(buf, sizeof(buf), "/usr/share/factory", path);
|
||||||
|
arg = buf;
|
||||||
|
}
|
||||||
|
if (!strc) {
|
||||||
|
struct dirent **namelist;
|
||||||
|
int num;
|
||||||
|
|
||||||
|
if (!S_ISDIR(st.st_mode))
|
||||||
|
break;
|
||||||
|
num = scandir(path, &namelist, NULL, NULL);
|
||||||
|
free(namelist);
|
||||||
|
if (num >= 3)
|
||||||
|
break; /* not empty */
|
||||||
|
}
|
||||||
|
if (fisdir(arg) && !fisslashdir(arg)) {
|
||||||
|
size_t len = strlen(arg) + 2;
|
||||||
|
|
||||||
|
dst = malloc(len);
|
||||||
|
if (!dst)
|
||||||
|
break;
|
||||||
|
snprintf(dst, len, "%s/", arg);
|
||||||
|
arg = dst;
|
||||||
|
}
|
||||||
|
mkparent(path, 0755);
|
||||||
|
rc = rsync(arg, path, LITE_FOPT_KEEP_MTIME, NULL);
|
||||||
|
if (rc && errno == ENOENT)
|
||||||
|
rc = 0;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
case 'D':
|
||||||
|
mkparent(path, 0755);
|
||||||
|
rc = mksubsys(path, mode ?: 0755, user, group);
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
if (glob(path, GLOB_NOESCAPE, NULL, &gl))
|
||||||
|
break;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < gl.gl_pathc; i++)
|
||||||
|
rc += mksubsys(gl.gl_pathv[i], mode ?: 0755, user, group);
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
case 'F':
|
||||||
|
mkparent(path, 0755);
|
||||||
|
if (type[1] == '+' || type[0] == 'F') {
|
||||||
|
/* f+/F will create or truncate the file */
|
||||||
|
if (!arg) {
|
||||||
|
rc = create(path, mode ?: 0644, user, group);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fp = fopen(path, "w+");
|
||||||
|
} else {
|
||||||
|
/* f will create the file if it doesn't exist */
|
||||||
|
if (strc)
|
||||||
|
fp = fopen(path, "w");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fp) {
|
||||||
|
write_arg(fp, arg);
|
||||||
|
rc = fclose(fp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'l': /* Finit extension, like 'L' but only if target exists */
|
||||||
|
if (!arg) {
|
||||||
|
paste(buf, sizeof(buf), "/usr/share/factory", path);
|
||||||
|
if (stat(buf, &ast))
|
||||||
|
break;
|
||||||
|
} else if (arg[0] != '/') {
|
||||||
|
char *tmp;
|
||||||
|
|
||||||
|
tmp = dirname(strdupa(path));
|
||||||
|
paste(buf, sizeof(buf), tmp, arg);
|
||||||
|
dst = realpath(buf, NULL);
|
||||||
|
if (!dst)
|
||||||
|
break;
|
||||||
|
if (stat(dst, &ast))
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (stat(arg, &ast))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* fallthrough */
|
||||||
|
case 'L':
|
||||||
|
if (!strc) {
|
||||||
|
if (type[1] != '+')
|
||||||
|
break;
|
||||||
|
rmrf(path);
|
||||||
|
}
|
||||||
|
mkparent(path, 0755);
|
||||||
|
if (!arg) {
|
||||||
|
paste(buf, sizeof(buf), "/usr/share/factory", path);
|
||||||
|
arg = buf;
|
||||||
|
}
|
||||||
|
rc = ln(arg, path);
|
||||||
|
if (rc && errno == EEXIST)
|
||||||
|
rc = 0;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
if (!strc) {
|
||||||
|
if (type[1] != '+')
|
||||||
|
break;
|
||||||
|
erase(path);
|
||||||
|
}
|
||||||
|
mkparent(path, 0755);
|
||||||
|
rc = mkfifo(path, mode ?: 0644);
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
rc = glob_do(path, erase);
|
||||||
|
if (rc && errno == ENOENT)
|
||||||
|
rc = 0;
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
rc = glob_do(path, rmrf);
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
if (!arg)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (glob(path, GLOB_NOESCAPE, NULL, &gl))
|
||||||
|
break;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < gl.gl_pathc; i++) {
|
||||||
|
fp = fopen(gl.gl_pathv[i], type[1] == '+' ? "a" : "w");
|
||||||
|
if (fp) {
|
||||||
|
write_arg(fp, arg);
|
||||||
|
rc = fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'Z':
|
||||||
|
opts = "-R";
|
||||||
|
/* fallthrough */
|
||||||
|
case 'z':
|
||||||
|
if (!whichp("restorecon"))
|
||||||
|
break;
|
||||||
|
if (glob(path, GLOB_NOESCAPE, NULL, &gl))
|
||||||
|
break;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < gl.gl_pathc; i++) {
|
||||||
|
snprintf(buf, sizeof(buf), "restorecon %s %s", opts, gl.gl_pathv[i]);
|
||||||
|
run(buf, "restorecon");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errx(1, "Unsupported tmpfiles command '%s'", type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dst)
|
||||||
|
free(dst);
|
||||||
|
|
||||||
|
if (rc)
|
||||||
|
warn("Failed %s operation on path %s", type, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only the three last tmpfiles.d/ directories are defined in
|
||||||
|
* tmpfiles.d(5) as system search paths. Finit adds two more
|
||||||
|
* before that to have Finit specific ones sorted first, and
|
||||||
|
* a configure prefix specific one after that for user needs.
|
||||||
|
*/
|
||||||
|
void tmpfilesd(void)
|
||||||
|
{
|
||||||
|
/* in priority order */
|
||||||
|
char *dir[] = {
|
||||||
|
FINIT_TMPFILES "/*.conf",
|
||||||
|
TMPFILES_PATH "/*.conf",
|
||||||
|
"/usr/lib/tmpfiles.d/*.conf",
|
||||||
|
"/run/tmpfiles.d/*.conf",
|
||||||
|
"/etc/tmpfiles.d/*.conf", /* local admin overrides */
|
||||||
|
};
|
||||||
|
int flags = GLOB_NOESCAPE;
|
||||||
|
glob_t gl;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < NELEMS(dir); i++) {
|
||||||
|
glob(dir[i], flags, NULL, &gl);
|
||||||
|
flags |= GLOB_APPEND;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < gl.gl_pathc; i++) {
|
||||||
|
char *fn = gl.gl_pathv[i];
|
||||||
|
size_t j;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
/* check for overrides */
|
||||||
|
for (j = i + 1; j < gl.gl_pathc; j++) {
|
||||||
|
if (strcmp(basename(fn), basename(gl.gl_pathv[j])))
|
||||||
|
continue;
|
||||||
|
fn = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fn)
|
||||||
|
continue; /* skip, override exists */
|
||||||
|
|
||||||
|
fp = fopen(fn, "r");
|
||||||
|
if (!fp)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// info("Parsing %s ...", fn);
|
||||||
|
while (!feof(fp)) {
|
||||||
|
char *line;
|
||||||
|
|
||||||
|
line = fparseln(fp, NULL, NULL, NULL, FPARSELN_UNESCCOMM);
|
||||||
|
if (!line)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tmpfiles(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
globfree(&gl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Variables:
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/* Limited tmpfiles.d implementation
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TMPFILES_H_
|
||||||
|
#define TMPFILES_H_
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <ftw.h>
|
||||||
|
#include <glob.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void tmpfilesd(void);
|
||||||
|
|
||||||
|
#endif /* TMPFILES_H_ */
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/* Finit TTY handling
|
/* Finit TTY handling
|
||||||
*
|
*
|
||||||
* Copyright (c) 2013 Mattias Walström <lazzer@gmail.com>
|
* Copyright (c) 2013 Mattias Walström <lazzer@gmail.com>
|
||||||
* Copyright (c) 2013-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2013-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -60,7 +60,7 @@ char *tty_canonicalize(char *dev)
|
|||||||
if (stat(path, &st)) {
|
if (stat(path, &st)) {
|
||||||
if (!strncmp(path, _PATH_DEV, strlen(_PATH_DEV))) {
|
if (!strncmp(path, _PATH_DEV, strlen(_PATH_DEV))) {
|
||||||
unavailable:
|
unavailable:
|
||||||
_d("TTY %s not available at the moment, registering anyway.", path);
|
dbg("TTY %s not available at the moment, registering anyway.", path);
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,14 +99,14 @@ char *tty_atcon(void)
|
|||||||
|
|
||||||
fp = fopen("/sys/class/tty/console/active", "r");
|
fp = fopen("/sys/class/tty/console/active", "r");
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
_e("Cannot find system console, is sysfs not mounted?");
|
errx(1, "Cannot find system console, is sysfs not mounted?");
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = malloc(512);
|
buf = malloc(512);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
_pe("Failed allocating memory for @console");
|
err(1, "Failed allocating memory for @console");
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -118,7 +118,7 @@ char *tty_atcon(void)
|
|||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
ptr = chomp(buf);
|
ptr = chomp(buf);
|
||||||
_d("consoles: %s", ptr);
|
dbg("consoles: %s", ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
dev = strtok_r(ptr, " \t", &save);
|
dev = strtok_r(ptr, " \t", &save);
|
||||||
@@ -133,7 +133,9 @@ char *tty_atcon(void)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* tty_parse_args - Parse cmdline args for a tty
|
* tty_parse_args - Parse cmdline args for a tty
|
||||||
* @cmd: command or tty
|
* @tty: service tty
|
||||||
|
* @cmd: command or tty
|
||||||
|
* @args: args from strtok_r()
|
||||||
*
|
*
|
||||||
* A Finit tty line can use the internal getty implementation or an
|
* A Finit tty line can use the internal getty implementation or an
|
||||||
* external one, like the BusyBox getty for instance. This function
|
* external one, like the BusyBox getty for instance. This function
|
||||||
@@ -151,9 +153,10 @@ char *tty_atcon(void)
|
|||||||
* Different getty implementations prefer the TTY device argument in
|
* Different getty implementations prefer the TTY device argument in
|
||||||
* different order, so take care to investigate this first.
|
* different order, so take care to investigate this first.
|
||||||
*/
|
*/
|
||||||
int tty_parse_args(char *cmd, struct tty *tty)
|
int tty_parse_args(struct tty *tty, char *cmd, char **args)
|
||||||
{
|
{
|
||||||
char *dev = NULL;
|
char *dev = NULL;
|
||||||
|
int passenv = 0;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@@ -165,6 +168,8 @@ int tty_parse_args(char *cmd, struct tty *tty)
|
|||||||
tty->nologin = 1;
|
tty->nologin = 1;
|
||||||
else if (!strcmp(cmd, "notty"))
|
else if (!strcmp(cmd, "notty"))
|
||||||
tty->notty = 1; /* for board bringup */
|
tty->notty = 1; /* for board bringup */
|
||||||
|
else if (!strcmp(cmd, "passenv"))
|
||||||
|
passenv = 1;
|
||||||
else if (!strcmp(cmd, "rescue"))
|
else if (!strcmp(cmd, "rescue"))
|
||||||
tty->rescue = 1; /* for rescue shells */
|
tty->rescue = 1; /* for rescue shells */
|
||||||
else if (whichp(cmd)) /* in $PATH? */
|
else if (whichp(cmd)) /* in $PATH? */
|
||||||
@@ -172,7 +177,7 @@ int tty_parse_args(char *cmd, struct tty *tty)
|
|||||||
else
|
else
|
||||||
tty->args[tty->num++] = cmd;
|
tty->args[tty->num++] = cmd;
|
||||||
|
|
||||||
cmd = strtok(NULL, " ");
|
cmd = strtok_r(NULL, " ", args);
|
||||||
} while (cmd && tty->num < NELEMS(tty->args));
|
} while (cmd && tty->num < NELEMS(tty->args));
|
||||||
|
|
||||||
/* rescue shells are always notty */
|
/* rescue shells are always notty */
|
||||||
@@ -220,16 +225,23 @@ int tty_parse_args(char *cmd, struct tty *tty)
|
|||||||
|
|
||||||
tty->dev = tty_canonicalize(dev);
|
tty->dev = tty_canonicalize(dev);
|
||||||
if (!tty->dev) {
|
if (!tty->dev) {
|
||||||
_e("Incomplete or non-existing TTY device given, cannot register.");
|
errx(1, "Incomplete or non-existing TTY device given, cannot register.");
|
||||||
return errno = EINVAL;
|
return errno = EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("Registering %s getty on TTY %s at %s baud with term %s", tty->cmd ? "external" : "built-in",
|
dbg("Registering %s getty on TTY %s at %s baud with term %s", tty->cmd ? "external" : "built-in",
|
||||||
tty->dev, tty->baud ?: "0", tty->term ?: "N/A");
|
tty->dev, tty->baud ?: "0", tty->term ?: "N/A");
|
||||||
|
|
||||||
/* Built-in getty now comes as standalone program */
|
/* Built-in getty now comes as standalone program */
|
||||||
if (!tty->cmd)
|
if (!tty->cmd) {
|
||||||
|
if (passenv && tty->num < NELEMS(tty->args)) {
|
||||||
|
for (i = tty->num; i > 0; i--)
|
||||||
|
tty->args[i] = tty->args[i - 1];
|
||||||
|
tty->args[0] = "-p";
|
||||||
|
tty->num++;
|
||||||
|
}
|
||||||
tty->cmd = _PATH_GETTY;
|
tty->cmd = _PATH_GETTY;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -281,21 +293,21 @@ int tty_exec(svc_t *svc)
|
|||||||
|
|
||||||
dev = tty_canonicalize(svc->dev);
|
dev = tty_canonicalize(svc->dev);
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
_d("%s: Cannot find TTY device: %s", svc->dev, strerror(errno));
|
dbg("%s: Cannot find TTY device: %s", svc->dev, strerror(errno));
|
||||||
return EX_CONFIG;
|
return EX_CONFIG;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tty_exists(dev)) {
|
if (!tty_exists(dev)) {
|
||||||
_d("%s: Not a valid TTY: %s", dev, strerror(errno));
|
dbg("%s: Not a valid TTY: %s", dev, strerror(errno));
|
||||||
return EX_OSFILE;
|
return EX_OSFILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (svc->nologin) {
|
if (svc->nologin) {
|
||||||
_d("%s: Starting /bin/sh ...", dev);
|
dbg("%s: Starting /bin/sh ...", dev);
|
||||||
return run_sh(dev, svc->noclear, svc->nowait, svc->rlimit);
|
return run_sh(dev, svc->noclear, svc->nowait, svc->rlimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("%s: Starting %s ...", dev, svc->cmd);
|
dbg("%s: Starting %s ...", dev, svc->cmd);
|
||||||
for (i = 1, j = 0; i < MAX_NUM_SVC_ARGS; i++) {
|
for (i = 1, j = 0; i < MAX_NUM_SVC_ARGS; i++) {
|
||||||
if (!svc->args[i][0])
|
if (!svc->args[i][0])
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* Finit TTY handling
|
/* Finit TTY handling
|
||||||
*
|
*
|
||||||
* Copyright (c) 2013 Mattias Walström <lazzer@gmail.com>
|
* Copyright (c) 2013 Mattias Walström <lazzer@gmail.com>
|
||||||
* Copyright (c) 2013-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2013-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -48,7 +48,7 @@ char *tty_canonicalize (char *dev);
|
|||||||
int tty_isatcon (char *dev);
|
int tty_isatcon (char *dev);
|
||||||
char *tty_atcon (void);
|
char *tty_atcon (void);
|
||||||
|
|
||||||
int tty_parse_args (char *cmdline, struct tty *tty);
|
int tty_parse_args (struct tty *tty, char *cmd, char **args);
|
||||||
|
|
||||||
int tty_exists (char *dev);
|
int tty_exists (char *dev);
|
||||||
int tty_exec (svc_t *tty);
|
int tty_exec (svc_t *tty);
|
||||||
|
|||||||
+45
-9
@@ -1,6 +1,6 @@
|
|||||||
/* Misc. shared utility functions for initctl, reboot and finit
|
/* Misc. shared utility functions for initctl, reboot and finit
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016-2022 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -30,6 +30,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <regex.h>
|
#include <regex.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#ifdef HAVE_TERMIOS_H
|
#ifdef HAVE_TERMIOS_H
|
||||||
# include <termios.h>
|
# include <termios.h>
|
||||||
@@ -303,13 +304,10 @@ int strtobytes(char *arg)
|
|||||||
|
|
||||||
char *sig2str(int signo)
|
char *sig2str(int signo)
|
||||||
{
|
{
|
||||||
static char signame[8];
|
|
||||||
|
|
||||||
if (signo < 1 || signo >= (int)NELEMS(signames))
|
if (signo < 1 || signo >= (int)NELEMS(signames))
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
snprintf(signame, sizeof(signame), "/%s", signames[signo]);
|
return signames[signo];
|
||||||
return signame;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -336,13 +334,10 @@ int str2sig(char *sig)
|
|||||||
|
|
||||||
char *code2str(int code)
|
char *code2str(int code)
|
||||||
{
|
{
|
||||||
static char codename[20];
|
|
||||||
|
|
||||||
if (code < 0 || code >= (int)NELEMS(exitcodes))
|
if (code < 0 || code >= (int)NELEMS(exitcodes))
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
snprintf(codename, sizeof(codename), "/%s", exitcodes[code]);
|
return exitcodes[code];
|
||||||
return codename;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -472,6 +467,47 @@ char *sanitize(char *arg, size_t len)
|
|||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void de_dotdot(char *file)
|
||||||
|
{
|
||||||
|
char *cp, *cp2;
|
||||||
|
int l;
|
||||||
|
|
||||||
|
/* Remove leading ./ and any /./ sequences. */
|
||||||
|
while (strncmp(file, "./", 2) == 0)
|
||||||
|
memmove(file, file + 2, strlen(file) - 1);
|
||||||
|
while ((cp = strstr(file, "/./")))
|
||||||
|
memmove(cp, cp + 2, strlen(cp) - 1);
|
||||||
|
|
||||||
|
/* Alternate between removing leading ../ and removing xxx/../ */
|
||||||
|
for (;;) {
|
||||||
|
while (strncmp(file, "../", 3) == 0)
|
||||||
|
memmove(file, file + 3, strlen(file) - 2);
|
||||||
|
cp = strstr(file, "/../");
|
||||||
|
if (!cp)
|
||||||
|
break;
|
||||||
|
|
||||||
|
for (cp2 = cp - 1; cp2 >= file && *cp2 != '/'; --cp2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
memmove(cp2 + 1, cp + 4, strlen(cp + 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Also elide any xxx/.. at the end. */
|
||||||
|
while ((l = strlen(file)) > 3 && strcmp((cp = file + l - 3), "/..") == 0) {
|
||||||
|
for (cp2 = cp - 1; cp2 >= file && *cp2 != '/'; --cp2)
|
||||||
|
continue;
|
||||||
|
if (cp2 < file)
|
||||||
|
break;
|
||||||
|
*cp2 = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Collapse any multiple / sequences. */
|
||||||
|
while ((cp = strstr(file, "//"))) {
|
||||||
|
cp2 = cp + 1;
|
||||||
|
memmove(cp, cp2, strlen(cp2) + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int hasopt(char *opts, char *opt)
|
static int hasopt(char *opts, char *opt)
|
||||||
{
|
{
|
||||||
char buf[strlen(opts) + 1];
|
char buf[strlen(opts) + 1];
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user