mirror of
https://github.com/troglobit/finit.git
synced 2026-10-14 10:19:36 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8379b4927b | ||
|
|
6a7f48970c | ||
|
|
d797754ca8 | ||
|
|
770a79fa89 | ||
|
|
ff24ee3553 | ||
|
|
25c194ef93 | ||
|
|
91a9c83928 | ||
|
|
9b022ed7a4 | ||
|
|
ca3fc057f2 | ||
|
|
bf6e599584 | ||
|
|
89c7171223 | ||
|
|
c41f3f4a06 | ||
|
|
0a54a9624a | ||
|
|
1e238eec61 | ||
|
|
4163527006 | ||
|
|
f06e17ccc6 | ||
|
|
fe41b9c4b8 | ||
|
|
7cf3ef80db | ||
|
|
69016bb8f5 | ||
|
|
f7d5b588c9 | ||
|
|
0ad99ce054 | ||
|
|
1176961e7b | ||
|
|
27c839bc92 | ||
|
|
6149e93aca | ||
|
|
4e7baa807e | ||
|
|
54cfa74042 | ||
|
|
97ce0aa519 | ||
|
|
e72b61c9c9 | ||
|
|
b66069278f | ||
|
|
1192506d43 | ||
|
|
decdc1560a | ||
|
|
f6372de6a9 | ||
|
|
9052248127 | ||
|
|
6ab9c8fad6 | ||
|
|
619bd03551 | ||
|
|
e301877b16 | ||
|
|
3b67afe480 | ||
|
|
9a9a9f4bfe | ||
|
|
f38299bfca | ||
|
|
99901782ff | ||
|
|
912a336997 | ||
|
|
c3eca9fe8f | ||
|
|
225510a270 | ||
|
|
4389fbd8bc | ||
|
|
920382518f | ||
|
|
997a699b7e | ||
|
|
21db27ee75 | ||
|
|
fa0c63070c | ||
|
|
9bfc9092b8 | ||
|
|
1c6464a7a8 | ||
|
|
51adba4387 | ||
|
|
bb1aed1010 | ||
|
|
cf4a1332f9 | ||
|
|
d70fb85aaf | ||
|
|
fc37b854ae | ||
|
|
ca210f5431 | ||
|
|
a19a3c774e | ||
|
|
a4f1330eae | ||
|
|
38d768ac9e | ||
|
|
36b14f9ff7 | ||
|
|
bdbd2afc40 | ||
|
|
33bb6ed5ac | ||
|
|
212083b922 | ||
|
|
55c49a0bf0 | ||
|
|
b369e1cfa2 | ||
|
|
cfefe23275 | ||
|
|
338c358a75 | ||
|
|
fe017642de | ||
|
|
8d271ac5b8 | ||
|
|
744719219e | ||
|
|
7bf2fcb6e3 | ||
|
|
ae9ed20d94 | ||
|
|
a5c9d0a3f4 | ||
|
|
a8c071c5ef | ||
|
|
238f63c0d3 | ||
|
|
41647a814c | ||
|
|
765ef63274 | ||
|
|
6a5f4398a2 | ||
|
|
7fc515678f | ||
|
|
e410a24d13 | ||
|
|
397f67d03a | ||
|
|
b4b9111b33 | ||
|
|
c19489d6c3 | ||
|
|
00a2840853 | ||
|
|
d1718d338e | ||
|
|
58ade5d74e | ||
|
|
c391e04983 | ||
|
|
85fe613b30 | ||
|
|
880ad98dbe | ||
|
|
b1a88df9fc | ||
|
|
aaf7888411 | ||
|
|
6edb01a72b | ||
|
|
636f6678ed | ||
|
|
3b62f46599 | ||
|
|
49f0d94b95 | ||
|
|
abccb26a83 | ||
|
|
0848b9b07a | ||
|
|
c64188bfc5 | ||
|
|
5e789401d4 | ||
|
|
744fdd654f | ||
|
|
f51fde4d46 | ||
|
|
85261c9acd | ||
|
|
6a1082a947 | ||
|
|
2094d2a53a | ||
|
|
d7da177742 | ||
|
|
170e5aa3fd | ||
|
|
f8ef8a1616 | ||
|
|
f5f1a55747 | ||
|
|
a36aade7f4 | ||
|
|
76fc72770e | ||
|
|
b64dbbf8d0 | ||
|
|
d371b85c47 | ||
|
|
053304012f | ||
|
|
12d14aae84 | ||
|
|
6a7f115781 | ||
|
|
423c8d41a7 | ||
|
|
f2cab53e55 | ||
|
|
33fd6f0049 | ||
|
|
e83dcafb02 | ||
|
|
9a98bff23f | ||
|
|
1a2f7d162b | ||
|
|
5579ba16b1 | ||
|
|
510b36645b | ||
|
|
67cd88cd23 | ||
|
|
a04a6eda12 | ||
|
|
94525d6aae | ||
|
|
1d14806fd8 | ||
|
|
5e6f64eec9 | ||
|
|
df22628183 | ||
|
|
4870cab898 | ||
|
|
859c216347 | ||
|
|
931565c425 | ||
|
|
3006caf670 | ||
|
|
1269f082de | ||
|
|
7d444e07a5 | ||
|
|
6ec4dce5f9 | ||
|
|
8a0edbe801 | ||
|
|
46683f8eb8 | ||
|
|
fb16abd855 | ||
|
|
060de93b5b | ||
|
|
231b887b2a | ||
|
|
dddd45e3b5 | ||
|
|
cb9f6213dc | ||
|
|
f33ed869e4 | ||
|
|
4790344fbe | ||
|
|
a40858f162 | ||
|
|
682e80fed5 | ||
|
|
cd91e2c66c | ||
|
|
470549badb | ||
|
|
a85c3628b8 | ||
|
|
53ac0ffdfb | ||
|
|
eee6ffe95c | ||
|
|
a5491b3ded | ||
|
|
a1ea8ff564 | ||
|
|
0dffa731d2 | ||
|
|
9516c28a8a | ||
|
|
fa0a4e8579 | ||
|
|
a487a30814 | ||
|
|
40db4f4f58 | ||
|
|
3a1ad67e92 | ||
|
|
43942ab513 | ||
|
|
3b2f2690e7 | ||
|
|
5684b761da | ||
|
|
59f22c7d27 | ||
|
|
f522a26125 | ||
|
|
efb1d40ffd | ||
|
|
ea591c7580 | ||
|
|
af9a06466c | ||
|
|
7ed9f2ad05 | ||
|
|
65ccc407fa | ||
|
|
7fe9f3c4b6 | ||
|
|
24299ab5d9 | ||
|
|
e9670b87b3 | ||
|
|
406339e755 | ||
|
|
dc7039b8d8 | ||
|
|
90249e50ef | ||
|
|
b8e6954c46 | ||
|
|
4585aa0fb4 | ||
|
|
f2655d14c8 | ||
|
|
6d1d51b28c | ||
|
|
b9d233d19e | ||
|
|
2ec132c75a | ||
|
|
3092d55ec5 | ||
|
|
cd791afea5 | ||
|
|
829405f966 | ||
|
|
72526d9e88 | ||
|
|
f704eab6d7 | ||
|
|
a50bfc016e | ||
|
|
396c1b491f | ||
|
|
df89cc79b9 | ||
|
|
3429901d83 | ||
|
|
dedf885b92 | ||
|
|
93a21197ab | ||
|
|
8a0fffb00d | ||
|
|
7fdb280712 | ||
|
|
0a643953c0 | ||
|
|
fd837a4242 | ||
|
|
2759992dd2 | ||
|
|
d880cd75ae | ||
|
|
29fe8cc73d | ||
|
|
2b6f00f126 | ||
|
|
86e534095d | ||
|
|
865a3a7a4a | ||
|
|
2dc7de3aa2 | ||
|
|
06a5b43005 | ||
|
|
38939cc57e | ||
|
|
a3eadb72a7 | ||
|
|
6d41725387 | ||
|
|
ceb91f746c | ||
|
|
a8802ab0d2 | ||
|
|
ad98f69560 | ||
|
|
5953090688 | ||
|
|
22a69d8cca | ||
|
|
710a3d2c8f | ||
|
|
658fb9b037 | ||
|
|
a84bb9042f | ||
|
|
eeb13dba74 | ||
|
|
3d20237959 | ||
|
|
ddf1bce642 | ||
|
|
93cd4116db | ||
|
|
1df6a91a94 | ||
|
|
c64a71ff30 | ||
|
|
b2b6fd25d8 | ||
|
|
3ca548b681 | ||
|
|
ba2ab4b446 | ||
|
|
a8183b0559 | ||
|
|
227e4fa097 | ||
|
|
3d68ebbf54 | ||
|
|
6e017025aa | ||
|
|
5f818f917e | ||
|
|
0da1deb487 | ||
|
|
0337985422 | ||
|
|
f59d41cdec | ||
|
|
1cc998eb60 | ||
|
|
8c1d84305d | ||
|
|
7e4e5127c7 | ||
|
|
3b813bca68 | ||
|
|
a1f210bc70 | ||
|
|
0ecf46d7a9 | ||
|
|
268304927d | ||
|
|
fa02b59db5 | ||
|
|
2c904b5b44 | ||
|
|
4191abc79f | ||
|
|
abb928f60b | ||
|
|
3c52118a8e | ||
|
|
5354a57313 | ||
|
|
92b1d882e5 | ||
|
|
fd7a6c5020 | ||
|
|
a61551d15f | ||
|
|
7f62a69f74 | ||
|
|
c969bda62d | ||
|
|
af41fcd35e | ||
|
|
84e9569be6 | ||
|
|
a4ece0fe3f | ||
|
|
b2f66da1f9 | ||
|
|
abbc0a1d5c | ||
|
|
37e420bd35 | ||
|
|
d72eb45d6e | ||
|
|
30c593f64e | ||
|
|
f858d94d2a | ||
|
|
992bab2f8f | ||
|
|
72c9681ffb | ||
|
|
e439b79e82 | ||
|
|
36e001d636 | ||
|
|
75aa14466f | ||
|
|
7f899b7a91 | ||
|
|
1c177fd953 | ||
|
|
617ec7c147 | ||
|
|
192d3aafe7 | ||
|
|
f11ebb0046 | ||
|
|
b5e260b9e0 | ||
|
|
45c10edad6 | ||
|
|
b60d8ce4b6 | ||
|
|
d35a8bbda9 | ||
|
|
c616270ccb | ||
|
|
890ac2f4e1 | ||
|
|
8063b1bfe1 | ||
|
|
0bcfb464ce | ||
|
|
dc5b1a5980 | ||
|
|
14555d7a7b | ||
|
|
a06127b990 | ||
|
|
3b8e7d677f | ||
|
|
097fce4170 | ||
|
|
306bf0f191 | ||
|
|
f25390004b | ||
|
|
cbd4cc8d34 | ||
|
|
44591c6e51 | ||
|
|
0e51a1eed8 | ||
|
|
c315fb5637 | ||
|
|
1017e7b8e5 | ||
|
|
8ef216af62 | ||
|
|
a9b9631098 | ||
|
|
cc186334e0 | ||
|
|
e1b87d707f | ||
|
|
68e7bcba4c | ||
|
|
f9783b4b41 | ||
|
|
32d9afc7bb | ||
|
|
91b550662e | ||
|
|
d87af8270e | ||
|
|
366c23f5d1 | ||
|
|
0d4bc69584 | ||
|
|
cccf199280 | ||
|
|
a1c33dec21 | ||
|
|
df303c6243 | ||
|
|
6a6ae6fa3b | ||
|
|
4011b5a3b8 | ||
|
|
68ef6ec108 | ||
|
|
89a9d92d6c | ||
|
|
15cb576293 | ||
|
|
90734eee16 | ||
|
|
71915e0e14 | ||
|
|
112ab2c22f | ||
|
|
8f00ac2e90 | ||
|
|
6fb070c75c | ||
|
|
8fd431f3e9 | ||
|
|
50f128cd1d | ||
|
|
f6fa576270 | ||
|
|
b26d30757d | ||
|
|
dc9d0b6fca | ||
|
|
ff95ca92b1 | ||
|
|
c939aed87f | ||
|
|
71ea9e2ea3 | ||
|
|
b6bd10d960 | ||
|
|
87d8157175 | ||
|
|
cf6faa9eeb | ||
|
|
80a71aff07 | ||
|
|
04a4653e9b | ||
|
|
3aa9d9f451 | ||
|
|
c1afca9c33 | ||
|
|
205915d42f | ||
|
|
631f89b58c | ||
|
|
6d1c245985 | ||
|
|
fc08b0c65b | ||
|
|
83021b11d8 | ||
|
|
5309ece2f9 | ||
|
|
6480850ee2 | ||
|
|
eaa82377c4 | ||
|
|
5b3df3654c | ||
|
|
55cb50ef90 | ||
|
|
3f7e03e813 | ||
|
|
ab723d2f31 | ||
|
|
bc149d95fc | ||
|
|
c605874b26 | ||
|
|
c33ba6a477 | ||
|
|
63199d368f | ||
|
|
db3263c441 | ||
|
|
925212f7cf | ||
|
|
ad401280c2 | ||
|
|
f3d2586417 | ||
|
|
6fc1d27bcf | ||
|
|
f3305e75b7 | ||
|
|
e4c12314b1 | ||
|
|
c9a1a64ce5 | ||
|
|
3843f62aa8 | ||
|
|
ef54c4826b | ||
|
|
2fac65becb | ||
|
|
46b253dea6 | ||
|
|
b04983c3f3 | ||
|
|
f2d142ef57 | ||
|
|
33ce746e58 | ||
|
|
6ecb86b4a7 | ||
|
|
338810b886 | ||
|
|
c1344e89ff | ||
|
|
bc35b42bd2 | ||
|
|
dcf8fbe235 | ||
|
|
c82a2ce215 | ||
|
|
e1bb5e3396 | ||
|
|
8198582c10 | ||
|
|
0d19842aa1 | ||
|
|
6f665ab283 | ||
|
|
3f731aa5a3 | ||
|
|
9e8a01669e | ||
|
|
cbafbaea1d | ||
|
|
f534368b33 | ||
|
|
78fc9fccc5 | ||
|
|
3f7df3d35e | ||
|
|
9fc33418f9 | ||
|
|
72bc3b1a91 | ||
|
|
d6ea1c0cab | ||
|
|
523a270f22 | ||
|
|
3258edc246 | ||
|
|
32b7a14cb3 |
No files matched your search
@@ -0,0 +1,3 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: [troglobit]
|
||||||
+8
-1
@@ -2,13 +2,15 @@
|
|||||||
*.o
|
*.o
|
||||||
*.so
|
*.so
|
||||||
*.gz
|
*.gz
|
||||||
|
ID
|
||||||
GPATH
|
GPATH
|
||||||
GRTAGS
|
GRTAGS
|
||||||
GSYMS
|
GSYMS
|
||||||
GTAGS
|
GTAGS
|
||||||
|
|
||||||
# GNU configure and build system
|
# GNU configure and build system
|
||||||
/autom4te.cache/*
|
/.deps
|
||||||
|
/autom4te.cache
|
||||||
/aclocal.m4
|
/aclocal.m4
|
||||||
/ar-lib
|
/ar-lib
|
||||||
/compile
|
/compile
|
||||||
@@ -33,3 +35,8 @@ GTAGS
|
|||||||
/.config
|
/.config
|
||||||
/.stamp
|
/.stamp
|
||||||
/.unpacked
|
/.unpacked
|
||||||
|
|
||||||
|
# WeOS build system
|
||||||
|
/.autoconf
|
||||||
|
/.automake
|
||||||
|
/.built
|
||||||
+13
-8
@@ -13,10 +13,12 @@ compiler:
|
|||||||
- gcc
|
- gcc
|
||||||
- clang
|
- clang
|
||||||
|
|
||||||
|
# The secure: declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||||
|
# via the "travis encrypt" command using the project repo's public key
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
- PKG_CONFIG_PATH=/tmp/lib/pkgconfig
|
||||||
# via the "travis encrypt" command using the project repo's public key
|
- CFLAGS="-W -Wall -Wextra"
|
||||||
- secure: "eOiuHs02lG2Uv146K9dMqucGTWUJFEhpz1oAtwe+kPrRXsXWc20hYMO+DSpMgD05vSvNeQA6p7h7LdRFQ+/g/Obj27TsOE+RKkUvRAtdwzxnKVyii9C/nmML8cFw7rIA0VS8O9mAkVYeyDxNDupBp3e9DPCibhKPvqCvioTnyy4="
|
- secure: "eOiuHs02lG2Uv146K9dMqucGTWUJFEhpz1oAtwe+kPrRXsXWc20hYMO+DSpMgD05vSvNeQA6p7h7LdRFQ+/g/Obj27TsOE+RKkUvRAtdwzxnKVyii9C/nmML8cFw7rIA0VS8O9mAkVYeyDxNDupBp3e9DPCibhKPvqCvioTnyy4="
|
||||||
|
|
||||||
addons:
|
addons:
|
||||||
@@ -28,25 +30,28 @@ addons:
|
|||||||
name: "troglobit/finit"
|
name: "troglobit/finit"
|
||||||
description: "finit | Fast & Extensible init for Linux"
|
description: "finit | Fast & Extensible init for Linux"
|
||||||
notification_email: troglobit@gmail.com
|
notification_email: troglobit@gmail.com
|
||||||
build_command_prepend: "./autogen.sh && PKG_CONFIG_PATH=/tmp/lib/pkgconfig ./configure --prefix=/tmp"
|
build_command_prepend: "./autogen.sh && ./configure --prefix=/tmp"
|
||||||
build_command: "make"
|
build_command: "make"
|
||||||
branch_pattern: dev
|
branch_pattern: dev
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- wget https://github.com/troglobit/libuev/releases/download/v2.1.0/libuev-2.1.0.tar.xz
|
- wget https://github.com/troglobit/libuev/releases/download/v2.2.0/libuev-2.2.0.tar.xz
|
||||||
- wget https://github.com/troglobit/libite/releases/download/v2.0.1/libite-2.0.1.tar.xz
|
- wget https://github.com/troglobit/libite/releases/download/v2.0.1/libite-2.0.1.tar.xz
|
||||||
- tar xf libuev-2.1.0.tar.xz
|
- tar xf libuev-2.2.0.tar.xz
|
||||||
- tar xf libite-2.0.1.tar.xz
|
- tar xf libite-2.0.1.tar.xz
|
||||||
- (cd libuev-2.1.0 && ./configure --prefix=/tmp && make && make install-strip)
|
- (cd libuev-2.2.0 && ./configure --prefix=/tmp && make && make install-strip)
|
||||||
- (cd libite-2.0.1 && ./configure --prefix=/tmp && make && make install-strip)
|
- (cd libite-2.0.1 && ./configure --prefix=/tmp && make && make install-strip)
|
||||||
|
|
||||||
# Custom build script for the time being, no "make test" yet
|
# Custom build script for the time being, no "make test" yet
|
||||||
script:
|
script:
|
||||||
- ./autogen.sh
|
- ./autogen.sh
|
||||||
- PKG_CONFIG_PATH=/tmp/lib/pkgconfig ./configure --prefix=/tmp
|
- ./configure --prefix=/tmp --disable-inetd --enable-static
|
||||||
|
- make clean
|
||||||
|
- make V=1 -j5
|
||||||
|
- ./configure --prefix=/tmp --enable-inetd-echo-plugin --enable-inetd-time-plugin --enable-x11-common-plugin --enable-inetd-chargen-plugin --enable-fallback-shell --enable-watchdog --enable-logit
|
||||||
- cat config.log
|
- cat config.log
|
||||||
- make clean
|
- make clean
|
||||||
- make -j5 V=1
|
- make V=1 -j5
|
||||||
- make install-strip
|
- make install-strip
|
||||||
- tree /tmp
|
- tree /tmp
|
||||||
- ldd /tmp/sbin/finit
|
- ldd /tmp/sbin/finit
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
Current Maintainer(s):
|
Current Maintainer(s):
|
||||||
* Joachim Nilsson <troglobit@gmail.com>
|
* Joachim Nilsson <troglobit@gmail.com>
|
||||||
|
|
||||||
|
Major Contributors:
|
||||||
|
* Tobias Waldekranz <tobias@waldekranz.com>
|
||||||
|
* Mattias Walström <mattias.walstrom@westermo.se>
|
||||||
|
* Jonas Johansson <jonas.johansson@westermo.se>
|
||||||
|
|
||||||
Original Author(s):
|
Original Author(s):
|
||||||
* Claudio Matsuoka <cmatsuoka@gmail.com>
|
* Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||||
|
|
||||||
+155
-4
@@ -4,17 +4,141 @@ Change Log
|
|||||||
All relevant changes are documented in this file.
|
All relevant changes are documented in this file.
|
||||||
|
|
||||||
|
|
||||||
[3.1][] - 2017-12-xx
|
[3.2][UNRELEASED] - 2020-04-xx
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
Bug fix release, but also cgroups and a new progress!
|
||||||
|
|
||||||
|
https://twitter.com/b0rk/status/1214341831049252870?s=20
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
* Introducing Finit progress 𝓜𝓸𝓭𝓮𝓻𝓷
|
||||||
|
* Support for `sysv` start/stop scripts as well as monitoring forking
|
||||||
|
services, stared using `sysv` or `service` stanza
|
||||||
|
* Support for custom `kill:DELAY`, default 3 sec.
|
||||||
|
* Support for custom `halt:SIGNAL`, default SIGTERM
|
||||||
|
* Support for tracking custom PID files, using `pid:!/path/to/foo.pid`,
|
||||||
|
useful with new `sysv` or `service` which fork to background
|
||||||
|
* Support starting run/task/services without absolute path, trust `$PATH`
|
||||||
|
* Add support for `--disable-docs` and `--disable-contrib` to speed up
|
||||||
|
builds and work around issue with massively parallel builds
|
||||||
|
* Add support for `@console` also for external getty
|
||||||
|
* Add `-b`, batch mode, for non-interactive use to `initctl`
|
||||||
|
* Prefer udev to handle `/dev/` if mdev is also available
|
||||||
|
* Redirect dbus daemon output to syslog
|
||||||
|
* Set `$SHELL`, like `$PATH`, to a sane default value, needed by BusyBox
|
||||||
|
* Finit no longer automatically reloads its `*.conf` files after running
|
||||||
|
`/etc/rc.local` or run-parts. Use `initctl reload` instead.
|
||||||
|
* `initctl` without an argument or option now defaults to list services
|
||||||
|
* Convert built-in watchdog daemon to standalone mini watchdogd, issue #102
|
||||||
|
* Improved watchdog hand-over, now based on `svc_t` and not PID
|
||||||
|
* Extended bootstrap, runlevel S, timeout: 10 --> 120 sec. before services
|
||||||
|
not allowed in the runtime runlevel are unconditionally stopped
|
||||||
|
* Removed `HOOK_SVC_START` and `HOOK_SVC_LOST`, caused more problems
|
||||||
|
than they were worth. Users are encouraged to use accounting instead
|
||||||
|
* Skip displaying "Restarting ..." progress for bootstrap processes
|
||||||
|
* Added a simple work queue mechanism to queue up work at boot + runtime
|
||||||
|
- Postpone deletion of `svc_t` until any `SIGKILL` timer has elapsed
|
||||||
|
- As long as a stepped service changes state we queue another step all
|
||||||
|
event, because services may depend on each other
|
||||||
|
* Require new libuEv API: `uev_init1()` to reduce event cache so that
|
||||||
|
the kernel can invalidate deleted events before enqueing to userspace
|
||||||
|
* Rename `hwclock.so` plugin to `rtc.so` since it now is stand-alone
|
||||||
|
from the `hwclock` tool. Note: the kernel can also be set to load
|
||||||
|
and store RTC to/from system clock at boot/halt as well, issue #110
|
||||||
|
* New plugin to support cold plugging devices, auto-loading of modules
|
||||||
|
at boot. Detects required modules by reading `/sys/devices/*`
|
||||||
|
* New plugin for `/etc/modules-load.d/` by Robert Andersson, Atlas Copco
|
||||||
|
* New `name:foo` support for services, by Robert Andersson, Atlas Copco
|
||||||
|
* New `manual:yes` support for services, by Robert Andersson, Atlas Copco
|
||||||
|
* New `log:console` support for services, by Robert Andersson, Atlas Copco
|
||||||
|
* Support for `:ID` as a string, by Jonas Johansson, Westermo
|
||||||
|
* Support for auto-reload, instead of having to do `initctl reload`,
|
||||||
|
when a service configuration has changed. Disabled by default, but
|
||||||
|
can be enabled with `./configure --enable-auto-reload`
|
||||||
|
* Support for logging security related events, e.g., runlevel change,
|
||||||
|
star/stop or failure to start services, by Jonas Holmberg, Westermo
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
* Fix #96: Start udevd as a proper service
|
||||||
|
* Ensure we track run commands as well as task/service, once per runlevel
|
||||||
|
* Fix #98: FTBFS with `--disable-inetd`
|
||||||
|
* Make sure to unblock UDP inetd services when connection terminates.
|
||||||
|
Regression introduced in v3.1
|
||||||
|
* Ensure run/tasks also go to stopping state on exit, like services,
|
||||||
|
otherwise it is unnecessarily hard to restart them
|
||||||
|
* Fix #99: Do not try to `SIGKILL` inetd services, they are not backed
|
||||||
|
by a PID. This caused a use after free issue crashing finit. Found
|
||||||
|
and fixed by Tobias Waldekranz, Westermo
|
||||||
|
* Fix missing OS/Finit title bug, adds leading newline before banner
|
||||||
|
* Remove "Failed connecting to watchdog ..." error message on systems
|
||||||
|
that do not have a watchdog
|
||||||
|
* Fix #100: Early condition handling may not work if `/var/run` does
|
||||||
|
not yet exist (symlink to `/run`). Added compat layer for access
|
||||||
|
* Fix #103: Register multiple getty if `@console` resolves to >1 TTY,
|
||||||
|
* Fix #105: Only remove /etc/nologin when moving from runlevel 0, 1, 6
|
||||||
|
* Fix #106: Don't mark inetd connections for deletion at .conf reload.
|
||||||
|
Fixed by Jonas Johansson, Westermo
|
||||||
|
* Fix #107: Stop spawned inetd conncections when stopping inetd service.
|
||||||
|
Fixed by Jonas Johansson, Westermo
|
||||||
|
* Fix #109: Support for PID files in sub-directories to `/var/run`
|
||||||
|
* Handle rename of PID files, by Robert Andersson, Atlas Copco
|
||||||
|
* Fix #111: Only restart inetd services when necessary. E.g., if the
|
||||||
|
listening interface is changed. Only stop established connections
|
||||||
|
which are no longer allowed, i.e. do not touch already allowed
|
||||||
|
established connections. Fixed by Jonas Johansson, Westermo
|
||||||
|
* Fix #120: Redirect `stdin` to `/dev/null` for services by default
|
||||||
|
* Fix #122: Switch to `nanosleep()` to achieve "signal safe" sleep,
|
||||||
|
fixed by Jacques de Laval, Westermo
|
||||||
|
* Fix #124: Lingering processes in process group when session leader
|
||||||
|
exits. E.g., lingering `logit` processes when parent dies
|
||||||
|
* Fix: update inetd service args on config change. Found and fixed by
|
||||||
|
Petrus Hellgren, Westermo
|
||||||
|
* Fix service name matching, e.g. for condition handling, may match with
|
||||||
|
wrong service, by Jonas Holmberg, Westermo
|
||||||
|
* Run all run-parts scripts using `/bin/sh -c foo` just like the standard
|
||||||
|
run-parts tool. Found by Magnus Malm, Westermo
|
||||||
|
* Fix `initctl [start | restart]`, should behave the same for services
|
||||||
|
that have crashed. Found by Mattias Walström, Westermo
|
||||||
|
* Wait for bootstrap phase to complete before cleaning out any bootstrap
|
||||||
|
processes that have stopped, they may be restarted again
|
||||||
|
* Reassert condition when an unmodified run/task/service goes from
|
||||||
|
WAITING back to RUNNING again after a reconfiguration event.
|
||||||
|
Found and fixed by Jonas Johansson, Westermo
|
||||||
|
* Restore Ctrl-D and Ctrl-U support in built-in getty
|
||||||
|
* Remove service condition when service is deleted
|
||||||
|
* Fix C++ compilation issues, by Robert Andersson, Atlas Copco
|
||||||
|
|
||||||
|
|
||||||
|
[3.1][] - 2018-01-23
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
Finit v3.1 require libuEv v2.1.0, or later, and libite v2.0.1, or later.
|
Improvements to `netlink.so` plugin, per-service `rlimit` support,
|
||||||
|
improved integration with `watchdogd`, auto-detect TTY console. Much
|
||||||
|
improved debug, rescue and logging support. Also, many fixes to both
|
||||||
|
big and small issues, most notably in the condition handling, which no
|
||||||
|
longer is sensitive to time skips.
|
||||||
|
|
||||||
|
This version requires at least libuEv v2.1.0 and libite v2.0.1
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
|
|
||||||
|
* Support for more kernel command line settings:
|
||||||
|
- splash, enable boot progress
|
||||||
|
- debug, like `--debug` but also enable kernel debug
|
||||||
|
- single, single user mode (no network)
|
||||||
|
- rescue, new rescue mode
|
||||||
|
* Support for `IFF_RUNNING` to netlink plugin => `net/IFNAME/running`
|
||||||
|
* Support for restarting `initctl` API socket on `SIGHUP`
|
||||||
|
* Greatly updated `initctl status <JOB|NAME>` command
|
||||||
* Support for `rlimit` per service/run/task/inetd/tty, issue #45
|
* Support for `rlimit` per service/run/task/inetd/tty, issue #45
|
||||||
|
* Support for setting `hard` and `soft` rlimit for a resource at once
|
||||||
* Support for auto-detecting serial console using Linux SysFS, the new
|
* Support for auto-detecting serial console using Linux SysFS, the new
|
||||||
`tty @console` eliminates the need to keep track of different console
|
`tty @console` eliminates the need to keep track of different console
|
||||||
devices across embedded platforms: `/dev/ttyS0`, `/dev/ttyAMA0`, etc.
|
devices across embedded platforms: `/dev/ttyS0`, `/dev/ttyAMA0`, etc.
|
||||||
|
* Add TTY `nologin` option. Bypasses login and skips immediately to a
|
||||||
|
root shell. Useful during board bringup, in developer builds, etc.
|
||||||
* Support for calling run/tasks on Finit internal HOOK points, issue #18
|
* Support for calling run/tasks on Finit internal HOOK points, issue #18
|
||||||
* Removed support for long-since deprecated `console DEV` setting
|
* Removed support for long-since deprecated `console DEV` setting
|
||||||
* Cosmetic change to login, pressing enter at the `Press enter to ...`
|
* Cosmetic change to login, pressing enter at the `Press enter to ...`
|
||||||
@@ -25,6 +149,9 @@ Finit v3.1 require libuEv v2.1.0, or later, and libite v2.0.1, or later.
|
|||||||
of inetd services, and `Loading configuration ...`. No end user knows
|
of inetd services, and `Loading configuration ...`. No end user knows
|
||||||
what those plugins and configurations are, i.e. internal state+config
|
what those plugins and configurations are, i.e. internal state+config
|
||||||
* Change kernel WDT timeout (3 --> 30 sec) for built-in watchdog daemon
|
* Change kernel WDT timeout (3 --> 30 sec) for built-in watchdog daemon
|
||||||
|
* Advise watchdog dawmon on shutdown and reboot using `SIGPWR` and then
|
||||||
|
`SIGTERM`. It is recommended the daemon start a timer on the first
|
||||||
|
signal, in case the shutdown process somehow hangs.
|
||||||
* Handle `/etc/` OverlayFS, reload /etc/finit.d/*.conf after `mount -a`
|
* Handle `/etc/` OverlayFS, reload /etc/finit.d/*.conf after `mount -a`
|
||||||
* initctl: Add support for printing previous runlevel
|
* initctl: Add support for printing previous runlevel
|
||||||
* initctl: Support short forms of all commands
|
* initctl: Support short forms of all commands
|
||||||
@@ -38,6 +165,25 @@ Finit v3.1 require libuEv v2.1.0, or later, and libite v2.0.1, or later.
|
|||||||
on mtime of `.conf` files, instead an inotify handler tracks file
|
on mtime of `.conf` files, instead an inotify handler tracks file
|
||||||
changes for time *insensitive* dependency tracking
|
changes for time *insensitive* dependency tracking
|
||||||
* Change condition handling to not rely on mtime but a generation id.
|
* Change condition handling to not rely on mtime but a generation id.
|
||||||
|
* New configure script option `--enable-redirect` to automatically
|
||||||
|
redirect `stdout` and `stderr` of all applications to `/dev/null`
|
||||||
|
* New `pid` sub-option to services when a service does not create a PID
|
||||||
|
file, or when the PID file has another name. Issue #95
|
||||||
|
* Greatly improved `log` sub-option to service/run/tasks, selectively
|
||||||
|
redirect `stdout` and `stderr` using the new tool `logit` to either
|
||||||
|
syslog or a logfile. Issue #44
|
||||||
|
* Support for automatic log rotation of logfiles created by `log`
|
||||||
|
option. Use `configure --disable-logrotate` on systems with a
|
||||||
|
dedicated log rotation service. Issue #44
|
||||||
|
* Support for disabling service/run/task progress with empty ` --`
|
||||||
|
description. Note: no description separator gives a default desc.
|
||||||
|
* Create `/etc/mtab` symlink if missing on system (bootmisc plugin)
|
||||||
|
* New hook: `hook/mount/post` runs after `mount -a` but before the
|
||||||
|
`hook/mount/all`, where `bootmisc.so` runs. This provides the
|
||||||
|
possibility of running a second stage mount command before files in
|
||||||
|
`/run` and similar are created
|
||||||
|
* Skip `gdbserver` when unleashing the grim reaper at shutdown
|
||||||
|
* Distribute and install `docs/` and `contrib/` directories
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
|
||||||
@@ -57,6 +203,8 @@ Finit v3.1 require libuEv v2.1.0, or later, and libite v2.0.1, or later.
|
|||||||
plugin before the pidfile plugin on `HOOK_SVC_RECONF` events
|
plugin before the pidfile plugin on `HOOK_SVC_RECONF` events
|
||||||
* Handle event loop failure modes, issue found by Westermo
|
* Handle event loop failure modes, issue found by Westermo
|
||||||
* Handle API socket errors more gracefully, restart socket
|
* Handle API socket errors more gracefully, restart socket
|
||||||
|
* Do not attempt to load kernel modules more than once at bootstrap
|
||||||
|
* Remove reboot symlinks properly on uninstall
|
||||||
* Fix regression in condition handling, reconf condition must be kept
|
* Fix regression in condition handling, reconf condition must be kept
|
||||||
as a reference point to previous reconfiguration, or bootstrap.
|
as a reference point to previous reconfiguration, or bootstrap.
|
||||||
* Fix nasty race condition with internal service stop, abort kill if the
|
* Fix nasty race condition with internal service stop, abort kill if the
|
||||||
@@ -70,6 +218,7 @@ Finit v3.1 require libuEv v2.1.0, or later, and libite v2.0.1, or later.
|
|||||||
* Fix issue #81 properly, remove use of SYSV shm IPC completely. Finit
|
* Fix issue #81 properly, remove use of SYSV shm IPC completely. Finit
|
||||||
now use the API socket for all communication between PID 1 and initctl
|
now use the API socket for all communication between PID 1 and initctl
|
||||||
* Fix segfault on x86_64 when started with kernel cmdline `--debug`
|
* Fix segfault on x86_64 when started with kernel cmdline `--debug`
|
||||||
|
* Normalize condition paths on systems with `/run` instead of `/var/run`
|
||||||
|
|
||||||
|
|
||||||
[3.0][] - 2017-10-19
|
[3.0][] - 2017-10-19
|
||||||
@@ -97,7 +246,7 @@ distributions.
|
|||||||
* Ensure plugins always have a default name, file name
|
* Ensure plugins always have a default name, file name
|
||||||
* Reorganization, move all source files to a `src/` sub-directory
|
* Reorganization, move all source files to a `src/` sub-directory
|
||||||
* Add support for `initctl <list|enable|disable> <SVC>`, much needed by
|
* Add support for `initctl <list|enable|disable> <SVC>`, much needed by
|
||||||
distributions. See [doc/distro.md](doc/distro.md) for details
|
distributions. See [docs/distro.md](docs/distro.md) for details
|
||||||
* Remove `UNUSED()` macro, mentioned here because it may have been used
|
* Remove `UNUSED()` macro, mentioned here because it may have been used
|
||||||
by external plugin developers. Set `-Wno-unused-parameter` instead
|
by external plugin developers. Set `-Wno-unused-parameter` instead
|
||||||
* New table headings in `initctl`, using `top` style inverted text
|
* New table headings in `initctl`, using `top` style inverted text
|
||||||
@@ -667,7 +816,9 @@ Major bug fix release.
|
|||||||
|
|
||||||
* Initial release
|
* Initial release
|
||||||
|
|
||||||
[UNRELEASED]: https://github.com/troglobit/finit/compare/3.0...HEAD
|
[UNRELEASED]: https://github.com/troglobit/finit/compare/3.1...HEAD
|
||||||
|
[3.2]: https://github.com/troglobit/finit/compare/3.1...3.2
|
||||||
|
[3.1]: https://github.com/troglobit/finit/compare/3.0...3.1
|
||||||
[3.0]: https://github.com/troglobit/finit/compare/2.4...3.0
|
[3.0]: https://github.com/troglobit/finit/compare/2.4...3.0
|
||||||
[2.4]: https://github.com/troglobit/finit/compare/2.3...2.4
|
[2.4]: https://github.com/troglobit/finit/compare/2.3...2.4
|
||||||
[2.3]: https://github.com/troglobit/finit/compare/2.2...2.3
|
[2.3]: https://github.com/troglobit/finit/compare/2.2...2.3
|
||||||
|
|||||||
+8
-1
@@ -3,12 +3,19 @@ SUBDIRS = plugins src
|
|||||||
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
|
||||||
|
|
||||||
|
if CONTRIB
|
||||||
|
SUBDIRS += contrib
|
||||||
|
endif
|
||||||
|
if DOCS
|
||||||
|
SUBDIRS += docs
|
||||||
|
endif
|
||||||
|
|
||||||
# Compat hook
|
# Compat hook
|
||||||
install-dev:
|
install-dev:
|
||||||
@make -C src install-pkgincludeHEADERS
|
@make -C src install-pkgincludeHEADERS
|
||||||
|
|
||||||
# Target to run when building a release
|
# Target to run when building a release
|
||||||
release: dist
|
release: distcheck
|
||||||
@for file in $(DIST_ARCHIVES); do \
|
@for file in $(DIST_ARCHIVES); do \
|
||||||
md5sum $$file > ../$$file.md5; \
|
md5sum $$file > ../$$file.md5; \
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -1,36 +1,41 @@
|
|||||||
<img align="right" src="images/finit3.png" alt="Finit: Fast Init">
|
[![License Badge][]][License] [![Travis Status]][Travis] [![Coverity Status]][Coverity Scan]
|
||||||
|
<img align="right" src="img/finit3.png" alt="Finit: Fast Init">
|
||||||
|
|
||||||
* [Introduction](#introduction)
|
* [Introduction](#introduction)
|
||||||
* [Features](#features)
|
* [Features](#features)
|
||||||
* [Bootstrap](doc/bootstrap.md#bootstrap)
|
* [Bootstrap](docs/bootstrap.md#bootstrap)
|
||||||
* [Runlevels](#runlevels)
|
* [Runlevels](#runlevels)
|
||||||
* [Syntax](doc/config.md#syntax)
|
* [Syntax](docs/config.md#syntax)
|
||||||
* [Inetd](doc/inetd.md#inetd)
|
* [Inetd](docs/inetd.md#inetd)
|
||||||
* [Runparts & /etc/rc.local](#runparts--etcrclocal)
|
* [Runparts & /etc/rc.local](#runparts--etcrclocal)
|
||||||
* [Hooks, Callbacks & Plugins](doc/plugins.md#hooks-callbacks--plugins)
|
* [Hooks, Callbacks & Plugins](docs/plugins.md#hooks-callbacks--plugins)
|
||||||
* [Rebooting & Halting](#rebooting--halting)
|
* [Rebooting & Halting](#rebooting--halting)
|
||||||
* [Commands & Status](#commands--status)
|
* [Commands & Status](#commands--status)
|
||||||
* [Building](doc/build.md#building)
|
* [Tips & Tricks with the kernel cmdline](docs/cmdline.md)
|
||||||
* [Running](doc/build.md#running)
|
* [Building](docs/build.md#building)
|
||||||
* [Debugging](doc/build.md#debugging)
|
* [Running](docs/build.md#running)
|
||||||
|
* [Recovery](docs/build.md#recovery)
|
||||||
|
* [Debugging](docs/build.md#debugging)
|
||||||
* [Requirements](#requirements)
|
* [Requirements](#requirements)
|
||||||
* [Origin & References](#origin--references)
|
* [Origin & References](#origin--references)
|
||||||
|
|
||||||
|
|
||||||
Introduction
|
Introduction
|
||||||
------------
|
------------
|
||||||
[![License Badge][]][License] [![Travis Status]][Travis] [![Coverity Status]][Coverity Scan]
|
|
||||||
|
|
||||||
Finit is a simple alternative to [SysV init][4] and [systemd][6]. It
|
Finit is a simple alternative to [SysV init][4] and [systemd][6]. It
|
||||||
was reverse engineered from the [EeePC fastinit][] ten years ago by
|
was reverse engineered from the [EeePC fastinit][] over ten years ago
|
||||||
[Claudio Matsuoka][] — "gaps filled with frog DNA …"
|
by [Claudio Matsuoka][] — "gaps filled with frog DNA …"
|
||||||
|
|
||||||
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 where both [Debian](contrib/debian/) and
|
[contrib/](contrib/) section with tutorials for:
|
||||||
up to date [Alpine Linux](contrib/alpine/) tutorials can be found.
|
|
||||||
|
|
||||||

|
* [Void Linux](contrib/void/),
|
||||||
|
* [Alpine Linux](contrib/alpine/), and
|
||||||
|
* [Debian GNU/Linux](contrib/debian/)
|
||||||
|
|
||||||
|

|
||||||
The screenshot shows [Alpine Linux](https://www.alpinelinux.org/).
|
The screenshot shows [Alpine Linux](https://www.alpinelinux.org/).
|
||||||
|
|
||||||
|
|
||||||
@@ -49,12 +54,23 @@ host default
|
|||||||
# Runlevel to start after bootstrap, 'S', default: 2
|
# Runlevel to start after bootstrap, 'S', default: 2
|
||||||
runlevel 2
|
runlevel 2
|
||||||
|
|
||||||
|
# Max file size for each log file: 100 kiB, rotate max 4 copies:
|
||||||
|
# log => log.1 => log.2.gz => log.3.gz => log.4.gz
|
||||||
|
log size=100k count=4
|
||||||
|
|
||||||
# Services to be monitored and respawned as needed
|
# Services to be monitored and respawned as needed
|
||||||
service [S12345] /sbin/watchdogd -L -f -- System watchdog daemon
|
service [S12345] /sbin/watchdogd -L -f -- System watchdog daemon
|
||||||
service [S12345] /sbin/syslogd -n -b 3 -D -- System log daemon
|
service [S12345] /sbin/syslogd -n -b 3 -D -- System log daemon
|
||||||
service [S12345] /sbin/klogd -n -- Kernel log daemon
|
service [S12345] /sbin/klogd -n -- Kernel log daemon
|
||||||
service [2345] /sbin/lldpd -d -c -M1 -H0 -i -- LLDP daemon (IEEE 802.1ab)
|
service [2345] /sbin/lldpd -d -c -M1 -H0 -i -- LLDP daemon (IEEE 802.1ab)
|
||||||
|
|
||||||
|
# The BusyBox ntpd does not use syslog when running in the foreground
|
||||||
|
# So we use this trick to redirect stdout/stderr to a log file. The
|
||||||
|
# log file is rotated with the above settings. The condition declares
|
||||||
|
# a dependency on a system default route (gateway) to be set. A single
|
||||||
|
# <!> at the beginning means ntpd does not respect SIGHUP for restart.
|
||||||
|
service [2345] log:/var/log/ntpd.log <!net/route/default> /sbin/ntpd -n -l -I eth0 -- NTP daemon
|
||||||
|
|
||||||
# For multiple instances of the same service, add :ID somewhere between
|
# For multiple instances of the same service, add :ID somewhere between
|
||||||
# the service/run/task keyword and the command.
|
# the service/run/task keyword and the command.
|
||||||
service :1 [2345] /sbin/merecat -n -p 80 /var/www -- Web server
|
service :1 [2345] /sbin/merecat -n -p 80 /var/www -- Web server
|
||||||
@@ -87,10 +103,13 @@ tty [12345] /sbin/getty -L 115200 /dev/tty3 linux
|
|||||||
# Use built-in getty for serial port and USB serial
|
# Use built-in getty for serial port and USB serial
|
||||||
tty [12345] /dev/ttyAMA0 115200 noclear nowait
|
tty [12345] /dev/ttyAMA0 115200 noclear nowait
|
||||||
tty [12345] /dev/ttyUSB0 115200 noclear
|
tty [12345] /dev/ttyUSB0 115200 noclear
|
||||||
|
|
||||||
|
# Just give me a shell, I need to debug this embedded system!
|
||||||
|
tty [12345] @console noclear nologin
|
||||||
```
|
```
|
||||||
|
|
||||||
The `service` stanza, as well as `task`, `run`, `inetd` and others are
|
The `service` stanza, as well as `task`, `run`, `inetd` and others are
|
||||||
described in full in [doc/config.md](doc/config.md). Here's a quick
|
described in full in [docs/config.md](docs/config.md). Here's a quick
|
||||||
overview of some of the most common components needed to start a UNIX
|
overview of some of the most common components needed to start a UNIX
|
||||||
daemon:
|
daemon:
|
||||||
|
|
||||||
@@ -111,7 +130,7 @@ advanced uses as well:
|
|||||||
|
|
||||||
service /usr/sbin/sshd -D
|
service /usr/sbin/sshd -D
|
||||||
|
|
||||||
Dependencies are handled using [conditions](doc/conditions.md). One of
|
Dependencies are handled using [conditions](docs/conditions.md). One of
|
||||||
the most common conditions is to wait for basic networking to become
|
the most common conditions is to wait for basic networking to become
|
||||||
available:
|
available:
|
||||||
|
|
||||||
@@ -152,7 +171,7 @@ Start, monitor and restart services should they fail.
|
|||||||
|
|
||||||
**Inetd**
|
**Inetd**
|
||||||
|
|
||||||
Finit comes with a built-in [inetd server](doc/inetd.md). No need to
|
Finit comes with a built-in [inetd server](docs/inetd.md). No need to
|
||||||
maintain a separate config file for services that you want to start on
|
maintain a separate config file for services that you want to start on
|
||||||
demand.
|
demand.
|
||||||
|
|
||||||
@@ -167,7 +186,7 @@ Built-in optional inetd services:
|
|||||||
- discard [RFC863][]
|
- discard [RFC863][]
|
||||||
- time (rdate) [RFC868][]
|
- time (rdate) [RFC868][]
|
||||||
|
|
||||||
For more information, see [doc/inetd.md](doc/inetd.md).
|
For more information, see [docs/inetd.md](docs/inetd.md).
|
||||||
|
|
||||||
|
|
||||||
**Getty**
|
**Getty**
|
||||||
@@ -192,7 +211,9 @@ figures it out by querying sysfs: `/sys/class/tty/console/active`.
|
|||||||
tty [12345] @console 115200 linux noclear
|
tty [12345] @console 115200 linux noclear
|
||||||
```
|
```
|
||||||
|
|
||||||
For more information, see [doc/config.md](doc/config.md#syntax).
|
Notice the optional `noclear`, `nowait`, and `nologin` flags. The
|
||||||
|
latter is for skipping the login process entirely. For more information,
|
||||||
|
see [docs/config.md](docs/config.md#syntax).
|
||||||
|
|
||||||
|
|
||||||
**Runlevels**
|
**Runlevels**
|
||||||
@@ -201,10 +222,18 @@ Support for SysV init-style [runlevels][5] is available, in the same
|
|||||||
minimal style as everything else in Finit. The `[2345]` syntax can be
|
minimal style as everything else in Finit. The `[2345]` syntax can be
|
||||||
applied to service, task, run, inetd, and TTY stanzas.
|
applied to service, task, run, inetd, and TTY stanzas.
|
||||||
|
|
||||||
All services in runlevel S(1) are started first, followed by the desired
|
Reserved runlevels are 0 and 6, halt and reboot, respectively just like
|
||||||
run-time runlevel. Runlevel S can be started in sequence by using `run
|
SysV init. Runlevel 1 can be configured freely, but is recommended to
|
||||||
[S] cmd`. Changing runlevels at runtime is done like any other init,
|
be kept as the system single-user runlevel since Finit will not start
|
||||||
e.g. <kbd>init 4</kbd>, but also using the more advanced `intictl` tool.
|
networking here. The configured `runlevel NUM` from `/etc/finit.conf`
|
||||||
|
is what Finit changes to after bootstrap, unless 'single' (or 'S') is
|
||||||
|
given on the kernel cmdline, in which case runlevel 1 is started.
|
||||||
|
|
||||||
|
All services in runlevel S(0) are started first, followed by the desired
|
||||||
|
run-time runlevel. Run tasks in runlevel S can be started in sequence
|
||||||
|
by using `run [S] cmd`. Changing runlevels at runtime is done like any
|
||||||
|
other init, e.g. <kbd>init 4</kbd>, but also using the more advanced
|
||||||
|
`intictl` tool.
|
||||||
|
|
||||||
|
|
||||||
**Plugins**
|
**Plugins**
|
||||||
@@ -229,25 +258,63 @@ Extensions and functionality not purely related to what an `/sbin/init`
|
|||||||
needs to start a system are available as a set of plugins that either
|
needs to start a system are available as a set of plugins that either
|
||||||
hook into the boot process or respond to various I/O.
|
hook into the boot process or respond to various I/O.
|
||||||
|
|
||||||
For more information, see [doc/plugins.md](doc/plugins.md).
|
For more information, see [docs/plugins.md](docs/plugins.md).
|
||||||
|
|
||||||
|
|
||||||
|
**Progress**
|
||||||
|
|
||||||
|
Finit prior to v3.0 showed the progress at boot: plugins and modules
|
||||||
|
being loaded, run/tasks/services being started, etc. By default Finit
|
||||||
|
is now silent, but progress can still be enabled at build-time using:
|
||||||
|
|
||||||
|
configure --enable-progress
|
||||||
|
|
||||||
|
or at boot from the kernel cmdline using the boot parameter `splash`:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
append="init=/sbin/finit splash"
|
||||||
|
```
|
||||||
|
|
||||||
|
For a really nice boot, add `quiet` as well. This silences the output
|
||||||
|
from the kernel, leaving only warnings and errors. For other kernel
|
||||||
|
command line parameters, see [docs/build.md](docs/build.md#recovery).
|
||||||
|
|
||||||
|
|
||||||
|
**Automatic Reload**
|
||||||
|
|
||||||
|
By default, Finit monitors `/etc/finit.d/` and `/etc/finit.d/enabled/`
|
||||||
|
registering any changes to `.conf` files. To activate a change the user
|
||||||
|
must call `initctl reload`, which reloads all modified files, stops any
|
||||||
|
removed services, starts new ones, and restarts any modified ones, with
|
||||||
|
SIGHUP if the process supports it.
|
||||||
|
|
||||||
|
For some use-cases the extra step of calling `initctl reload` creates an
|
||||||
|
unnecessary overhead, which can be removed at build-time using:
|
||||||
|
|
||||||
|
configure --enable-auto-reload
|
||||||
|
|
||||||
|
|
||||||
Runparts & /etc/rc.local
|
Runparts & /etc/rc.local
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
At the end of the boot, when networking and all services are up, Finit
|
At the end of the boot, when all bootstrap (`S`) tasks and services have
|
||||||
calls its built-in [run-parts(8)][] on the `runparts <DIR>` directory,
|
started, but not networking, Finit calls its built-in [run-parts(8)][]
|
||||||
and `/etc/rc.local`, in that order if they exist.
|
command on any configured `runparts <DIR>` directory. This happens just
|
||||||
|
before changing to the configured runlevel (default 2). (Networking is
|
||||||
|
enabled just prior to changing from single user mode.)
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
runparts /etc/rc.d/
|
runparts /etc/rc.d/
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Right after the runlevel change when all services have started properly,
|
||||||
|
`/etc/rc.local` is called.
|
||||||
|
|
||||||
No configuration stanza in `/etc/finit.conf` is required for `rc.local`.
|
No configuration stanza in `/etc/finit.conf` is required for `rc.local`.
|
||||||
If it exists and is an executable shell script, finit calls it at the
|
If it exists and is an executable shell script Finit calls it at the very
|
||||||
very end of the boot, before calling the `HOOK_SYSTEM_UP`. See more on
|
end of the boot, before calling the `HOOK_SYSTEM_UP`. See more on hooks
|
||||||
hooks in [doc/plugins.md](doc/plugins.md#hooks), and about the system
|
in [docs/plugins.md](docs/plugins.md#hooks), and about the system bootstrap
|
||||||
bootstrap in [doc/bootstrap.md](doc/bootstrap.md).
|
in [docs/bootstrap.md](docs/bootstrap.md).
|
||||||
|
|
||||||
|
|
||||||
Runlevels
|
Runlevels
|
||||||
@@ -325,7 +392,7 @@ section.
|
|||||||
For compatibility reasons Finit listens to the same set of signals as
|
For compatibility reasons Finit listens to the same set of signals as
|
||||||
BusyBox init. This is not 100% compatible with SysV init, but clearly
|
BusyBox init. This is not 100% compatible with SysV init, but clearly
|
||||||
the more common combination for Finit. For more details, see
|
the more common combination for Finit. For more details, see
|
||||||
[doc/signals.md](doc/signals.md).
|
[docs/signals.md](docs/signals.md).
|
||||||
|
|
||||||
Finit also listens to the classic SysV init FIFO, used by `telinit`.
|
Finit also listens to the classic SysV init FIFO, used by `telinit`.
|
||||||
Support for this is implemented by the `initctl.so` plugin. Hence,
|
Support for this is implemented by the `initctl.so` plugin. Hence,
|
||||||
@@ -373,10 +440,9 @@ Commands:
|
|||||||
list List all .conf in /etc/finit.d/
|
list List all .conf in /etc/finit.d/
|
||||||
enable <CONF> Enable .conf in /etc/finit.d/available/
|
enable <CONF> Enable .conf in /etc/finit.d/available/
|
||||||
disable <CONF> Disable .conf in /etc/finit.d/[enabled/]
|
disable <CONF> Disable .conf in /etc/finit.d/[enabled/]
|
||||||
|
touch <CONF> Mark .conf in /etc/finit.d/ for reload
|
||||||
reload Reload *.conf in /etc/finit.d/ (activates changes)
|
reload Reload *.conf in /etc/finit.d/ (activates changes)
|
||||||
|
|
||||||
cond set <COND> Set (assert) condition => +COND
|
|
||||||
cond clear <COND> Clear (deassert) condition => -COND
|
|
||||||
cond show Show condition status
|
cond show Show condition status
|
||||||
cond dump Dump all conditions and their status
|
cond dump Dump all conditions and their status
|
||||||
|
|
||||||
@@ -384,6 +450,7 @@ Commands:
|
|||||||
start <JOB|NAME>[:ID] Start service by job# or name, with optional ID
|
start <JOB|NAME>[:ID] Start service by job# or name, with optional ID
|
||||||
stop <JOB|NAME>[:ID] Stop/Pause a running service by job# or name
|
stop <JOB|NAME>[:ID] Stop/Pause a running service by job# or name
|
||||||
restart <JOB|NAME>[:ID] Restart (stop/start) service by job# or name
|
restart <JOB|NAME>[:ID] Restart (stop/start) service by job# or name
|
||||||
|
status <JOB|NAME>[:ID] Show service status, by job# or name
|
||||||
status | show Show status of services, default command
|
status | show Show status of services, default command
|
||||||
|
|
||||||
runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot
|
runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot
|
||||||
@@ -396,7 +463,7 @@ Commands:
|
|||||||
|
|
||||||
For services *not* supporting `SIGHUP` the `<!>` notation in the .conf
|
For services *not* supporting `SIGHUP` the `<!>` notation in the .conf
|
||||||
file must be used to tell Finit to stop and start it on `reload` and
|
file must be used to tell Finit to stop and start it on `reload` and
|
||||||
`runlevel` changes. If `<>` holds more [conditions](doc/conditions.md),
|
`runlevel` changes. If `<>` holds more [conditions](docs/conditions.md),
|
||||||
these will also affect how a service is maintained.
|
these will also affect how a service is maintained.
|
||||||
|
|
||||||
**Note:** even though it is possible to start services not belonging in
|
**Note:** even though it is possible to start services not belonging in
|
||||||
@@ -422,11 +489,13 @@ Requirements
|
|||||||
------------
|
------------
|
||||||
|
|
||||||
Finit is capable of running on both desktop/server systems with udev and
|
Finit is capable of running on both desktop/server systems with udev and
|
||||||
embedded systems that usually come with BusyBox mdev. Finit probes for
|
embedded systems that usually come with BusyBox mdev. Some systems have
|
||||||
them at runtime and expects `/dev/` to be writable, usually `devtmpfs`.
|
systemd-udev or eudev today instead of the original udev, Finit probes
|
||||||
It is also possible to run on a statically set up `/dev` if needed. It
|
for all of them at runtime and expects `/dev/` to be a writable file
|
||||||
is however not a good idea to have both udev and mdev installed at the
|
system using `devtmpfs`. It is also possible to run on a statically set
|
||||||
same time, this will lead to unpredictable results.
|
up `/dev` if needed. It is however not a good idea to have both udev
|
||||||
|
and mdev installed at the same time, this will lead to unpredictable
|
||||||
|
results.
|
||||||
|
|
||||||
At boot Finit calls either `mdev` or `udevd` to populate `/dev`, this is
|
At boot Finit calls either `mdev` or `udevd` to populate `/dev`, this is
|
||||||
done slightly differently and on systems with udev you might want to add
|
done slightly differently and on systems with udev you might want to add
|
||||||
@@ -476,12 +545,12 @@ and proposed extensions.
|
|||||||
[openrc]: http://www.gentoo.org/proj/en/base/openrc/
|
[openrc]: http://www.gentoo.org/proj/en/base/openrc/
|
||||||
[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
|
||||||
[original finit]: http://helllabs.org/finit/
|
[original finit]: http://helllabs.org/finit/
|
||||||
[EeePC fastinit]: 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 Nilsson]: http://troglobit.com
|
[Joachim Nilsson]: http://troglobit.com
|
||||||
[GitHub]: https://github.com/troglobit/finit
|
[GitHub]: https://github.com/troglobit/finit
|
||||||
[License]: https://en.wikipedia.org/wiki/MIT_License
|
[License]: https://en.wikipedia.org/wiki/MIT_License
|
||||||
[License Badge]: https://img.shields.io/badge/License-MIT-yellow.svg
|
[License Badge]: https://img.shields.io/badge/License-MIT-teal.svg
|
||||||
[Travis]: https://travis-ci.org/troglobit/finit
|
[Travis]: https://travis-ci.org/troglobit/finit
|
||||||
[Travis Status]: https://travis-ci.org/troglobit/finit.png?branch=master
|
[Travis Status]: https://travis-ci.org/troglobit/finit.png?branch=master
|
||||||
[Coverity Scan]: https://scan.coverity.com/projects/3545
|
[Coverity Scan]: https://scan.coverity.com/projects/3545
|
||||||
|
|||||||
+81
-14
@@ -1,10 +1,17 @@
|
|||||||
AC_INIT(Finit, 3.1-rc1, https://github.com/troglobit/finit/issues, finit, http://troglobit.com/finit.html)
|
AC_INIT(Finit, 3.2-rc2, https://github.com/troglobit/finit/issues, finit, http://troglobit.com/finit.html)
|
||||||
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz subdir-objects])
|
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip 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_HEADER([config.h])
|
||||||
AC_CONFIG_FILES([Makefile plugins/Makefile src/Makefile])
|
AC_CONFIG_FILES([Makefile
|
||||||
|
contrib/Makefile
|
||||||
|
contrib/alpine/Makefile contrib/alpine/finit.d/Makefile contrib/alpine/finit.d/available/Makefile
|
||||||
|
contrib/debian/Makefile contrib/debian/finit.d/Makefile contrib/debian/finit.d/available/Makefile contrib/debian/grub.d/Makefile
|
||||||
|
contrib/void/Makefile contrib/void/finit.d/Makefile contrib/void/finit.d/available/Makefile
|
||||||
|
docs/Makefile
|
||||||
|
plugins/Makefile
|
||||||
|
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])
|
||||||
@@ -21,6 +28,7 @@ LT_INIT([shared disable-static dlopen aix-soname=both disable-fast-install])
|
|||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
AC_PROG_LN_S
|
AC_PROG_LN_S
|
||||||
AC_PROG_INSTALL
|
AC_PROG_INSTALL
|
||||||
|
AC_PROG_MKDIR_P
|
||||||
|
|
||||||
# Configuration.
|
# Configuration.
|
||||||
AC_HEADER_STDC
|
AC_HEADER_STDC
|
||||||
@@ -32,8 +40,11 @@ AC_TYPE_UINT8_T
|
|||||||
AC_TYPE_UINT16_T
|
AC_TYPE_UINT16_T
|
||||||
AC_TYPE_UINT32_T
|
AC_TYPE_UINT32_T
|
||||||
|
|
||||||
|
# Check for pkg-config first, warn if it's not installed
|
||||||
|
PKG_PROG_PKG_CONFIG
|
||||||
|
|
||||||
# Check for required libraries
|
# Check for required libraries
|
||||||
PKG_CHECK_MODULES([uev], [libuev >= 2.1.0])
|
PKG_CHECK_MODULES([uev], [libuev >= 2.2.0])
|
||||||
PKG_CHECK_MODULES([lite], [libite >= 2.0.1])
|
PKG_CHECK_MODULES([lite], [libite >= 2.0.1])
|
||||||
|
|
||||||
# Check for configured Finit features
|
# Check for configured Finit features
|
||||||
@@ -46,26 +57,50 @@ AC_ARG_ENABLE(fallback_shell,
|
|||||||
AS_HELP_STRING([--enable-fallback-shell], [Start a shell if no TTYs can start]),,[
|
AS_HELP_STRING([--enable-fallback-shell], [Start a shell if no TTYs can start]),,[
|
||||||
enable_fallback_shell=no])
|
enable_fallback_shell=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(auto_reload,
|
||||||
|
AS_HELP_STRING([--enable-auto-reload], [Automatic reload on any .conf change]),,[
|
||||||
|
enable_auto_reload=no])
|
||||||
|
|
||||||
AC_ARG_ENABLE(rw-rootfs,
|
AC_ARG_ENABLE(rw-rootfs,
|
||||||
AS_HELP_STRING([--enable-rw-rootfs], [Remount / R/W at boot, usually not for embedded]),,[
|
AS_HELP_STRING([--enable-rw-rootfs], [Remount / R/W at boot, usually not for embedded]),,[
|
||||||
enable_rw_rootfs=no])
|
enable_rw_rootfs=no])
|
||||||
|
|
||||||
AC_ARG_ENABLE(progress,
|
AC_ARG_ENABLE(progress,
|
||||||
AS_HELP_STRING([--enable-progress], [Pre Finit v3 bootup progress and heading]),,[
|
AS_HELP_STRING([--enable-progress], [Modern progress display at bootup]),,[
|
||||||
enable_progress=no])
|
enable_progress=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(progress-classic,
|
||||||
|
AS_HELP_STRING([--enable-progress-classic], [Pre Finit v3 bootup progress and heading]),,[
|
||||||
|
enable_progress_classic=no])
|
||||||
|
|
||||||
AC_ARG_ENABLE(watchdog,
|
AC_ARG_ENABLE(watchdog,
|
||||||
AS_HELP_STRING([--enable-watchdog], [Enable built-in watchdog, uses /dev/watchdog]),,[
|
AS_HELP_STRING([--enable-watchdog], [Enable built-in watchdog, uses /dev/watchdog]),,[
|
||||||
enable_watchdog=no])
|
enable_watchdog=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(redirect,
|
||||||
|
AS_HELP_STRING([--enable-redirect], [Redirect service output to /dev/null, default: no]),,[
|
||||||
|
enable_redirect_output=no])
|
||||||
|
|
||||||
AC_ARG_ENABLE(inetd,
|
AC_ARG_ENABLE(inetd,
|
||||||
AS_HELP_STRING([--disable-inetd], [Disable built-in inetd super server, default enabled]),,[
|
AS_HELP_STRING([--disable-inetd], [Disable built-in inetd super server, default enabled]),,[
|
||||||
enable_inetd=yes])
|
enable_inetd=yes])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(logit,
|
||||||
|
AS_HELP_STRING([--disable-logit], [Disable logit, used for log redirection, default: enable]),,[
|
||||||
|
enable_logit=yes])
|
||||||
|
|
||||||
AC_ARG_ENABLE(logrotate,
|
AC_ARG_ENABLE(logrotate,
|
||||||
AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp, default enabled]),,[
|
AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp, default enabled]),,[
|
||||||
enable_logrotate=yes])
|
enable_logrotate=yes])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(docs,
|
||||||
|
AS_HELP_STRING([--disable-docs], [Disable build and install of docs section]),,[
|
||||||
|
enable_docs=yes])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(contrib,
|
||||||
|
AS_HELP_STRING([--disable-contrib], [Disable build and install of contrib section]),,[
|
||||||
|
enable_contrib=yes])
|
||||||
|
|
||||||
# Check for extra plugins to enable
|
# Check for extra plugins to enable
|
||||||
enable_all_plugins=auto
|
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])
|
||||||
@@ -75,7 +110,7 @@ AC_PLUGIN([inetd-chargen], [no], [Inetd plugin: character generator, RFC864])
|
|||||||
AC_PLUGIN([inetd-daytime], [no], [Inetd plugin: daytime server, RFC867])
|
AC_PLUGIN([inetd-daytime], [no], [Inetd plugin: daytime server, RFC867])
|
||||||
AC_PLUGIN([inetd-discard], [no], [Inetd plugin: discard server, RFC863])
|
AC_PLUGIN([inetd-discard], [no], [Inetd plugin: discard server, RFC863])
|
||||||
AC_PLUGIN([inetd-time], [no], [Inetd plugin: time (rdate) server, RFC868])
|
AC_PLUGIN([inetd-time], [no], [Inetd plugin: time (rdate) server, RFC868])
|
||||||
AC_PLUGIN([lost], [no], [Example HOOK_SVC_LOST plugin, very noisy as-is!])
|
AC_PLUGIN([modules-load], [no], [Scans /etc/modules-load.d for modules to load])
|
||||||
AC_PLUGIN([resolvconf], [no], [Setup necessary files for resolvconf])
|
AC_PLUGIN([resolvconf], [no], [Setup necessary files for resolvconf])
|
||||||
AC_PLUGIN([x11-common], [no], [Console setup (for X)])
|
AC_PLUGIN([x11-common], [no], [Console setup (for X)])
|
||||||
AC_PLUGIN([netlink], [yes], [Basic netlink plugin for IFUP/IFDN and GW events. Can be replaced with externally built plugin that links with libnl or similar.])
|
AC_PLUGIN([netlink], [yes], [Basic netlink plugin for IFUP/IFDN and GW events. Can be replaced with externally built plugin that links with libnl or similar.])
|
||||||
@@ -89,11 +124,6 @@ AC_ARG_WITH(fifo,
|
|||||||
AS_HELP_STRING([--with-fifo=FIFO], [FIFO for init/telinit clients, default /var/run/initctl]),
|
AS_HELP_STRING([--with-fifo=FIFO], [FIFO for init/telinit clients, default /var/run/initctl]),
|
||||||
[fifo=$withval], [fifo=$localstatedir/run/initctl])
|
[fifo=$withval], [fifo=$localstatedir/run/initctl])
|
||||||
|
|
||||||
AC_ARG_WITH(plugindir,
|
|
||||||
AS_HELP_STRING([--with-plugindir=DIR], [Finit plugin directory, default /lib/finit/plugins]),
|
|
||||||
[pkglibdir=$withval], [pkglibdir=$libdir/finit/plugins])
|
|
||||||
AC_SUBST([pkglibdir])
|
|
||||||
|
|
||||||
AC_ARG_WITH(config,
|
AC_ARG_WITH(config,
|
||||||
AS_HELP_STRING([--with-config=CONFIG], [Finit bootstrap config file, default /etc/finit.conf]),
|
AS_HELP_STRING([--with-config=CONFIG], [Finit bootstrap config file, default /etc/finit.conf]),
|
||||||
[conf=$withval], [conf=$sysconfdir/finit.conf])
|
[conf=$withval], [conf=$sysconfdir/finit.conf])
|
||||||
@@ -122,7 +152,6 @@ AC_ARG_WITH(random-seed,
|
|||||||
AS_HELP_STRING([--with-random-seed=FILE], [Save a random seed for /dev/urandom across reboots, default /var/lib/misc/random-seed]),
|
AS_HELP_STRING([--with-random-seed=FILE], [Save a random seed for /dev/urandom across reboots, default /var/lib/misc/random-seed]),
|
||||||
[random_seed=$withval], [random_seed=/var/lib/misc/random-seed])
|
[random_seed=$withval], [random_seed=/var/lib/misc/random-seed])
|
||||||
|
|
||||||
|
|
||||||
### Enable features ###########################################################################
|
### Enable features ###########################################################################
|
||||||
|
|
||||||
# Create config.h from selected features and fallback defautls
|
# Create config.h from selected features and fallback defautls
|
||||||
@@ -132,22 +161,39 @@ AS_IF([test "x$enable_emergency_shell" = "xyes"], [
|
|||||||
AS_IF([test "x$enable_fallback_shell" = "xyes"], [
|
AS_IF([test "x$enable_fallback_shell" = "xyes"], [
|
||||||
AC_DEFINE(FALLBACK_SHELL, 1, [Start /bin/sh on console if no TTYs.])])
|
AC_DEFINE(FALLBACK_SHELL, 1, [Start /bin/sh on console if no TTYs.])])
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_auto_reload" = "xyes"], [
|
||||||
|
AC_DEFINE(AUTO_RELOAD, 1, [Finit automatically does `initctl reload` on any .conf change])])
|
||||||
|
|
||||||
AS_IF([test "x$enable_rw_rootfs" = "xyes"], [
|
AS_IF([test "x$enable_rw_rootfs" = "xyes"], [
|
||||||
AC_DEFINE(REMOUNT_ROOTFS, 1, [Remount / as rw at boot])])
|
AC_DEFINE(REMOUNT_ROOTFS, 1, [Remount / as rw at boot])])
|
||||||
|
|
||||||
AS_IF([test "x$enable_progress" = "xyes"], [
|
AS_IF([test "x$enable_progress" = "xyes"], [
|
||||||
AC_DEFINE(SILENT_MODE, 0, [Pre Finit v3 bootup messages and heading])
|
AC_DEFINE(PROGRESS_STYLE, 2, [Modern bootup messages, systemd inspired])])
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_progress_classic" = "xyes"], [
|
||||||
|
enable_progress=no
|
||||||
|
AC_DEFINE(PROGRESS_STYLE, 1, [Pre Finit v3 bootup messages and heading])])
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_progress_classic" = "xyes" -o "x$enable_progress" = "xyes"], [
|
||||||
|
AC_DEFINE(SILENT_MODE, 0, [Display bootup progress, see above for style])
|
||||||
], [
|
], [
|
||||||
AC_DEFINE(SILENT_MODE, 1, [Completely silent until login prompt])])
|
AC_DEFINE(PROGRESS_STYLE, 0, [Default progress style])
|
||||||
|
AC_DEFINE(SILENT_MODE, 1, [Completely silent until login prompt (default)])])
|
||||||
|
|
||||||
AS_IF([test "x$enable_watchdog" = "xyes"], [
|
AS_IF([test "x$enable_watchdog" = "xyes"], [
|
||||||
AC_DEFINE(BUILTIN_WATCHDOG, 1, [Enable built-in watchdog, kicks on /dev/watchdog])])
|
AC_DEFINE(BUILTIN_WATCHDOG, 1, [Enable built-in watchdog, kicks on /dev/watchdog])])
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_redirect" = "xyes"], [
|
||||||
|
AC_DEFINE(REDIRECT_OUTPUT, 1, [Enable redirection of service output to /dev/null])])
|
||||||
|
|
||||||
### Disable features ###########################################################################
|
### Disable features ###########################################################################
|
||||||
AS_IF([test "x$enable_inetd" != "xno"], [
|
AS_IF([test "x$enable_inetd" != "xno"], [
|
||||||
enable_inetd="yes"
|
enable_inetd="yes"
|
||||||
AC_DEFINE(INETD_ENABLED, 1, [Enable built-in inetd])])
|
AC_DEFINE(INETD_ENABLED, 1, [Enable built-in inetd])])
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_logit" != "xno"], [
|
||||||
|
AC_DEFINE(LOGIT_ENABLED, 1, [Enable logit tool, used for log redirection by Finit])])
|
||||||
|
|
||||||
AS_IF([test "x$enable_logrotate" != "xno"], [
|
AS_IF([test "x$enable_logrotate" != "xno"], [
|
||||||
AC_DEFINE(LOGROTATE_ENABLED, 1, [Enable built-in rotation of /var/log/wtmp et al.])])
|
AC_DEFINE(LOGROTATE_ENABLED, 1, [Enable built-in rotation of /var/log/wtmp et al.])])
|
||||||
|
|
||||||
@@ -206,6 +252,22 @@ AS_IF([test "x$with_random_seed" != "xno"], [
|
|||||||
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
||||||
AM_CONDITIONAL(INETD, [test "x$enable_inetd" = "xyes"])
|
AM_CONDITIONAL(INETD, [test "x$enable_inetd" = "xyes"])
|
||||||
AM_CONDITIONAL(WATCHDOGD, [test "x$enable_watchdog" = "xyes"])
|
AM_CONDITIONAL(WATCHDOGD, [test "x$enable_watchdog" = "xyes"])
|
||||||
|
AM_CONDITIONAL(LOGIT, [test "x$enable_logit" = "xyes"])
|
||||||
|
AM_CONDITIONAL(DOCS, [test "x$enable_docs" = "xyes"])
|
||||||
|
AM_CONDITIONAL(CONTRIB, [test "x$enable_contrib" = "xyes"])
|
||||||
|
|
||||||
|
# Override default libdir, used for plugins and rescue.conf
|
||||||
|
pkglibdir=$libdir/finit
|
||||||
|
AC_SUBST(pkglibexecdir)
|
||||||
|
AC_EXPAND_DIR(pkglibexecdir, "$libexecdir/finit")
|
||||||
|
AC_DEFINE_UNQUOTED(FINIT_LIBPATH_, "$pkglibexecdir", [Finit libexec path])
|
||||||
|
|
||||||
|
AC_EXPAND_DIR(plugin_path, "$libdir/finit/plugins")
|
||||||
|
AC_SUBST(plugin_path)
|
||||||
|
AC_DEFINE_UNQUOTED(PLUGIN_PATH, "$plugin_path", [Finit plugin path])
|
||||||
|
|
||||||
|
AC_EXPAND_DIR(rescue_conf, "$libdir/finit/rescue.conf")
|
||||||
|
AC_DEFINE_UNQUOTED(RESCUE_CONF, "$rescue_conf", [Finit rescue mode .conf])
|
||||||
|
|
||||||
# Generate all files
|
# Generate all files
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
@@ -220,6 +282,7 @@ cat <<EOF
|
|||||||
FIFO path.............: $fifo_path
|
FIFO path.............: $fifo_path
|
||||||
Finit config file.....: $conf_path
|
Finit config file.....: $conf_path
|
||||||
Finit config.d path...: $rcsd_path
|
Finit config.d path...: $rcsd_path
|
||||||
|
Finit plugin path.....: $plugin_path
|
||||||
Compat rc.local path..: $rclocal_path
|
Compat rc.local path..: $rclocal_path
|
||||||
Random seed path......: $random_path
|
Random seed path......: $random_path
|
||||||
C Compiler............: $CC $CFLAGS $CPPFLAGS $LDFLAGS $LIBS
|
C Compiler............: $CC $CFLAGS $CPPFLAGS $LDFLAGS $LIBS
|
||||||
@@ -230,13 +293,17 @@ Behavior:
|
|||||||
Plugins...............: $plugins
|
Plugins...............: $plugins
|
||||||
|
|
||||||
Optional features:
|
Optional features:
|
||||||
|
Install docs/.........: $enable_docs
|
||||||
|
Install contrib/......: $enable_contrib
|
||||||
Built-in inetd........: $enable_inetd
|
Built-in inetd........: $enable_inetd
|
||||||
Built-in watchdogd....: $enable_watchdog
|
Built-in watchdogd....: $enable_watchdog
|
||||||
Built-in logrotate....: $enable_logrotate
|
Built-in logrotate....: $enable_logrotate
|
||||||
|
Scripting tool logit..: $enable_logit
|
||||||
Emergency shell.......: $enable_emergency_shell
|
Emergency shell.......: $enable_emergency_shell
|
||||||
Fallback shell........: $enable_fallback_shell
|
Fallback shell........: $enable_fallback_shell
|
||||||
Remount / RW at boot..: $enable_rw_rootfs
|
Remount / RW at boot..: $enable_rw_rootfs
|
||||||
Traditional progress..: $enable_progress
|
Modern progress.......: $enable_progress
|
||||||
|
Classic progress......: $enable_progress_classic
|
||||||
Default console dev...: $console
|
Default console dev...: $console
|
||||||
Default hostname......: $hostname
|
Default hostname......: $hostname
|
||||||
Default runlevel......: $runlevel
|
Default runlevel......: $runlevel
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
Makefile
|
||||||
|
Makefile.in
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
SUBDIRS = alpine debian void
|
||||||
|
bin_SCRIPT = service
|
||||||
|
docsdir := @docdir@/contrib
|
||||||
|
docs_DATA = README.md finit.conf procmon.sh
|
||||||
|
EXTRA_DIST = $(docs_DATA)
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
SUBDIRS = finit.d
|
||||||
|
docsdir := @docdir@/contrib/alpine
|
||||||
|
docs_DATA = README.md finit.conf alpine-release build.sh install.sh rc.local
|
||||||
|
EXTRA_DIST = $(docs_DATA)
|
||||||
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
SUBDIRS = available
|
||||||
|
docsdir := @docdir@/contrib/alpine/finit.d
|
||||||
|
d_LINKS = dropbear.conf getty.conf keymap.conf modules.conf klogd.conf \
|
||||||
|
syslogd.conf
|
||||||
|
|
||||||
|
install-exec-hook:
|
||||||
|
@$(MKDIR_P) $(DESTDIR)$(docsdir)/available
|
||||||
|
@for file in $(d_LINKS); do \
|
||||||
|
lnk=$(DESTDIR)$(docsdir)/$$file; \
|
||||||
|
src=available/$$file; \
|
||||||
|
if [ -L $$lnk ]; then \
|
||||||
|
echo "Skipping $$lnk exists."; \
|
||||||
|
else \
|
||||||
|
$(LN_S) $$src $$lnk; \
|
||||||
|
fi; \
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
uninstall-hook:
|
||||||
|
@for file in $(d_LINKS); do \
|
||||||
|
lnk=$(DESTDIR)$(docsdir)/$$file; \
|
||||||
|
src=available/$$file; \
|
||||||
|
if [ "`readlink $$lnk`" != "$$src" ]; then \
|
||||||
|
continue; \
|
||||||
|
fi; \
|
||||||
|
$(RM) $$lnk; \
|
||||||
|
done
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
docsdir := @docdir@/contrib/alpine/finit.d/available
|
||||||
|
docs_DATA = acpid.conf crond.conf dropbear.conf getty.conf keymap.conf \
|
||||||
|
lxdm.conf modules.conf ntpd.conf klogd.conf syslogd.conf
|
||||||
|
EXTRA_DIST = $(docs_DATA)
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
SUBDIRS = finit.d grub.d
|
||||||
|
docsdir := @docdir@/contrib/debian
|
||||||
|
docs_DATA = README.md finit.conf os-release build.sh install.sh
|
||||||
|
EXTRA_DIST = $(docs_DATA)
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
SUBDIRS = available
|
||||||
|
docsdir := @docdir@/contrib/debian/finit.d
|
||||||
|
d_LINKS = console-setup.conf getty.conf keyboard-setup.conf \
|
||||||
|
modules.conf rsyslogd.conf sshd.conf
|
||||||
|
|
||||||
|
install-exec-hook:
|
||||||
|
@$(MKDIR_P) $(DESTDIR)$(docsdir)/available
|
||||||
|
@for file in $(d_LINKS); do \
|
||||||
|
lnk=$(DESTDIR)$(docsdir)/$$file; \
|
||||||
|
src=available/$$file; \
|
||||||
|
if [ -L $$lnk ]; then \
|
||||||
|
echo "Skipping $$lnk exists."; \
|
||||||
|
else \
|
||||||
|
$(LN_S) $$src $$lnk; \
|
||||||
|
fi; \
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
uninstall-hook:
|
||||||
|
@for file in $(d_LINKS); do \
|
||||||
|
lnk=$(DESTDIR)$(docsdir)/$$file; \
|
||||||
|
src=available/$$file; \
|
||||||
|
if [ "`readlink $$lnk`" != "$$src" ]; then \
|
||||||
|
continue; \
|
||||||
|
fi; \
|
||||||
|
$(RM) $$lnk; \
|
||||||
|
done
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
docsdir := @docdir@/contrib/debian/finit.d/available
|
||||||
|
docs_DATA = acpid.conf console-setup.conf getty.conf \
|
||||||
|
keyboard-setup.conf lightdm.conf modules.conf \
|
||||||
|
ntpclient.conf rsyslogd.conf sshd.conf xdm.conf
|
||||||
|
EXTRA_DIST = $(docs_DATA)
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
docsdir := @docdir@/contrib/debian/grub.d
|
||||||
|
docs_DATA = 40_custom
|
||||||
|
EXTRA_DIST = $(docs_DATA)
|
||||||
@@ -17,6 +17,10 @@ runlevel 2
|
|||||||
# Network bringup script
|
# Network bringup script
|
||||||
network service networking start
|
network service networking start
|
||||||
|
|
||||||
|
# Max file size for each log file: 100 kiB, rotate max 4 copies:
|
||||||
|
# log => log.1 => log.2.gz => log.3.gz => log.4.gz
|
||||||
|
log size=100k count=4
|
||||||
|
|
||||||
# Virtual consoles to start getty on
|
# Virtual consoles to start getty on
|
||||||
tty /dev/tty1
|
tty /dev/tty1
|
||||||
tty /dev/tty2
|
tty /dev/tty2
|
||||||
@@ -33,6 +37,13 @@ service [2345] /sbin/klogd -n -- Kernel logging server
|
|||||||
service [2345] /sbin/syslogd -n -- Syslog server
|
service [2345] /sbin/syslogd -n -- Syslog server
|
||||||
service [3] /usr/sbin/gdm -- GNOME Display Manager
|
service [3] /usr/sbin/gdm -- GNOME Display Manager
|
||||||
|
|
||||||
|
# The BusyBox ntpd does not use syslog when running in the foreground
|
||||||
|
# So we use this trick to redirect stdout/stderr to a log file. The
|
||||||
|
# log file is rotated with the above settings. The condition declares
|
||||||
|
# a dependency on a system default route (gateway) to be set. A single
|
||||||
|
# <!> at the beginning means ntpd does not respect SIGHUP for restart.
|
||||||
|
service [2345] log:/var/log/ntpd.log <!net/route/default> /sbin/ntpd -n -l -I eth0 -- NTP daemon
|
||||||
|
|
||||||
# Run start scripts from this directory
|
# Run start scripts from this directory
|
||||||
# runparts /etc/start.d
|
# runparts /etc/start.d
|
||||||
|
|
||||||
|
|||||||
Executable
+51
@@ -0,0 +1,51 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
USAGE="Usage: $0 processName"
|
||||||
|
LOG_FILE="/tmp/memusage.csv"
|
||||||
|
ELAPSED_TIME=0
|
||||||
|
PERIOD=1 # seconds
|
||||||
|
|
||||||
|
if [ $# -ne 1 ]; then
|
||||||
|
echo $USAGE
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "ElapsedTime,VmSize,VmRSS" > $LOG_FILE
|
||||||
|
|
||||||
|
# Monitor memory usage forever until script is killed
|
||||||
|
while :
|
||||||
|
do
|
||||||
|
SUM_VM_SIZE=0
|
||||||
|
SUM_RSS_SIZE=0
|
||||||
|
# In case the monitored process has not yet started
|
||||||
|
# keep searching until its PID is found
|
||||||
|
PROCESS_PIDS=""
|
||||||
|
while :
|
||||||
|
do
|
||||||
|
PROCESS_PIDS=`/bin/pidof $1`
|
||||||
|
if [ "$PROCESS_PIDS.X" != ".X" ]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
for PID in ${PROCESS_PIDS} ; do
|
||||||
|
VM_SIZE=`awk '/VmSize/ {print $2}' < /proc/$PID/status`
|
||||||
|
if [ "$VM_SIZE.X" = ".X" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
#echo exprVM_ $SUM_VM_SIZE + $VM_SIZE
|
||||||
|
SUM_VM_SIZE=`expr $SUM_VM_SIZE + $VM_SIZE`
|
||||||
|
|
||||||
|
VM_RSS=`awk '/VmRSS/ {print $2}' < /proc/$PID/status`
|
||||||
|
if [ "$VM_RSS.X" = ".X" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
SUM_RSS_SIZE=`expr $SUM_RSS_SIZE + $VM_RSS`
|
||||||
|
done
|
||||||
|
echo "$ELAPSED_TIME sec, $SUM_VM_SIZE KB, $SUM_RSS_SIZE KB"
|
||||||
|
echo "$ELAPSED_TIME,$SUM_VM_SIZE,$SUM_RSS_SIZE" >> $LOG_FILE
|
||||||
|
sleep $PERIOD
|
||||||
|
VM_SIZE=""
|
||||||
|
VM_RSS=""
|
||||||
|
# Needs to get actual elapsed time instead of doing this
|
||||||
|
ELAPSED_TIME=`expr $ELAPSED_TIME + $PERIOD`
|
||||||
|
done
|
||||||
Executable
+33
@@ -0,0 +1,33 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
JOB=$1
|
||||||
|
CMD=$2
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "Usage: service [job# | name] <stop | start | restart | status | show>"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
|
initctl show
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
case $CMD in
|
||||||
|
stop)
|
||||||
|
;;
|
||||||
|
start)
|
||||||
|
;;
|
||||||
|
restart)
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
;;
|
||||||
|
show)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
initctl $2 $1
|
||||||
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
SUBDIRS = finit.d
|
||||||
|
docsdir := @docdir@/contrib/void
|
||||||
|
docs_DATA = README.md finit.conf build.sh install.sh rc.local xbps
|
||||||
|
EXTRA_DIST = $(docs_DATA)
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
SUBDIRS = available
|
||||||
|
docsdir := @docdir@/contrib/void/finit.d
|
||||||
|
d_LINKS = acpid.conf dhcpcd.conf getty.conf sshd.conf uuidd.conf
|
||||||
|
|
||||||
|
install-exec-hook:
|
||||||
|
@$(MKDIR_P) $(DESTDIR)$(docsdir)/available
|
||||||
|
@for file in $(d_LINKS); do \
|
||||||
|
lnk=$(DESTDIR)$(docsdir)/$$file; \
|
||||||
|
src=available/$$file; \
|
||||||
|
if [ -L $$lnk ]; then \
|
||||||
|
echo "Skipping $$lnk exists."; \
|
||||||
|
else \
|
||||||
|
$(LN_S) $$src $$lnk; \
|
||||||
|
fi; \
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
uninstall-hook:
|
||||||
|
@for file in $(d_LINKS); do \
|
||||||
|
lnk=$(DESTDIR)$(docsdir)/$$file; \
|
||||||
|
src=available/$$file; \
|
||||||
|
if [ "`readlink $$lnk`" != "$$src" ]; then \
|
||||||
|
continue; \
|
||||||
|
fi; \
|
||||||
|
$(RM) $$lnk; \
|
||||||
|
done
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
docsdir := @docdir@/contrib/void/finit.d/available
|
||||||
|
docs_DATA = acpid.conf crond.conf dhcpcd.conf dmeventd.conf getty.conf \
|
||||||
|
keymap.conf klogd.conf lxdm.conf modules.conf ntpd.conf \
|
||||||
|
sshd.conf syslogd.conf uuidd.conf
|
||||||
|
EXTRA_DIST = $(docs_DATA)
|
||||||
-287
@@ -1,287 +0,0 @@
|
|||||||
Configuration
|
|
||||||
=============
|
|
||||||
|
|
||||||
* [Introduction](#introduction)
|
|
||||||
* [Syntax](#syntax)
|
|
||||||
* [Limitations](#limitations)
|
|
||||||
* [/etc/finit.conf](#etcfinitconf)
|
|
||||||
* [/etc/finit.d](#etcfinitd)
|
|
||||||
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
------------
|
|
||||||
|
|
||||||
Finit can be configured using only the original `/etc/finit.conf` file
|
|
||||||
or in combination with `/etc/finit.d/*.conf`. Finit 3 can even start a
|
|
||||||
system using only `/etc/finit.d/*.conf`, highly useful for package-based
|
|
||||||
Linux distributions -- each package can provide its own "script" file.
|
|
||||||
|
|
||||||
- `/etc/finit.conf`: main configuration file, read only once at boot
|
|
||||||
- `/etc/finit.d/*.conf`: snippets, usually one service per file
|
|
||||||
|
|
||||||
Not all configuration directives are available in `/etc/finit.d/*.conf`
|
|
||||||
and some directives are only available at bootstrap, runlevel `S`, see
|
|
||||||
the section [Limitations](#limitations) below for details.
|
|
||||||
|
|
||||||
To add a new service, simply drop a `.conf` file in `/etc/finit.d` and
|
|
||||||
run `initctl reload`. (It is also possible to `SIGHUP` to PID 1, or
|
|
||||||
call `finit q`, but that has been deprecated with the `initctl` tool).
|
|
||||||
Any service read from this directory is flagged as a dynamic service, so
|
|
||||||
changes to or removal of `/etc/finit.d/*.conf` files, is detected.
|
|
||||||
|
|
||||||
On `initctl reload` the following is checked for all services:
|
|
||||||
|
|
||||||
- If a service's `.conf` file has been removed, or its conditions are no
|
|
||||||
longer satisifed, the service is stopped.
|
|
||||||
- If the file is modified, or a service it depends on has been reloaded,
|
|
||||||
the service is reloaded (stopped and started).
|
|
||||||
- If a new service is added it is automatically started — respecting
|
|
||||||
runlevels and return values from any callbacks.
|
|
||||||
|
|
||||||
For more info on the different states of a service, see the separate
|
|
||||||
document [Finit Services](service.md).
|
|
||||||
|
|
||||||
|
|
||||||
Syntax
|
|
||||||
------
|
|
||||||
|
|
||||||
* `module <MODULE>`
|
|
||||||
Load a kernel module, with optional arguments
|
|
||||||
|
|
||||||
* `network <PATH>`
|
|
||||||
Script or program to bring up networking, with optional arguments
|
|
||||||
|
|
||||||
* `rlimit <hard|soft> RESOURCE <LIMIT|unlimited>`
|
|
||||||
Set the hard or soft limit for a resource. `RESOURCE` is a lower-case
|
|
||||||
string matching the `RLIMIT_` constants from `setrlimit(2)`, without
|
|
||||||
the prefix. E.g. to set `RLIMIT_CPU`, use `cpu`.
|
|
||||||
|
|
||||||
The limit is an integer that depends on the resource being modified,
|
|
||||||
see the man page, or the kernel `/proc/PID/limits` file, for more
|
|
||||||
information. Finit versions before v3.1 used `infinity` for
|
|
||||||
`unlimited`, which is still a supported keyword.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# No process is allowed more than 8MB of address space
|
|
||||||
rlimit hard as 8388608
|
|
||||||
|
|
||||||
# Core dumps may be arbitrarily large
|
|
||||||
rlimit soft core infinity
|
|
||||||
```
|
|
||||||
|
|
||||||
* `runlevel <N>`
|
|
||||||
N is the runlevel number 1-9, where 6 is reserved for reboot.
|
|
||||||
Default is 2.
|
|
||||||
|
|
||||||
* `run [LVLS] <COND> /path/to/cmd ARGS -- Optional description`
|
|
||||||
One-shot command to run in sequence when entering a runlevel, with
|
|
||||||
optional arguments and description.
|
|
||||||
|
|
||||||
`run` commands are guaranteed to be completed before running the next
|
|
||||||
command. Highly useful if true serialization is needed.
|
|
||||||
|
|
||||||
* `task [LVLS] <COND> /path/to/cmd ARGS -- Optional description`
|
|
||||||
One-shot like 'run', but starts in parallel with the next command.
|
|
||||||
|
|
||||||
Both `run` and `task` commands are run in a shell, so pipes and
|
|
||||||
redirects can be freely used:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
task [s] echo "foo" | cat >/tmp/bar
|
|
||||||
```
|
|
||||||
|
|
||||||
* `service [LVLS] <COND> /path/to/daemon ARGS -- Optional description`
|
|
||||||
Service, or daemon, to be monitored and automatically restarted if it
|
|
||||||
exits prematurely. Please note that you often need to provide a
|
|
||||||
`--foreground` or `--no-background` argument to most daemons to
|
|
||||||
prevent them from forking off a sub-process in the background.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
service [2345] <svc/sbin/zebra> /sbin/ospfd -- OSPF daemon
|
|
||||||
```
|
|
||||||
|
|
||||||
The `[2345]` is the runlevels `ospfd` is allowed to run in, they are
|
|
||||||
optional and default to level 2-5 if left out.
|
|
||||||
|
|
||||||
The `<...>` is the condition for starting `ospfd`. In this example
|
|
||||||
Finit waits for another service, `/sbin/zebra`, to have created its
|
|
||||||
PID file in `/var/run/zebra.pid` before starting `ospfd`.
|
|
||||||
|
|
||||||
For a detailed description of conditions, and how to debug them,
|
|
||||||
see the [Finit Conditions](conditions.md) document.
|
|
||||||
|
|
||||||
* `inetd service/proto[@iflist] <wait|nowait> [LVLS] /path/to/daemon args`
|
|
||||||
Launch a daemon when a client initiates a connection on an Internet
|
|
||||||
port. Available services are listed in the UNIX `/etc/services` file.
|
|
||||||
Finit can filter access to from a list of interfaces, `@iflist`, per
|
|
||||||
inetd service as well as listen to custom ports.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
inetd ftp/tcp nowait @root /usr/sbin/uftpd -i -f
|
|
||||||
inetd tftp/udp wait @root /usr/sbin/uftpd -i -t
|
|
||||||
```
|
|
||||||
|
|
||||||
The following example listens to port 2323 for telnet connections and
|
|
||||||
only allows clients connecting from `eth0`:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
inetd 2323/tcp@eth0 nowait [2345] /sbin/telnetd -i -F
|
|
||||||
```
|
|
||||||
|
|
||||||
The interface list, `@iflist`, is of the format `@iface,!iface,iface`,
|
|
||||||
where a single `!` means to deny access. Notice how interfaces are
|
|
||||||
comma separated with no spaces.
|
|
||||||
|
|
||||||
The `inetd` directive can also have ` -- Optional Description`, only
|
|
||||||
Finit does not output this text on the console when launching inetd
|
|
||||||
services. Instead this text is sent to syslog and also shown by the
|
|
||||||
`initctl` tool. More on inetd below.
|
|
||||||
|
|
||||||
* `runparts <DIR>`
|
|
||||||
Call [run-parts(8)][] on `DIR` to run start scripts. All executable
|
|
||||||
files, or scripts, in the directory are called, in alphabetic order.
|
|
||||||
|
|
||||||
It can be beneficial to use `S01name`, `S02othername`, etc. if there
|
|
||||||
is a dependency order between the scripts. Symlinks to existing
|
|
||||||
daemons can talso be used, but make sure they daemonize by default.
|
|
||||||
|
|
||||||
As the optional `/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.
|
|
||||||
|
|
||||||
* `include <CONF>`
|
|
||||||
Include another configuration file. Absolute path required.
|
|
||||||
|
|
||||||
* `tty [LVLS] <DEV> [BAUD] [noclear] [nowait] [TERM]`
|
|
||||||
`tty [LVLS] <CMD> <ARGS> [noclear] [nowait]`
|
|
||||||
The first variant of this option uses the built-in getty on the given
|
|
||||||
TTY device DEV, in the given runlevels. Default baud rate is `38400`.
|
|
||||||
|
|
||||||
**Example:**
|
|
||||||
```conf
|
|
||||||
tty [12345] /dev/ttyAMA0 115200 noclear vt220
|
|
||||||
```
|
|
||||||
|
|
||||||
The second `tty` syntax variant is for using an external getty, like
|
|
||||||
agetty or the BusyBox getty.
|
|
||||||
|
|
||||||
By default both variants *clear* the TTY and *wait* for the user to
|
|
||||||
press enter before starting getty.
|
|
||||||
|
|
||||||
**Example:**
|
|
||||||
```conf
|
|
||||||
tty [12345] /sbin/getty -L 115200 /dev/ttyAMA0 vt100
|
|
||||||
tty [12345] /sbin/agetty -L ttyAMA0 115200 vt100 nowait
|
|
||||||
```
|
|
||||||
|
|
||||||
The `noclear` option disables clearing the TTY after each session.
|
|
||||||
Clearing the TTY when a user logs out is usually preferable.
|
|
||||||
|
|
||||||
The `nowait` option disables the `press Enter to activate console`
|
|
||||||
message before actually starting the getty program. On small and
|
|
||||||
embedded systems running multiple unused getty wastes both memory
|
|
||||||
and CPU cycles, so `wait` is the preferred default.
|
|
||||||
|
|
||||||
Notice the ordering, the `TERM` option to the built-in getty must be
|
|
||||||
the last argument.
|
|
||||||
|
|
||||||
Embedded systems may want to enable automatic `DEV` by supplying the
|
|
||||||
special `@console` device. This works regardless weather the system
|
|
||||||
uses `ttyS0`, `ttyAMA0`, `ttyMXC0`, or anything else. Finit figures
|
|
||||||
it out by querying sysfs: `/sys/class/tty/console/active`.
|
|
||||||
|
|
||||||
**Example:**
|
|
||||||
```conf
|
|
||||||
tty [12345] @console 115200 noclear vt220
|
|
||||||
```
|
|
||||||
|
|
||||||
On really bare bones systems Finit offers a fallback shell, which
|
|
||||||
should not be enabled on production systems since. This because it
|
|
||||||
may give a user root access without having to log in. However, for
|
|
||||||
bringup and system debugging it can come in handy:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
configure --enable-fallback-shell
|
|
||||||
```
|
|
||||||
|
|
||||||
One can also use the `service` stanza to start a stand-alone shell:
|
|
||||||
|
|
||||||
```conf
|
|
||||||
service [12345] /bin/sh -l
|
|
||||||
```
|
|
||||||
|
|
||||||
When running <kbd>make install</kbd> no default `/etc/finit.conf` will
|
|
||||||
be installed since system requirements differ too much. Try out the
|
|
||||||
Debian 6.0 example `/usr/share/doc/finit/finit.conf` configuration that
|
|
||||||
is capable of service monitoring SSH, sysklogd, gdm and getty!
|
|
||||||
|
|
||||||
Every `run`, `task`, `service`, or `inetd` can also list the privileges
|
|
||||||
the `/path/to/cmd` should be executed with. Simply prefix the path with
|
|
||||||
`[@USR[:GRP]]` like this:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
run [2345] @joe:users /usr/bin/logger "Hello world"
|
|
||||||
```
|
|
||||||
|
|
||||||
For multiple instances of the same command, e.g. a DHCP client or
|
|
||||||
multiple web servers, add `:ID` somewhere between the `run`, `task`,
|
|
||||||
`service` keyword and the command, like this:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
service :1 [2345] /sbin/httpd -f -h /http -p 80 -- Web server
|
|
||||||
service :2 [2345] /sbin/httpd -f -h /http -p 8080 -- Old web server
|
|
||||||
```
|
|
||||||
|
|
||||||
Without the `:ID` to the service the latter will overwrite the former
|
|
||||||
and only the old web server would be started and supervised.
|
|
||||||
|
|
||||||
The `run`, `task`, `service`, or `inetd` stanzas also allow the keyword
|
|
||||||
`log` to redirect `stderr` and `stdout` of the application to syslog,
|
|
||||||
using `logger`.
|
|
||||||
|
|
||||||
Worth noting is that conditions is allowed for all these stanzas. For a
|
|
||||||
detailed description, see the [Conditions](conditions.md) document.
|
|
||||||
|
|
||||||
|
|
||||||
Limitations
|
|
||||||
-----------
|
|
||||||
|
|
||||||
To understand the limitations of `finit.conf` vs `finit.d` it is useful
|
|
||||||
to picture the different phases of the system: bootstrap, runtime, and
|
|
||||||
shutdown. The `finit.conf` file can be used for all possible settings,
|
|
||||||
but `finit.d/*.conf` can only be used for runtime settings.
|
|
||||||
|
|
||||||
### /etc/finit.conf
|
|
||||||
|
|
||||||
This file was the only way to set up and boot a system using Finit. It
|
|
||||||
is used for pre-runtime settings like system hostname, network bringup
|
|
||||||
and shutdown:
|
|
||||||
|
|
||||||
- `host`
|
|
||||||
- `mkdod`
|
|
||||||
- `network`
|
|
||||||
- `runparts`
|
|
||||||
- `include`
|
|
||||||
- `shtudown`
|
|
||||||
- `runlevel`
|
|
||||||
- ... and all configuration stanzas from `/etc/finit.d` below
|
|
||||||
|
|
||||||
### /etc/finit.d
|
|
||||||
|
|
||||||
Support for partial `.conf` files in `/etc/finit.d` was added to handle
|
|
||||||
changes of the system configuration at runtime. It does *not support*
|
|
||||||
the above `finit.conf` settings described above, only the following:
|
|
||||||
|
|
||||||
- `module`, but only in runlevel `S`
|
|
||||||
- `service`
|
|
||||||
- `task`
|
|
||||||
- `run`
|
|
||||||
- `inetd`
|
|
||||||
- `rlimit`
|
|
||||||
- `tty`
|
|
||||||
|
|
||||||
**NOTE:** The `/etc/finit.d` directory was previously the default Finit
|
|
||||||
`runparts` directory. Finit no longer has a default `runparts`, make
|
|
||||||
sure to update your setup, or the finit configuration, accordingly.
|
|
||||||
|
|
||||||
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
Makefile
|
||||||
|
Makefile.in
|
||||||
File renamed without changes.
@@ -66,9 +66,6 @@ how `git commit -s` is used to automatically add a `Signed-off-by`:
|
|||||||
Signed-off-by: Jane Doe <jane.doe@example.com>
|
Signed-off-by: Jane Doe <jane.doe@example.com>
|
||||||
|
|
||||||
|
|
||||||
Another good *counter* example [is this][rambling] ...
|
|
||||||
|
|
||||||
|
|
||||||
Code of Conduct
|
Code of Conduct
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
@@ -79,11 +76,4 @@ Bill & Ted; [be excellent to each other][conduct].
|
|||||||
[github]: https://github.com/troglobit/finit/
|
[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
|
||||||
[rambling]: http://stopwritingramblingcommitmessages.com/
|
|
||||||
[conduct]: https://github.com/troglobit/finit/blob/master/CODE-OF-CONDUCT.md
|
[conduct]: https://github.com/troglobit/finit/blob/master/CODE-OF-CONDUCT.md
|
||||||
|
|
||||||
<!--
|
|
||||||
-- Local Variables:
|
|
||||||
-- mode: markdown
|
|
||||||
-- End:
|
|
||||||
-->
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
docsdir := @docdir@/docs
|
||||||
|
docs_DATA = config.md conditions.md distro.md inetd.md plugins.md \
|
||||||
|
service.md signals.md svc-machine.png cmdline.md
|
||||||
|
EXTRA_DIST = $(docs_DATA)
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
config.md
|
||||||
+31
-36
@@ -18,27 +18,30 @@ after a reconfiguration (`initctl reload`), the Finit dependency system
|
|||||||
can also be used.
|
can also be used.
|
||||||
|
|
||||||
|
|
||||||
General
|
Near Future
|
||||||
-------
|
-----------
|
||||||
|
|
||||||
* Add support for `rescue` on the kernel command line, start rescue mode
|
* When a process dies, and Finit does not restart it, we should collect
|
||||||
if enabled with `configure` script. Could mean skip `/etc/finit.conf`
|
a `siginfo_t` from the SIGCHLD signal and supply to the user in case
|
||||||
et al and jump straight to a single getty login on console.
|
`initctl status <process>` is called to debug the issue.
|
||||||
* Add support for timed shutdown in Finit, including cancelled shutdown.
|
* Merge UDP redirect service uredir as an UDP inetd variant
|
||||||
* SysV init and systemd use SIGUSR1 to restart their FIFO/D-Bus. Add
|
|
||||||
API restart to SIGHUP callback for the same functionality in Finit.
|
|
||||||
* Add `finit.conf` support for UPS notification (SIGPWR) to start a task
|
* Add `finit.conf` support for UPS notification (SIGPWR) to start a task
|
||||||
using, e.g. <sys/power/{ok,fail,low}> conditions. More info in sig.c
|
using, e.g. <sys/power/{ok,fail,low}> conditions. More info in sig.c
|
||||||
* Add `finit.conf` support for ctrl-alt-delete (SIGINT) and kbrequest,
|
* Add `finit.conf` support for ctrl-alt-delete (SIGINT) and kbrequest,
|
||||||
i.e. KeyboardSignal, (SIGWINCH) behavior. Using conditions to a task,
|
i.e. KeyboardSignal, (SIGWINCH) behavior. Using conditions to a task,
|
||||||
e.g, <sys/key/ctrlaltdel> and <sys/key/signal> like SIGPWR handling.
|
e.g, <sys/key/ctrlaltdel> and <sys/key/signal> like SIGPWR handling.
|
||||||
* Add `IFF_RUNNING` support to netlink plugin along `IFF_UP`
|
* Cron/At support, see below
|
||||||
* Implement `initctl stop|start|restart|reload|status <SVC>` and
|
* Write man pages for finit and `finit.conf`, steal from the excellent
|
||||||
`service <SVC> stop|start|restart|reload|status` on top
|
`pimd` man pages ...
|
||||||
|
|
||||||
|
|
||||||
|
General
|
||||||
|
-------
|
||||||
|
|
||||||
|
* Add support for timed shutdown in Finit, including cancelled shutdown,
|
||||||
|
possibly using an at-job, see [crond section](#Crond) below
|
||||||
* Add support for JSON output, or similar, from `initctl show`, e.g.
|
* Add support for JSON output, or similar, from `initctl show`, e.g.
|
||||||
`initctl show --json`
|
`initctl show --json`
|
||||||
* Improve `initctl show SVC` output. Add service uptime, last ten SVC
|
|
||||||
logs/history (historian), etc. Similar to `systemctl show SVC`
|
|
||||||
* [Solaris SMF][] (Service Management Facility) has some interesting
|
* [Solaris SMF][] (Service Management Facility) has some interesting
|
||||||
features that may be well worth looking into adopting:
|
features that may be well worth looking into adopting:
|
||||||
|
|
||||||
@@ -49,6 +52,15 @@ General
|
|||||||
* `initctl add /sbin/service -n -- Service description`, for details
|
* `initctl add /sbin/service -n -- Service description`, for details
|
||||||
see above [Solaris SMF][] featuer, issue #55 and issue #69,
|
see above [Solaris SMF][] featuer, issue #55 and issue #69,
|
||||||
https://github.com/troglobit/finit/issues/69#issuecomment-287907610
|
https://github.com/troglobit/finit/issues/69#issuecomment-287907610
|
||||||
|
* Changing the name of a pidfile, `pid:[/path/]file.pid`, after a
|
||||||
|
service has been started is not supported atm. The previous name will
|
||||||
|
not be (never) removed and the new name will not be created until the
|
||||||
|
process has been stopped and started again.
|
||||||
|
* PID files created in subdirectories to `/run` is not supported right
|
||||||
|
now inotify listeners should be automatically created (and removed)
|
||||||
|
when a subdirectory is added (or removed).
|
||||||
|
|
||||||
|
[Solaris SMF]: http://www.oracle.com/technetwork/articles/servers-storage-admin/intro-smf-basics-s11-1729181.html
|
||||||
|
|
||||||
|
|
||||||
Init
|
Init
|
||||||
@@ -85,14 +97,16 @@ system-level timed periodic tasks:
|
|||||||
Proposed syntax:
|
Proposed syntax:
|
||||||
|
|
||||||
# Crontab
|
# Crontab
|
||||||
cron @YY-mm-ddTHH:MM [LVLS] /path/to/cmd [ARGS] -- Optional descr
|
cron @SPEC [LVLS] /path/to/cmd [ARGS] -- Optional descr
|
||||||
|
|
||||||
# One-shot 'at' command
|
# One-shot 'at' command
|
||||||
at @YY-mm-ddTHH:MM [LVLS] /path/to/cmd [ARGS] -- Optional descr
|
at @YY-mm-ddTHH:MM [LVLS] /path/to/cmd [ARGS] -- Optional descr
|
||||||
|
|
||||||
Notice the ISO date in notation. The runlevels is extra filtering
|
Notice the ISO date in the `at` notation. The `cron @SPEC` could use
|
||||||
sugar. E.g., if cron service is only allowed in runlevels two or three
|
are mo loose notation, e.g. `@hourly`, `@midnight`, `@daily`, `@weekly`,
|
||||||
it will not start if system currently is in runlevel four.
|
`@reboot`, etc. The runlevels is extra filtering sugar. E.g., if cron
|
||||||
|
service is only allowed in runlevels two or three it will not start if
|
||||||
|
system currently is in runlevel four.
|
||||||
|
|
||||||
To run a command as another user the `.conf` file must have a that
|
To run a command as another user the `.conf` file must have a that
|
||||||
owner. E.g., `/etc/finit.d/extra.conf` may be owned by operator and
|
owner. E.g., `/etc/finit.d/extra.conf` may be owned by operator and
|
||||||
@@ -103,22 +117,3 @@ could support the basic functionality of the `at` command directly from
|
|||||||
the shell -- that way setting up one-time jobs would not entail
|
the shell -- that way setting up one-time jobs would not entail
|
||||||
re-reading `/etc/finit.conf`
|
re-reading `/etc/finit.conf`
|
||||||
|
|
||||||
|
|
||||||
Documentation
|
|
||||||
-------------
|
|
||||||
|
|
||||||
* Write man pages for finit and `finit.conf`, steal from the excellent
|
|
||||||
`pimd` man pages ...
|
|
||||||
* Add simple, *very* simple, `finit-simple.conf` example. To illustrate
|
|
||||||
how close Finit3 still is to the original easy-to-use Finit0 :)
|
|
||||||
|
|
||||||
|
|
||||||
[libwdt]: http://www.wehavemorefun.de/fritzbox/Libwdt.so
|
|
||||||
[Fritz!Box source dump]: ftp://ftp.avm.de/fritz.box/fritzbox.fon_wlan_7170/x_misc/opensrc/
|
|
||||||
[Solaris SMF]: http://www.oracle.com/technetwork/articles/servers-storage-admin/intro-smf-basics-s11-1729181.html
|
|
||||||
|
|
||||||
<!--
|
|
||||||
-- Local Variables:
|
|
||||||
-- mode: markdown
|
|
||||||
-- End:
|
|
||||||
-->
|
|
||||||
@@ -5,7 +5,7 @@ Bootstrap
|
|||||||
2. Set up initial signal handlers
|
2. Set up initial signal handlers
|
||||||
3. Set up default $PATH early
|
3. Set up default $PATH early
|
||||||
4. Mount `/proc` and `/sys`
|
4. Mount `/proc` and `/sys`
|
||||||
5. Check kernel command line for `--debug` to figure out log level
|
5. Check kernel command line for `debug` to figure out log level
|
||||||
6. Load all `.so` plugins
|
6. Load all `.so` plugins
|
||||||
7. Call `fsck` on file systems listed in `/etc/fstab`
|
7. Call `fsck` on file systems listed in `/etc/fstab`
|
||||||
8. Populate `/dev` using either udev or mdev, depending on system type
|
8. Populate `/dev` using either udev or mdev, depending on system type
|
||||||
@@ -25,13 +25,13 @@ Bootstrap
|
|||||||
20. Bring up loopback interface and all `/etc/network/interfaces`, if
|
20. Bring up loopback interface and all `/etc/network/interfaces`, if
|
||||||
the `.conf` setting `network <SCRIPT>` is set, it is called instead
|
the `.conf` setting `network <SCRIPT>` is set, it is called instead
|
||||||
21. Call 3rd level hooks, `HOOK_NETWORK_UP`
|
21. Call 3rd level hooks, `HOOK_NETWORK_UP`
|
||||||
22. Switch to the configured runlevel from `/etc/finit.conf`, default 2.
|
22. If `runparts <DIR>` is set, [run-parts(8)][] is called on `<DIR>`
|
||||||
|
23. Switch to the configured runlevel from `/etc/finit.conf`, default 2.
|
||||||
At every runlevel change all `*.conf` files in `/etc/finit.d/` are
|
At every runlevel change all `*.conf` files in `/etc/finit.d/` are
|
||||||
(re)loaded and new services, tasks, and blocking run commands are
|
(re)loaded and new services, tasks, and blocking run commands are
|
||||||
started. Provided they are allowed in the new runlevel and all of
|
started. Provided they are allowed in the new runlevel and all of
|
||||||
their conditions, if any, are set.
|
their conditions, if any, are set.
|
||||||
23. Call 4th level hooks, `HOOK_SVC_UP`
|
24. Call 4th level hooks, `HOOK_SVC_UP`
|
||||||
24. If `runparts <DIR>` is set, [run-parts(8)][] is called on `<DIR>`
|
|
||||||
25. Call `/etc/rc.local`, if it exists and is an executable shell script
|
25. Call `/etc/rc.local`, if it exists and is an executable shell script
|
||||||
26. Call 5th level (last) hooks, `HOOK_SYSTEM_UP`
|
26. Call 5th level (last) hooks, `HOOK_SYSTEM_UP`
|
||||||
27. Start all configured TTYs, or a fallback shell on `/dev/console`
|
27. Start all configured TTYs, or a fallback shell on `/dev/console`
|
||||||
@@ -53,8 +53,6 @@ Below are a few of the main switches to configure:
|
|||||||
|
|
||||||
* `--enable-dbus-plugin`: Enable the optional D-Bus `dbus.so` plugin.
|
* `--enable-dbus-plugin`: Enable the optional D-Bus `dbus.so` plugin.
|
||||||
|
|
||||||
* `--enable-lost-plugin`: Enable noisy example plugin for `HOOK_SVC_LOST`.
|
|
||||||
|
|
||||||
* `--enable-resolvconf-plugin`: Enable the `resolvconf.so` optional plugin.
|
* `--enable-resolvconf-plugin`: Enable the `resolvconf.so` optional plugin.
|
||||||
|
|
||||||
* `--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.
|
||||||
@@ -124,14 +122,32 @@ append="init=/sbin/finit"
|
|||||||
Remember to also set up an initial `/etc/finit.conf` before rebooting!
|
Remember to also set up an initial `/etc/finit.conf` before rebooting!
|
||||||
|
|
||||||
|
|
||||||
|
Recovery
|
||||||
|
--------
|
||||||
|
|
||||||
|
To rescue a system with Finit, append the following to the kernel
|
||||||
|
command line:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
append="init=/sbin/finit rescue"
|
||||||
|
```
|
||||||
|
|
||||||
|
This tells Finit to start in a very limited recovery mode, no services
|
||||||
|
are loaded, no filesystems are mounted or checked, and no networking is
|
||||||
|
enabled. The default Finit rescue mode configuration is installed into
|
||||||
|
`/lib/finit/rescue.conf`, which can be safely removed or changed.
|
||||||
|
|
||||||
|
By default the a root shell, without login, is started.
|
||||||
|
|
||||||
|
|
||||||
Debugging
|
Debugging
|
||||||
---------
|
---------
|
||||||
|
|
||||||
Add `finit_debug`, or `--debug`, to the kernel command line to enable
|
Edit, or append to, the kernel command line: remove `quiet` to enable
|
||||||
debug messages.
|
kernel messages and add `debug` to enable Finit debug messages.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
append="init=/sbin/finit --debug"
|
append="init=/sbin/finit debug"
|
||||||
```
|
```
|
||||||
|
|
||||||
To debug startup issues, in particular issues with getty/login, try
|
To debug startup issues, in particular issues with getty/login, try
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
Tips & Tricks with the kernel cmdline
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
This document summarizes the different boot parameters that can be
|
||||||
|
passed on the Linux kernel command line. Not just limited to Finit.
|
||||||
|
|
||||||
|
* `debug`, or `--debug`
|
||||||
|
Enable debug mode. The former syntax also enable kernel debug, and
|
||||||
|
the latter only in Finit. Debug messages are printed to the console
|
||||||
|
until a syslog daemon has been started.
|
||||||
|
|
||||||
|
* `init=/bin/sh`
|
||||||
|
Bypass system default init and tell kernel to start a shell. Note,
|
||||||
|
this shell is very limited and does not support signals and has no
|
||||||
|
job control. Recommend using, and modifying, `rescue` mode instead.
|
||||||
|
|
||||||
|
* `panic=SEC`
|
||||||
|
By default the kernel does not reboot after a kernel panic. This
|
||||||
|
setting will cause a kernel reboot after SEC seconds.
|
||||||
|
|
||||||
|
* `quiet`
|
||||||
|
Suppress kernel logging to console, except for warnings and errors.
|
||||||
|
|
||||||
|
* `rescue`
|
||||||
|
Start Finit rescue mode; no network, no `fsck` of file systems in
|
||||||
|
`/etc/fstab`, no `/etc/rc.local`, no `runparts`. The configuration
|
||||||
|
is read from `/etc/rescue.conf`, can be modified by the operator.
|
||||||
|
|
||||||
|
* `single`, or `S`
|
||||||
|
Single user mode, runlevel 1, in Finit. Useful to debug problems with
|
||||||
|
the regular runlevel. All services and TTYs in `[1]` will be started,
|
||||||
|
so a `tty [1] @console nologin` configuration presents you with a
|
||||||
|
root console without login.
|
||||||
|
|
||||||
|
* `splash`
|
||||||
|
Display Finit splash screen with progress at bootstrap and shutdown.
|
||||||
|
|
||||||
|
For more on kernel boot paramaters, see the man page `bootparam(7)`.
|
||||||
@@ -47,17 +47,7 @@ service's PID file being created.
|
|||||||
Triggering
|
Triggering
|
||||||
----------
|
----------
|
||||||
|
|
||||||
Conditions are triggered by built-in plugins, but can for debugging
|
Conditions can only be triggered by built-in plugins.
|
||||||
purposes also be controlled using the `cond set` and `cond clear`
|
|
||||||
sub-commands to the `initctl` control tool:
|
|
||||||
|
|
||||||
* `initctl cond set your/cond/here`
|
|
||||||
|
|
||||||
To set a condition
|
|
||||||
|
|
||||||
* `initctl cond clear your/cond/here`
|
|
||||||
|
|
||||||
To clear a condition
|
|
||||||
|
|
||||||
Conditions retain their current state until the next reconfiguration or
|
Conditions retain their current state until the next reconfiguration or
|
||||||
runlevel change. At that point all set conditions transition into the
|
runlevel change. At that point all set conditions transition into the
|
||||||
@@ -95,10 +85,30 @@ Built-in conditions:
|
|||||||
- `net/route/default`
|
- `net/route/default`
|
||||||
- `net/<IFNAME>/exist`
|
- `net/<IFNAME>/exist`
|
||||||
- `net/<IFNAME>/up`
|
- `net/<IFNAME>/up`
|
||||||
|
- `net/<IFNAME>/running`
|
||||||
|
|
||||||
**Note:** `up` means administratively up, the interface flag `IFF_UP`,
|
**Note:** `up` means administratively up, the interface flag `IFF_UP`.
|
||||||
not link up, `IFF_RUNNING`. This latter conditions is currently not
|
`running` is the `IFF_RUNNING` flag, meaning operatively up. The
|
||||||
implemented by the `plugins/netlink.c` plugin.
|
difference is that `running` tells if the NIC has link.
|
||||||
|
|
||||||
|
|
||||||
|
Composition
|
||||||
|
-----------
|
||||||
|
|
||||||
|
The `svc/` conditions can be quite tricky to understand. They are
|
||||||
|
generated by the Finit `pidfile.so` plugin and are composed from the
|
||||||
|
daemon's path and the pidfile name (and path).
|
||||||
|
|
||||||
|
| **service** | **pid:** | **pidfile path** | **svc condition** |
|
||||||
|
|--------------------------------------|-----------------|------------------|-------------------|
|
||||||
|
| /sbin/foo | | /run/foo.pid | svc/sbin/foo |
|
||||||
|
| /sbin/bar -p /run/baz.pid | pid:baz | /run/bas.pid | svc/sbin/baz |
|
||||||
|
| lxc-start -n foo -p /run/lxc/foo.pid | pid:lxc/foo.pid | /run/lxc/foo.pid | svc/lxc/foo |
|
||||||
|
| /usr/bin/dbus-daemon | pid:dbus/pid | /run/dbus/pid | svc/usr/bin/dbus |
|
||||||
|
|
||||||
|
Omitting the `pid:` to run/task/service/sysv stanza means Finit will
|
||||||
|
guess the pidfile path based on `/run/` and the basename(1) of the
|
||||||
|
program.
|
||||||
|
|
||||||
|
|
||||||
Debugging
|
Debugging
|
||||||
@@ -132,12 +142,13 @@ To fake interface `vlan1` suddenly appearing, and test what happens to
|
|||||||
|
|
||||||
```shell
|
```shell
|
||||||
~ # initctl debug
|
~ # initctl debug
|
||||||
~ # initctl cond set net/vlan1/exist
|
~ # mkdir -p /var/run/finit/cond/net/vlan1
|
||||||
|
~ # cp /var/run/finit/cond /var/run/finit/cond/net/vlan1/exist
|
||||||
```
|
```
|
||||||
|
|
||||||
Then watch the console for the debug messages and then check the output
|
Then watch the console for the debug messages and then check the output
|
||||||
from `initctl cond show` again. (The client will likely have failed to
|
from `initctl cond show` again. The client will likely have failed to
|
||||||
start, but at least the condition is now satisfied.)
|
start, but at least the condition is now satisfied.
|
||||||
|
|
||||||
There is also the `initctl cond dump` command, which dumps all known
|
There is also the `initctl cond dump` command, which dumps all known
|
||||||
conditions and their current status.
|
conditions and their current status.
|
||||||
@@ -146,9 +157,10 @@ conditions and their current status.
|
|||||||
Internals
|
Internals
|
||||||
---------
|
---------
|
||||||
|
|
||||||
Conditions are implemented as simple files in the file system, in the
|
As shown previously, conditions are implemented as simple files in the
|
||||||
`/var/run/finit/cond/` sub-directory. Use the `initctl cond set/clear`
|
file system, in the `/var/run/finit/cond/` sub-directory. The files
|
||||||
commands to add/remove files in this hierarchy.
|
are created, updated, and removed by condition plugins. To debug them,
|
||||||
|
see the previous section.
|
||||||
|
|
||||||
A condition is always in one of three states:
|
A condition is always in one of three states:
|
||||||
|
|
||||||
+457
@@ -0,0 +1,457 @@
|
|||||||
|
Configuration
|
||||||
|
=============
|
||||||
|
|
||||||
|
* [Introduction](#introduction)
|
||||||
|
* [Service Wrapper Scripts](#service-wrapper-scripts)
|
||||||
|
* [Syntax](#syntax)
|
||||||
|
* [Limitations](#limitations)
|
||||||
|
* [/etc/finit.conf](#etcfinitconf)
|
||||||
|
* [/etc/finit.d](#etcfinitd)
|
||||||
|
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
------------
|
||||||
|
|
||||||
|
Finit can be configured using only the original `/etc/finit.conf` file
|
||||||
|
or in combination with `/etc/finit.d/*.conf`. Finit 3 can even start a
|
||||||
|
system using only `/etc/finit.d/*.conf`, highly useful for package-based
|
||||||
|
Linux distributions -- each package can provide its own "script" file.
|
||||||
|
|
||||||
|
- `/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`
|
||||||
|
and some directives are only available at bootstrap, runlevel `S`, see
|
||||||
|
the section [Limitations](#limitations) below for details.
|
||||||
|
|
||||||
|
To add a new service, simply drop a `.conf` file in `/etc/finit.d` and
|
||||||
|
run `initctl reload`. (It is also possible to `SIGHUP` to PID 1, or
|
||||||
|
call `finit q`, but that has been deprecated with the `initctl` tool).
|
||||||
|
Finit monitors all known active `.conf` files, so if you want to force
|
||||||
|
a restart of any service you can simply touch its corresponding `.conf`
|
||||||
|
file in `/etc/finit.d` and call `initctl reload`. Finit handle any
|
||||||
|
and all conditions and dependencies between services automatically.
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
- If a service's `.conf` file has been removed, or its conditions are no
|
||||||
|
longer satisifed, the service is stopped.
|
||||||
|
- If the file is modified, or a service it depends on has been reloaded,
|
||||||
|
the service is reloaded (stopped and started).
|
||||||
|
- If a new service is added it is automatically started — respecting
|
||||||
|
runlevels and return values from any callbacks.
|
||||||
|
|
||||||
|
For more info on the different states of a service, see the separate
|
||||||
|
document [Finit Services](service.md).
|
||||||
|
|
||||||
|
|
||||||
|
Service Wrapper Scripts
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
If your service requires to run additional commands, executed before the
|
||||||
|
service is actually started, like the systemd `ExecStartPre`, you can
|
||||||
|
use a wrapper shell script to start your service.
|
||||||
|
|
||||||
|
The Finit service `.conf` file can be put into `/etc/finit.d/available`,
|
||||||
|
so you can control the service using `initctl`. Then use the path to
|
||||||
|
the wrapper script in the Finit `.conf` service stanza. The following
|
||||||
|
example employs a wrapper script in `/etc/start.d`.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
* `/etc/finit.d/available/program.conf`:
|
||||||
|
```conf
|
||||||
|
service [235] <!> /etc/start.d/program -- Example Program
|
||||||
|
```
|
||||||
|
|
||||||
|
* `/etc/start.d/program:`
|
||||||
|
```shell
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Prepare the command line options
|
||||||
|
OPTIONS="-u $(cat /etc/username)"
|
||||||
|
|
||||||
|
# Execute the program
|
||||||
|
exec /usr/bin/program $OPTIONS
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:**, that the example sets `<!>` to denote that it doesn't support
|
||||||
|
`SIGHUP`. That way Finit will stop/start such the service instead of
|
||||||
|
sending SIGHUP at restart/reload.
|
||||||
|
|
||||||
|
|
||||||
|
Syntax
|
||||||
|
------
|
||||||
|
|
||||||
|
* `host <NAME>`, or `hostname <NAME>`
|
||||||
|
Set system hostname to NAME, unless `/etc/hostname` exists in which
|
||||||
|
case the contents of that file is used.
|
||||||
|
|
||||||
|
* `module <MODULE> [ARGS]`
|
||||||
|
Load a kernel module, with optional arguments. Similar to `insmod`
|
||||||
|
command line tool.
|
||||||
|
|
||||||
|
Note, there is both a `modules-load.so` and a `modprobe.so` plugin
|
||||||
|
that can handle module loading better. The former supports loading
|
||||||
|
from `/etc/modules-load.d/`, and the latter uses kernel modinfo to
|
||||||
|
automatically load (or coldplug) every required module. For hotplug
|
||||||
|
we recommend the BusyBox mdev tool, add to `/etc/mdev.conf`:
|
||||||
|
|
||||||
|
$MODALIAS=.* root:root 0660 @modprobe -b "$MODALIAS"
|
||||||
|
|
||||||
|
* `network <PATH>`
|
||||||
|
Script or program to bring up networking, with optional arguments
|
||||||
|
|
||||||
|
* `rlimit [hard|soft] RESOURCE <LIMIT|unlimited>` Set the hard or soft
|
||||||
|
limit for a resource, or both if that argument is omitted. `RESOURCE`
|
||||||
|
is the lower-case `RLIMIT_` string constants from `setrlimit(2)`,
|
||||||
|
without the prefix. E.g. to set `RLIMIT_CPU`, use `cpu`.
|
||||||
|
|
||||||
|
LIMIT is an integer that depends on the resource being modified, see
|
||||||
|
the man page, or the kernel `/proc/PID/limits` file, for details.
|
||||||
|
Finit versions before v3.1 used `infinity` for `unlimited`, which is
|
||||||
|
still supported, albeit deprecated.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# No process is allowed more than 8MB of address space
|
||||||
|
rlimit hard as 8388608
|
||||||
|
|
||||||
|
# Core dumps may be arbitrarily large
|
||||||
|
rlimit soft core infinity
|
||||||
|
|
||||||
|
# CPU limit for all services, soft & hard = 10 sec
|
||||||
|
rlimit cpu 10
|
||||||
|
```
|
||||||
|
|
||||||
|
`rlimit` can be set globally, in `/etc/finit.conf`, or locally for
|
||||||
|
a set of task/run/services, in `/etc/finit.d/*.conf`.
|
||||||
|
|
||||||
|
* `runlevel <N>`
|
||||||
|
N is the runlevel number 1-9, where 6 is reserved for reboot.
|
||||||
|
Default is 2.
|
||||||
|
|
||||||
|
* `run [LVLS] <COND> /path/to/cmd ARGS -- Optional description`
|
||||||
|
One-shot command to run in sequence when entering a runlevel, with
|
||||||
|
optional arguments and description.
|
||||||
|
|
||||||
|
`run` commands are guaranteed to be completed before running the next
|
||||||
|
command. Highly useful if true serialization is needed.
|
||||||
|
|
||||||
|
* `task [LVLS] <COND> /path/to/cmd ARGS -- Optional description`
|
||||||
|
One-shot like 'run', but starts in parallel with the next command.
|
||||||
|
|
||||||
|
Both `run` and `task` commands are run in a shell, so pipes and
|
||||||
|
redirects can be freely used:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
task [s] echo "foo" | cat >/tmp/bar
|
||||||
|
```
|
||||||
|
|
||||||
|
* `sysv [LVLS] <COND> /path/to/init-script -- Optional description`__
|
||||||
|
Similar to `task` is the `sysv` stanza, which can be used to call SysV
|
||||||
|
style scripts. The primary intention for this command is to be able to
|
||||||
|
re-use much of existing setup and init scripts in Linux distributions.
|
||||||
|
|
||||||
|
When entering an allowed runlevel, Finit calls `init-script start`,
|
||||||
|
when entering a disallowed runlevel, Finit calls `init-script stop`,
|
||||||
|
and if the Finit .conf, where `sysv` stanza is declared, is modified,
|
||||||
|
Finit calls `init-script restart` on `initctl reload`. Similar to
|
||||||
|
how `service` stanzas work.
|
||||||
|
|
||||||
|
Forking services started with `sysv` scripts can be monitored by Finit
|
||||||
|
by declaring the PID file to look for: `pid:!/path/to/pidfile.pid`.
|
||||||
|
|
||||||
|
* `service [LVLS] <COND> /path/to/daemon ARGS -- Optional description`
|
||||||
|
Service, or daemon, to be monitored and automatically restarted if it
|
||||||
|
exits prematurely.
|
||||||
|
|
||||||
|
For daemons that support it, we recommend appending `--foreground`, or
|
||||||
|
`--no-background`, argument to prevent them from forking off a
|
||||||
|
sub-process in the background. This is the most reliable way to
|
||||||
|
monitor a service.
|
||||||
|
|
||||||
|
However, not all daemons support running in the foreground, or they
|
||||||
|
may start logging to the foreground as well, these are called forking
|
||||||
|
services and are supported using the same syntax as forking `sysv`
|
||||||
|
services, using the `pid:!/path/to/pidfile.pid` syntax.
|
||||||
|
|
||||||
|
In the case of `ospfd` (below), we omit the `-d` flag to prevent it
|
||||||
|
from forking (daemonizing):
|
||||||
|
|
||||||
|
```shell
|
||||||
|
service [2345] <svc/sbin/zebra> /sbin/ospfd -- OSPF daemon
|
||||||
|
```
|
||||||
|
|
||||||
|
The `[2345]` is the runlevels `ospfd` is allowed to run in, they are
|
||||||
|
optional and default to level 2-5 if left out.
|
||||||
|
|
||||||
|
The `<...>` is the condition for starting `ospfd`. In this example
|
||||||
|
Finit waits for another service, `/sbin/zebra`, to have created its
|
||||||
|
PID file in `/var/run/zebra.pid` before starting `ospfd`.
|
||||||
|
|
||||||
|
Some services do not maintain a PID file and rather than patching each
|
||||||
|
application Finit provides a workaround. A `pid` keyword can be set
|
||||||
|
to have Finit automatically create (when starting) and later remove
|
||||||
|
(when stopping) the PID file. The file is created in the `/var/run`
|
||||||
|
directory using the `basename(1)` of the service. The default can be
|
||||||
|
modified with an optional argument:
|
||||||
|
|
||||||
|
pid[:[/path/to/]filename[.pid]]
|
||||||
|
|
||||||
|
For example, by adding `pid:/run/foo.pid` to the service `/sbin/bar`
|
||||||
|
that PID file will, not only be created and removed automatically, but
|
||||||
|
also be used by the Finit condition subsystem. So a service/run/task
|
||||||
|
can depend on `<svc/sbin/foo>`, notice the composition of conditions.
|
||||||
|
|
||||||
|
However, if a service `bar` *does* create a PID file, using `foo.pid`,
|
||||||
|
we can inform Finit of this by prepending an `!`:
|
||||||
|
|
||||||
|
pid:!/run/foo.pid
|
||||||
|
|
||||||
|
Here Finit will *not* create/remove/touch the PID file, only use it
|
||||||
|
for the condition handling instead of the default PID file name.
|
||||||
|
|
||||||
|
> For a detailed description of conditions, and how to debug them, see
|
||||||
|
> the [Finit Conditions](conditions.md) document.
|
||||||
|
|
||||||
|
If a service should not be automatically started, it can be configured
|
||||||
|
as manual with the optional `manual` argument. The service can then be
|
||||||
|
started at any time by running `initctl start <service>`.
|
||||||
|
|
||||||
|
manual:yes
|
||||||
|
|
||||||
|
The name of a service, shown by the `initctl` tool, defaults to the
|
||||||
|
basename of the service executable. It can be changed with the
|
||||||
|
optional `name` argument:
|
||||||
|
|
||||||
|
name:<service-name>
|
||||||
|
|
||||||
|
When stopping a service (run/task/sysv/service), either manually or
|
||||||
|
when moving to another runlevel, Finit starts by sending `SIGTERM`, to
|
||||||
|
allow the process to shut down gracefully. If the process has not
|
||||||
|
been collected within 3 seconds, Finit sends `SIGKILL`. To halt the
|
||||||
|
process using a different signal, use the option `halt:SIGNAL`, e.g.,
|
||||||
|
`halt:SIGPWR`. To change the delay between your halt signal and KILL,
|
||||||
|
use the option `kill:SEC`, e.g., `kill:10` to wait 10 seconds before
|
||||||
|
sending `SIGKILL`.
|
||||||
|
|
||||||
|
* `inetd service/proto[@iflist] <wait|nowait> [LVLS] /path/to/daemon args`
|
||||||
|
Launch a daemon when a client initiates a connection on an Internet
|
||||||
|
port. Available services are listed in the UNIX `/etc/services` file.
|
||||||
|
Finit can filter access to from a list of interfaces, `@iflist`, per
|
||||||
|
inetd service as well as listen to custom ports.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
inetd ftp/tcp nowait @root /usr/sbin/uftpd -i -f
|
||||||
|
inetd tftp/udp wait @root /usr/sbin/uftpd -i -t
|
||||||
|
```
|
||||||
|
|
||||||
|
The following example listens to port 2323 for telnet connections and
|
||||||
|
only allows clients connecting from `eth0`:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
inetd 2323/tcp@eth0 nowait [2345] /sbin/telnetd -i -F
|
||||||
|
```
|
||||||
|
|
||||||
|
The interface list, `@iflist`, is of the format `@iface,!iface,iface`,
|
||||||
|
where a single `!` means to deny access. Notice how interfaces are
|
||||||
|
comma separated with no spaces.
|
||||||
|
|
||||||
|
The `inetd` directive can also have ` -- Optional Description`, only
|
||||||
|
Finit does not output this text on the console when launching inetd
|
||||||
|
services. Instead this text is sent to syslog and also shown by the
|
||||||
|
`initctl` tool. More on inetd below.
|
||||||
|
|
||||||
|
* `runparts <DIR>`
|
||||||
|
Call [run-parts(8)][] on `DIR` to run start scripts. All executable
|
||||||
|
files, or scripts, in the directory are called, in alphabetic order.
|
||||||
|
The scripts in this directory are executed at the very end of runlevel
|
||||||
|
`S`, bootstrap.
|
||||||
|
|
||||||
|
It can be beneficial to use `S01name`, `S02othername`, etc. if there
|
||||||
|
is a dependency order between the scripts. Symlinks to existing
|
||||||
|
daemons can talso be used, but make sure they daemonize by default.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
* `include <CONF>`
|
||||||
|
Include another configuration file. Absolute path required.
|
||||||
|
|
||||||
|
* `log size:200k count:5`
|
||||||
|
|
||||||
|
Log rotation for run/task/services using the `log` sub-option with
|
||||||
|
redirection to a log file. Global setting, applies to all services.
|
||||||
|
|
||||||
|
The size can be given as bytes, without a specifier, or in `k`, `M`,
|
||||||
|
or `G`, e.g. `size:10M`, or `size:3G`. A value of `size:0` disables
|
||||||
|
log rotation. The default is `200k`.
|
||||||
|
|
||||||
|
The count value is recommended to be between 1-5, with a default 5.
|
||||||
|
Setting count to 0 means the logfile will be truncated when the MAX
|
||||||
|
size limit is reached.
|
||||||
|
|
||||||
|
* `tty [LVLS] <DEV> [BAUD] [noclear] [nowait] [nologin] [TERM]`
|
||||||
|
`tty [LVLS] <CMD> <ARGS> [noclear] [nowait]`
|
||||||
|
The first variant of this option uses the built-in getty on the given
|
||||||
|
TTY device DEV, in the given runlevels. The DEV may be the special
|
||||||
|
keyword `@console`, which is very useful on embedded systems. Default
|
||||||
|
baud rate is `38400`.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```conf
|
||||||
|
tty [12345] /dev/ttyAMA0 115200 noclear vt220
|
||||||
|
```
|
||||||
|
|
||||||
|
The second `tty` syntax variant is for using an external getty, like
|
||||||
|
agetty or the BusyBox getty.
|
||||||
|
|
||||||
|
By default both variants *clear* the TTY and *wait* for the user to
|
||||||
|
press enter before starting getty.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```conf
|
||||||
|
tty [12345] /sbin/getty -L 115200 /dev/ttyAMA0 vt100
|
||||||
|
tty [12345] /sbin/agetty -L ttyAMA0 115200 vt100 nowait
|
||||||
|
```
|
||||||
|
|
||||||
|
The `noclear` option disables clearing the TTY after each session.
|
||||||
|
Clearing the TTY when a user logs out is usually preferable.
|
||||||
|
|
||||||
|
The `nowait` option disables the `press Enter to activate console`
|
||||||
|
message before actually starting the getty program. On small and
|
||||||
|
embedded systems running multiple unused getty wastes both memory
|
||||||
|
and CPU cycles, so `wait` is the preferred default.
|
||||||
|
|
||||||
|
The `nologin` option disables getty and `/bin/login`, and gives the
|
||||||
|
user a root (login) shell on the given TTY `<DEV>` immediately.
|
||||||
|
Needless to say, this is a rather insecure option, but can be very
|
||||||
|
useful for developer builds, during board bringup, or similar.
|
||||||
|
|
||||||
|
Notice the ordering, the `TERM` option to the built-in getty must be
|
||||||
|
the last argument.
|
||||||
|
|
||||||
|
Embedded systems may want to enable automatic `DEV` by supplying the
|
||||||
|
special `@console` device. This works regardless weather the system
|
||||||
|
uses `ttyS0`, `ttyAMA0`, `ttyMXC0`, or anything else. Finit figures
|
||||||
|
it out by querying sysfs: `/sys/class/tty/console/active`.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```conf
|
||||||
|
tty [12345] @console 115200 noclear vt220
|
||||||
|
```
|
||||||
|
|
||||||
|
On really bare bones systems Finit offers a fallback shell, which
|
||||||
|
should not be enabled on production systems since. This because it
|
||||||
|
may give a user root access without having to log in. However, for
|
||||||
|
bringup and system debugging it can come in handy:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
configure --enable-fallback-shell
|
||||||
|
```
|
||||||
|
|
||||||
|
One can also use the `service` stanza to start a stand-alone shell:
|
||||||
|
|
||||||
|
```conf
|
||||||
|
service [12345] /bin/sh -l
|
||||||
|
```
|
||||||
|
|
||||||
|
When running <kbd>make install</kbd> no default `/etc/finit.conf` will
|
||||||
|
be installed since system requirements differ too much. Try out the
|
||||||
|
Debian 6.0 example `/usr/share/doc/finit/finit.conf` configuration that
|
||||||
|
is capable of service monitoring SSH, sysklogd, gdm and getty!
|
||||||
|
|
||||||
|
Every `run`, `task`, `service`, or `inetd` can also list the privileges
|
||||||
|
the `/path/to/cmd` should be executed with. Simply prefix the path with
|
||||||
|
`[@USR[:GRP]]` like this:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
run [2345] @joe:users /usr/bin/logger "Hello world"
|
||||||
|
```
|
||||||
|
|
||||||
|
For multiple instances of the same command, e.g. a DHCP client or
|
||||||
|
multiple web servers, add `:ID` somewhere between the `run`, `task`,
|
||||||
|
`service` keyword and the command, like this:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
service :1 [2345] /sbin/httpd -f -h /http -p 80 -- Web server
|
||||||
|
service :2 [2345] /sbin/httpd -f -h /http -p 8080 -- Old web server
|
||||||
|
```
|
||||||
|
|
||||||
|
Without the `:ID` to the service the latter will overwrite the former
|
||||||
|
and only the old web server would be started and supervised.
|
||||||
|
|
||||||
|
The `run`, `task`, `service`, or `inetd` stanzas also allow the keyword
|
||||||
|
`log` to redirect `stderr` and `stdout` of the application to a file or
|
||||||
|
syslog using the native `logit` tool. The full syntax is:
|
||||||
|
|
||||||
|
log:/path/to/file
|
||||||
|
log:prio:facility.level,tag:ident
|
||||||
|
log:console
|
||||||
|
log:null
|
||||||
|
log
|
||||||
|
|
||||||
|
Default `prio` is `daemon.info` and default `tag` is the basename of the
|
||||||
|
service or run/task command.
|
||||||
|
|
||||||
|
Log rotation is controlled using the global `log` setting.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
|
||||||
|
|
||||||
|
Worth noting is that conditions is allowed for all these stanzas. For a
|
||||||
|
detailed description, see the [Conditions](conditions.md) document.
|
||||||
|
|
||||||
|
|
||||||
|
Limitations
|
||||||
|
-----------
|
||||||
|
|
||||||
|
To understand the limitations of `finit.conf` vs `finit.d` it is useful
|
||||||
|
to picture the different phases of the system: bootstrap, runtime, and
|
||||||
|
shutdown.
|
||||||
|
|
||||||
|
### /etc/finit.conf
|
||||||
|
|
||||||
|
This file used to be the only way to set up and boot a Finit system.
|
||||||
|
Today it is mainly used for pre-runtime settings like system hostname,
|
||||||
|
network bringup and shutdown:
|
||||||
|
|
||||||
|
- `host`, only at bootstrap, (runlevel `S`)
|
||||||
|
- `mknod`, only at bootstrap
|
||||||
|
- `network`, only at bootstrap
|
||||||
|
- `runparts`, only at bootstrap
|
||||||
|
- `include`
|
||||||
|
- `log`, global setting
|
||||||
|
- `shutdown`
|
||||||
|
- `runlevel`, only at bootstrap
|
||||||
|
- ... and all configuration stanzas from `/etc/finit.d` below
|
||||||
|
|
||||||
|
### /etc/finit.d
|
||||||
|
|
||||||
|
Support for per-service `.conf` files in `/etc/finit.d` was added in
|
||||||
|
v3.0 to handle changes of the system configuration at runtime. As of
|
||||||
|
v3.1 `finit.conf` is also handled at runtime, except of course for any
|
||||||
|
stanza that only runs at bootstrap. However, a `/etc/finit.d/*.conf`
|
||||||
|
does *not support* the above `finit.conf` settings described above, only
|
||||||
|
the following:
|
||||||
|
|
||||||
|
- `module`, but only at bootstrap
|
||||||
|
- `service`
|
||||||
|
- `task`
|
||||||
|
- `run`
|
||||||
|
- `inetd`
|
||||||
|
- `rlimit`
|
||||||
|
- `tty`
|
||||||
|
|
||||||
|
**NOTE:** The `/etc/finit.d` directory was previously the default Finit
|
||||||
|
`runparts` directory. Finit no longer has a default `runparts`, make
|
||||||
|
sure to update your setup, or the finit configuration, accordingly.
|
||||||
|
|
||||||
|
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
||||||
File renamed without changes.
File renamed without changes.
@@ -42,13 +42,11 @@ For your convenience a set of *optional* plugins are available:
|
|||||||
|
|
||||||
* *discard.so*: RFC 863 plugin. Start as inetd service, like time below.
|
* *discard.so*: RFC 863 plugin. Start as inetd service, like time below.
|
||||||
|
|
||||||
* *hwclock.so*: Restore and save system clock from/to RTC on
|
* *rtc.so*: Restore and save system clock from/to RTC on boot/halt.
|
||||||
startup/shutdown.
|
|
||||||
|
|
||||||
* *initctl.so*: Extends finit with a traditional `initctl` functionality.
|
* *initctl.so*: Extends finit with a traditional `initctl` functionality.
|
||||||
|
|
||||||
* *lost.so*: Very simple `HOOK_SVC_LOST` example. Logs process ID and
|
* *modules-load.so*: Scans /etc/modules-load.d for modules to modprobe.
|
||||||
name to syslog. _Optional plugin._
|
|
||||||
|
|
||||||
* *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
|
||||||
@@ -102,19 +100,6 @@ Hooks
|
|||||||
all modified/removed services have been stopped. When the hook has
|
all modified/removed services have been stopped. When the hook has
|
||||||
completed, Finit continues to start all modified and new services.
|
completed, Finit continues to start all modified and new services.
|
||||||
|
|
||||||
* `HOOK_SVC_LOST`: Called when a process is lost. When reconfiguring
|
|
||||||
services at runtime this hook may be called a lot. However, it may be
|
|
||||||
a quite useful hook to monitor a system post bootstrap when no, or
|
|
||||||
few, services are expected to exit. A default plugin `lost.so` is
|
|
||||||
available in the `plugins/` subdirectory as an example.
|
|
||||||
|
|
||||||
**NOTE:** This hook callback gets the lost PID as argument.
|
|
||||||
|
|
||||||
* `HOOK_SVC_START`: Like `HOOK_SVC_LOST`, but called when a process is
|
|
||||||
started. Same caveats apply.
|
|
||||||
|
|
||||||
**NOTE:** This hook callback gets the new PID as argument.
|
|
||||||
|
|
||||||
* `HOOK_RUNLEVEL_CHANGE`: Called when the user has issued a runlevel
|
* `HOOK_RUNLEVEL_CHANGE`: Called when the user has issued a runlevel
|
||||||
change. The hook is called when services not matching the new
|
change. The hook is called when services not matching the new
|
||||||
runlevel have been been stopped. When the hook has completed, Finit
|
runlevel have been been stopped. When the hook has completed, Finit
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+7
-6
@@ -1,3 +1,4 @@
|
|||||||
|
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 -U_FORTIFY_SOURCE
|
||||||
@@ -6,7 +7,7 @@ AM_CPPFLAGS += $(lite_CFLAGS)
|
|||||||
|
|
||||||
if STATIC
|
if STATIC
|
||||||
noinst_LTLIBRARIES = libplug.la
|
noinst_LTLIBRARIES = libplug.la
|
||||||
libplug_la_SOURCES = bootmisc.c hwclock.c initctl.c pidfile.c procps.c tty.c urandom.c
|
libplug_la_SOURCES = bootmisc.c modprobe.c rtc.c initctl.c pidfile.c procps.c tty.c urandom.c
|
||||||
|
|
||||||
if BUILD_ALSA_UTILS_PLUGIN
|
if BUILD_ALSA_UTILS_PLUGIN
|
||||||
libplug_la_SOURCES += alsa-utils.c
|
libplug_la_SOURCES += alsa-utils.c
|
||||||
@@ -38,8 +39,8 @@ libplug_la_SOURCES += time.c
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if BUILD_LOST_PLUGIN
|
if BUILD_MODULES_LOAD_PLUGIN
|
||||||
libplug_la_SOURCES += lost.c
|
libplug_la_SOURCES += modules-load.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if BUILD_NETLINK_PLUGIN
|
if BUILD_NETLINK_PLUGIN
|
||||||
@@ -51,7 +52,7 @@ libplug_la_SOURCES += resolvconf.c
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
else
|
else
|
||||||
pkglib_LTLIBRARIES = bootmisc.la hwclock.la initctl.la pidfile.la procps.la tty.la urandom.la
|
pkglib_LTLIBRARIES = bootmisc.la modprobe.la rtc.la initctl.la pidfile.la procps.la tty.la urandom.la
|
||||||
|
|
||||||
if BUILD_ALSA_UTILS_PLUGIN
|
if BUILD_ALSA_UTILS_PLUGIN
|
||||||
pkglib_LTLIBRARIES += alsa-utils.la
|
pkglib_LTLIBRARIES += alsa-utils.la
|
||||||
@@ -83,8 +84,8 @@ pkglib_LTLIBRARIES += time.la
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if BUILD_LOST_PLUGIN
|
if BUILD_MODULES_LOAD_PLUGIN
|
||||||
pkglib_LTLIBRARIES += lost.la
|
pkglib_LTLIBRARIES += modules-load.la
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if BUILD_NETLINK_PLUGIN
|
if BUILD_NETLINK_PLUGIN
|
||||||
|
|||||||
@@ -170,6 +170,9 @@ static void setup(void *arg)
|
|||||||
makefifo("/dev/xconsole", 0640); /* sysklogd */
|
makefifo("/dev/xconsole", 0640); /* sysklogd */
|
||||||
chown("/dev/xconsole", 0, gid);
|
chown("/dev/xconsole", 0, gid);
|
||||||
|
|
||||||
|
if (!fexist("/etc/mtab"))
|
||||||
|
symlink("../proc/self/mounts", "/etc/mtab");
|
||||||
|
|
||||||
/* Void Linux has a uuidd that runs as uuid:uuid and needs /run/uuid */
|
/* Void Linux has a uuidd that runs as uuid:uuid and needs /run/uuid */
|
||||||
uid = getuser("uuidd", NULL);
|
uid = getuser("uuidd", NULL);
|
||||||
if (uid >= 0) {
|
if (uid >= 0) {
|
||||||
|
|||||||
+2
-2
@@ -38,7 +38,7 @@
|
|||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
{
|
{
|
||||||
char *cmd;
|
char *cmd;
|
||||||
char line[80];
|
char line[256];
|
||||||
|
|
||||||
cmd = which(DAEMON);
|
cmd = which(DAEMON);
|
||||||
if (!cmd) {
|
if (!cmd) {
|
||||||
@@ -58,7 +58,7 @@ static void setup(void *arg)
|
|||||||
erase("/var/run/dbus/pid");
|
erase("/var/run/dbus/pid");
|
||||||
|
|
||||||
/* Register service with Finit */
|
/* Register service with Finit */
|
||||||
snprintf(line, sizeof(line), "[S12345] %s %s -- %s", cmd, ARGS, DESC);
|
snprintf(line, sizeof(line), "[S12345] pid:!/run/dbus/pid log:prio:daemon.info,tag:dbus %s %s -- %s", cmd, ARGS, DESC);
|
||||||
if (service_register(SVC_TYPE_SERVICE, line, global_rlimit, NULL))
|
if (service_register(SVC_TYPE_SERVICE, line, global_rlimit, NULL))
|
||||||
_pe("Failed registering %s", DAEMON);
|
_pe("Failed registering %s", DAEMON);
|
||||||
free(cmd);
|
free(cmd);
|
||||||
|
|||||||
@@ -0,0 +1,176 @@
|
|||||||
|
/* Coldplug modules using modalias magic
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Joachim Nilsson <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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cold plug magic taken from Buildroot
|
||||||
|
* https://github.com/buildroot/buildroot/commit/b4fc5a180c81689a982d5c595844331684c14f51
|
||||||
|
*
|
||||||
|
* The plugin basically does this, only in C:
|
||||||
|
*
|
||||||
|
* system("find /sys/devices -name modalias -print0"
|
||||||
|
* " | xargs -0 sort -u -z"
|
||||||
|
* " | xargs -0 modprobe -abq");
|
||||||
|
*
|
||||||
|
* Note: BusyBox must *not* be built with CONFIG_MODPROBE_SMALL
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fnmatch.h>
|
||||||
|
#include <ftw.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/time.h> /* gettimeofday() */
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <lite/lite.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "finit.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
#include "plugin.h"
|
||||||
|
|
||||||
|
struct module {
|
||||||
|
TAILQ_ENTRY(module) link;
|
||||||
|
char *alias;
|
||||||
|
};
|
||||||
|
|
||||||
|
static TAILQ_HEAD(, module) modules = TAILQ_HEAD_INITIALIZER(modules);
|
||||||
|
|
||||||
|
static int modprobe(char *alias)
|
||||||
|
{
|
||||||
|
char *args[] = {
|
||||||
|
"modprobe",
|
||||||
|
"-abq",
|
||||||
|
alias,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
pid = fork();
|
||||||
|
switch (pid) {
|
||||||
|
case -1:
|
||||||
|
_pe("Failed forking modprobe child");
|
||||||
|
return 1;
|
||||||
|
case 0:
|
||||||
|
execvp(args[0], args);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (!complete(args[0], pid))
|
||||||
|
_d("Successful modprobe of %s", alias);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void alias_add(char *alias)
|
||||||
|
{
|
||||||
|
struct module *m;
|
||||||
|
|
||||||
|
m = malloc(sizeof(*m));
|
||||||
|
if (!m)
|
||||||
|
return;
|
||||||
|
m->alias = strdup(alias);
|
||||||
|
if (!m->alias) {
|
||||||
|
free(m);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TAILQ_INSERT_TAIL(&modules, m, link);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void alias_remove(struct module *m)
|
||||||
|
{
|
||||||
|
TAILQ_REMOVE(&modules, m, link);
|
||||||
|
free(m->alias);
|
||||||
|
free(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int alias_exist(char *alias)
|
||||||
|
{
|
||||||
|
struct module *m;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(m, &modules, link) {
|
||||||
|
if (!strcmp(m->alias, alias))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int scan_alias(const char *path, const struct stat *st, int flag, struct FTW *unused)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
char buf[256];
|
||||||
|
|
||||||
|
if (fnmatch("*/modalias", path, 0))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fp = fopen(path, "r");
|
||||||
|
if (!fp)
|
||||||
|
return 0;
|
||||||
|
if (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
chomp(buf);
|
||||||
|
if (!alias_exist(buf))
|
||||||
|
alias_add(buf);
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void coldplug(void *arg)
|
||||||
|
{
|
||||||
|
struct module *m, *tmp;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
print_desc("Cold plugging system", NULL);
|
||||||
|
nftw("/sys/devices", scan_alias, 200, FTW_DEPTH);
|
||||||
|
TAILQ_FOREACH_SAFE(m, &modules, link, tmp) {
|
||||||
|
rc += modprobe(m->alias);
|
||||||
|
alias_remove(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
print_result(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static plugin_t plugin = {
|
||||||
|
.name = __FILE__,
|
||||||
|
.hook[HOOK_BASEFS_UP] = { .cb = coldplug },
|
||||||
|
.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:
|
||||||
|
*/
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
/* Scans /etc/modules-load.d for modules to load.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Robert Andersson <robert.m.andersson@se.atlascopco.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 <lite/lite.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
|
#include "finit.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
#include "plugin.h"
|
||||||
|
#include "service.h"
|
||||||
|
#include "conf.h"
|
||||||
|
|
||||||
|
#define MODULES_LOAD_PATH "/etc/modules-load.d"
|
||||||
|
#define SERVICE_LINE \
|
||||||
|
":%d name:modprobe.%s [2345] /sbin/modprobe %s %s -- Kernel module: %s"
|
||||||
|
|
||||||
|
static void load(void *arg)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
DIR *dirp;
|
||||||
|
struct dirent *direntp;
|
||||||
|
char line[256];
|
||||||
|
int index = 1;
|
||||||
|
|
||||||
|
_d("Scanning " MODULES_LOAD_PATH " for config files ...");
|
||||||
|
|
||||||
|
dirp = opendir(MODULES_LOAD_PATH);
|
||||||
|
if (!dirp) return;
|
||||||
|
|
||||||
|
while ((direntp = readdir(dirp)))
|
||||||
|
{
|
||||||
|
char module_path[PATH_MAX];
|
||||||
|
strlcpy(module_path, MODULES_LOAD_PATH "/", sizeof(module_path));
|
||||||
|
strlcat(module_path, direntp->d_name, sizeof(module_path));
|
||||||
|
|
||||||
|
fp = fopen(module_path, "r");
|
||||||
|
if (!fp) continue;
|
||||||
|
|
||||||
|
while (fgets(line, sizeof(line), fp)) {
|
||||||
|
char cmd[CMD_SIZE], *mod, *args;
|
||||||
|
|
||||||
|
mod = strip_line(line);
|
||||||
|
if (!*mod) continue;
|
||||||
|
|
||||||
|
mod = chomp(mod);
|
||||||
|
if (!mod || !*mod) continue;
|
||||||
|
|
||||||
|
mod = strtok_r(mod, " ", &args);
|
||||||
|
|
||||||
|
snprintf(cmd, sizeof(cmd), SERVICE_LINE,
|
||||||
|
index, mod, mod, args, mod);
|
||||||
|
service_register(SVC_TYPE_TASK, cmd, global_rlimit, NULL);
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dirp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static plugin_t plugin = {
|
||||||
|
.name = __FILE__,
|
||||||
|
.hook[HOOK_BASEFS_UP] = {
|
||||||
|
.cb = load
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
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:
|
||||||
|
*/
|
||||||
+20
-23
@@ -94,6 +94,17 @@ static void nl_route(struct nlmsghdr *nlmsg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void net_cond_set(char *ifname, char *cond, int set)
|
||||||
|
{
|
||||||
|
char msg[MAX_ARG_LEN];
|
||||||
|
|
||||||
|
snprintf(msg, sizeof(msg), "net/%s/%s", ifname, cond);
|
||||||
|
if (set)
|
||||||
|
cond_set(msg);
|
||||||
|
else
|
||||||
|
cond_clear(msg);
|
||||||
|
}
|
||||||
|
|
||||||
static void nl_link(struct nlmsghdr *nlmsg)
|
static void nl_link(struct nlmsghdr *nlmsg)
|
||||||
{
|
{
|
||||||
int la;
|
int la;
|
||||||
@@ -112,39 +123,25 @@ static void nl_link(struct nlmsghdr *nlmsg)
|
|||||||
|
|
||||||
while (RTA_OK(a, la)) {
|
while (RTA_OK(a, la)) {
|
||||||
if (a->rta_type == IFLA_IFNAME) {
|
if (a->rta_type == IFLA_IFNAME) {
|
||||||
char msg[MAX_ARG_LEN];
|
|
||||||
|
|
||||||
strlcpy(ifname, RTA_DATA(a), sizeof(ifname));
|
strlcpy(ifname, RTA_DATA(a), sizeof(ifname));
|
||||||
switch (nlmsg->nlmsg_type) {
|
switch (nlmsg->nlmsg_type) {
|
||||||
case RTM_NEWLINK:
|
case RTM_NEWLINK:
|
||||||
/*
|
/*
|
||||||
* New interface has appearad, 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, ifi_change 0x%x", ifname, i->ifi_change);
|
_d("%s: New link, flags 0x%x, change 0x%x", ifname, i->ifi_flags, i->ifi_change);
|
||||||
if (i->ifi_change & IFF_UP) {
|
net_cond_set(ifname, "exist", 1);
|
||||||
snprintf(msg, sizeof(msg), "net/%s/up", ifname);
|
net_cond_set(ifname, "up", i->ifi_flags & IFF_UP);
|
||||||
|
net_cond_set(ifname, "running", i->ifi_flags & IFF_RUNNING);
|
||||||
if (i->ifi_flags & IFF_UP)
|
|
||||||
cond_set(msg);
|
|
||||||
else
|
|
||||||
cond_clear(msg);
|
|
||||||
|
|
||||||
if (string_compare("lo", ifname)) {
|
|
||||||
snprintf(msg, sizeof(msg), "net/%s/exist", ifname);
|
|
||||||
cond_set(msg);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
snprintf(msg, sizeof(msg), "net/%s/exist", ifname);
|
|
||||||
cond_set(msg);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTM_DELLINK:
|
case RTM_DELLINK:
|
||||||
/* NOTE: Interface has dissapeared, not link down ... */
|
/* NOTE: Interface has disappeared, not link down ... */
|
||||||
_d("%s: Delete link", ifname);
|
_d("%s: Delete link", ifname);
|
||||||
snprintf(msg, sizeof(msg), "net/%s/exist", ifname);
|
net_cond_set(ifname, "exist", 0);
|
||||||
cond_clear(msg);
|
net_cond_set(ifname, "up", 0);
|
||||||
|
net_cond_set(ifname, "running", 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTM_NEWADDR:
|
case RTM_NEWADDR:
|
||||||
|
|||||||
+247
-66
@@ -1,6 +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-2020 Joachim Nilsson <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,115 +22,289 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <glob.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
|
#include <lite/queue.h>
|
||||||
#include <sys/inotify.h>
|
#include <sys/inotify.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
#include "pid.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
|
|
||||||
struct context {
|
struct wd_entry {
|
||||||
|
TAILQ_ENTRY(wd_entry) link;
|
||||||
|
char *path;
|
||||||
int fd;
|
int fd;
|
||||||
int wd;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static char *mkcond(char *buf, size_t len, char *nm)
|
struct context {
|
||||||
|
int fd;
|
||||||
|
TAILQ_HEAD(, wd_entry) wd_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct context pidfile_ctx;
|
||||||
|
|
||||||
|
static int watcher_add(struct context *ctx, char *path)
|
||||||
{
|
{
|
||||||
snprintf(buf, len, "svc%s%s", nm[0] != '/' ? "/" : "", nm);
|
struct wd_entry *wd;
|
||||||
return buf;
|
uint32_t mask = IN_ONLYDIR | IN_CREATE | IN_ATTRIB | IN_DELETE | IN_MODIFY | IN_MOVED_TO;
|
||||||
|
char *ptr;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
_d("pidfile: Adding new watcher for path %s", path);
|
||||||
|
ptr = strstr(path, "run/");
|
||||||
|
if (ptr) {
|
||||||
|
char *slash;
|
||||||
|
|
||||||
|
ptr += 4;
|
||||||
|
slash = strchr(ptr, '/');
|
||||||
|
if (slash) {
|
||||||
|
ptr = slash++;
|
||||||
|
slash = strchr(ptr, '/');
|
||||||
|
if (slash) {
|
||||||
|
_d("pidfile: Path too deep, skipping.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = inotify_add_watch(ctx->fd, path, mask);
|
||||||
|
if (fd < 0) {
|
||||||
|
_pe("inotify_add_watch()");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
wd = malloc(sizeof(struct wd_entry));
|
||||||
|
if (!wd) {
|
||||||
|
_pe("Failed allocating new `struct wd_entry`");
|
||||||
|
inotify_rm_watch(ctx->fd, fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
wd->path = path;
|
||||||
|
wd->fd = fd;
|
||||||
|
TAILQ_INSERT_HEAD(&ctx->wd_list, wd, link);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int watcher_del(struct context *ctx, struct wd_entry *wde)
|
||||||
|
{
|
||||||
|
_d("pidfile: Removing watcher for removed path %s", wde->path);
|
||||||
|
TAILQ_REMOVE(&ctx->wd_list, wde, link);
|
||||||
|
inotify_rm_watch(ctx->fd, wde->fd);
|
||||||
|
free(wde->path);
|
||||||
|
free(wde);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_conds(char *name, uint32_t mask)
|
||||||
|
{
|
||||||
|
svc_t *svc;
|
||||||
|
char cond[MAX_COND_LEN];
|
||||||
|
|
||||||
|
_d("name: %s", name);
|
||||||
|
svc = svc_find_by_pidfile(name);
|
||||||
|
if (!svc) {
|
||||||
|
_d("pidfile: No matching svc for %s", name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_d("Event %s for svc %s", name, svc->cmd);
|
||||||
|
|
||||||
|
mkcond(svc, cond, sizeof(cond));
|
||||||
|
if (mask & (IN_CREATE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) {
|
||||||
|
svc_started(svc);
|
||||||
|
if (svc_is_forking(svc)) {
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
pid = pid_file_read(pid_file(svc));
|
||||||
|
_d("Forking service %s changed PID from %d to %d",
|
||||||
|
svc->cmd, svc->pid, pid);
|
||||||
|
svc->pid = pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
cond_set(cond);
|
||||||
|
} else if (mask & IN_DELETE)
|
||||||
|
cond_clear(cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* synthesize events in case of new run dirs */
|
||||||
|
static void scan_for_pidfiles(struct context *ctx, char *dir, int len)
|
||||||
|
{
|
||||||
|
glob_t gl;
|
||||||
|
size_t i;
|
||||||
|
char path[len + 6];
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "%s/*.pid", dir);
|
||||||
|
rc = glob(path, GLOB_NOSORT, NULL, &gl);
|
||||||
|
if (rc && rc != GLOB_NOMATCH)
|
||||||
|
return;
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "%s/pid", dir);
|
||||||
|
rc = glob(path, GLOB_NOSORT | GLOB_APPEND, NULL, &gl);
|
||||||
|
if (rc && rc != GLOB_NOMATCH)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < gl.gl_pathc; i++) {
|
||||||
|
_d("scan found %s", gl.gl_pathv[i]);
|
||||||
|
update_conds(gl.gl_pathv[i], IN_CREATE);
|
||||||
|
}
|
||||||
|
globfree(&gl);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_dir(struct context *ctx, struct wd_entry *wde, char *name, int mask)
|
||||||
|
{
|
||||||
|
char *path;
|
||||||
|
int plen;
|
||||||
|
int exist = 0;
|
||||||
|
|
||||||
|
plen = snprintf(NULL, 0, "%s/%s", wde->path, name) + 1;
|
||||||
|
path = malloc(plen);
|
||||||
|
if (!path) {
|
||||||
|
_pe("Failed allocating path buffer for watcher");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
snprintf(path, plen, "%s/%s", wde->path, name);
|
||||||
|
_d("pidfile: path is %s", path);
|
||||||
|
|
||||||
|
TAILQ_FOREACH(wde, &ctx->wd_list, link) {
|
||||||
|
if (!strcmp(wde->path, path)) {
|
||||||
|
exist = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mask & IN_CREATE) {
|
||||||
|
if (!exist) {
|
||||||
|
int rc = watcher_add(ctx, path);
|
||||||
|
|
||||||
|
scan_for_pidfiles(ctx, path, plen);
|
||||||
|
if (!rc)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (mask & IN_DELETE) {
|
||||||
|
if (exist)
|
||||||
|
watcher_del(&pidfile_ctx, wde);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pidfile_callback(void *arg, int fd, int events)
|
static void pidfile_callback(void *arg, int fd, int events)
|
||||||
{
|
{
|
||||||
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
|
||||||
static char cond[MAX_COND_LEN];
|
|
||||||
|
|
||||||
struct inotify_event *ev;
|
struct inotify_event *ev;
|
||||||
ssize_t sz, len;
|
ssize_t sz, off;
|
||||||
char *basename;
|
size_t buflen = 8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1;
|
||||||
svc_t *svc;
|
char *buf;
|
||||||
|
|
||||||
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
buf= malloc(buflen);
|
||||||
if (sz <= 0) {
|
if (!buf) {
|
||||||
_pe("invalid inotify event");
|
_pe("Failed allocating buffer for inotify events");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ev_buf[sz] = 0;
|
|
||||||
|
|
||||||
for (ev = (void *)ev_buf; sz > (ssize_t)sizeof(*ev);
|
_d("pidfile: Entering ... reading %zu bytes into ev_buf[]", buflen - 1);
|
||||||
len = sizeof(*ev) + ev->len, ev = (void *)ev + len, sz -= len) {
|
sz = read(fd, buf, buflen - 1);
|
||||||
/* ev = (void *)(ev + 1) + ev->len, sz -= sizeof(*ev) + ev->len) { */
|
if (sz <= 0) {
|
||||||
if (!ev->mask || !strstr(ev->name, ".pid"))
|
_pe("invalid inotify event");
|
||||||
continue;
|
goto done;
|
||||||
|
|
||||||
basename = strtok(ev->name, ".");
|
|
||||||
if (!basename)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
svc = svc_find_by_nameid(basename, 1);
|
|
||||||
if (!svc)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* TODO FIXME XXX WKZ check that pid is controlled by finit */
|
|
||||||
|
|
||||||
_d("%s: match %s", basename, svc->cmd);
|
|
||||||
mkcond(cond, sizeof(cond), svc->cmd);
|
|
||||||
if (ev->mask & (IN_CREATE | IN_ATTRIB | IN_MODIFY)) {
|
|
||||||
svc_started(svc);
|
|
||||||
cond_set(cond);
|
|
||||||
} else if (ev->mask & IN_DELETE)
|
|
||||||
cond_clear(cond);
|
|
||||||
}
|
}
|
||||||
|
buf[sz] = 0;
|
||||||
|
_d("pidfile: Read %zd bytes, processing ...", sz);
|
||||||
|
|
||||||
|
off = 0;
|
||||||
|
for (off = 0; off < sz; off += sizeof(*ev) + ev->len) {
|
||||||
|
struct wd_entry *wde;
|
||||||
|
|
||||||
|
ev = (struct inotify_event *)&buf[off];
|
||||||
|
|
||||||
|
_d("pidfile: path %s, event: 0x%08x", ev->name, ev->mask);
|
||||||
|
if (!ev->mask)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Find base path for this event */
|
||||||
|
TAILQ_FOREACH(wde, &pidfile_ctx.wd_list, link) {
|
||||||
|
if (wde->fd == ev->wd)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ev->mask & IN_ISDIR) {
|
||||||
|
handle_dir(&pidfile_ctx, wde, ev->name, ev->mask);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ev->mask & IN_DELETE) {
|
||||||
|
_d("pidfile %s/%s removed ...", wde->path, ev->name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ev->mask & (IN_CREATE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO))
|
||||||
|
update_conds(ev->name, ev->mask);
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Assert condition only if the service is running, but not if it's
|
* This function is called after `initctl reload` to reassert conditions
|
||||||
* recently been changed or while it's starting up.
|
* for services that have not been changed.
|
||||||
*
|
*
|
||||||
* We must wait for the service to create/touch its pidfile.
|
* We reassert the run/task/service's condition only if it is running,
|
||||||
|
* but not if it's recently been changed or while it's starting up.
|
||||||
*/
|
*/
|
||||||
static void pidfile_reconf(void *arg)
|
static void pidfile_reconf(void *arg)
|
||||||
{
|
{
|
||||||
static char cond[MAX_COND_LEN];
|
static char cond[MAX_COND_LEN];
|
||||||
svc_t *svc, *iter = NULL;
|
svc_t *svc, *iter = NULL;
|
||||||
int restart = 0;
|
|
||||||
|
|
||||||
do {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
restart = 0;
|
if (svc->state != SVC_RUNNING_STATE)
|
||||||
|
continue;
|
||||||
|
|
||||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
if (svc_is_changed(svc) || svc_is_starting(svc))
|
||||||
mkcond(cond, sizeof(cond), svc->cmd);
|
continue;
|
||||||
if (svc->state == SVC_RUNNING_STATE &&
|
|
||||||
!svc_is_changed(svc) &&
|
|
||||||
!svc_is_starting(svc) &&
|
|
||||||
cond_get(cond) != COND_ON) {
|
|
||||||
cond_set_path(cond_path(cond), COND_ON);
|
|
||||||
restart = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (restart)
|
mkcond(svc, cond, sizeof(cond));
|
||||||
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_RUNTASK | SVC_TYPE_INETD);
|
if (cond_get(cond) == COND_ON)
|
||||||
|
continue;
|
||||||
|
|
||||||
} while (restart);
|
cond_set_path(cond_path(cond), COND_ON);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This will call service_step(), which in turn will schedule itself
|
||||||
|
* as long as stepped services change state. Services going from
|
||||||
|
* WAITING to RUNNING will reassert their conditions in that loop,
|
||||||
|
* which in turn may unlock other services, and so on.
|
||||||
|
*/
|
||||||
|
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_RUNTASK | SVC_TYPE_INETD);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pidfile_init(void *arg)
|
static void pidfile_init(void *arg)
|
||||||
{
|
{
|
||||||
struct context *ctx = arg;
|
char *path;
|
||||||
|
|
||||||
ctx->wd = inotify_add_watch(ctx->fd, _PATH_VARRUN,
|
/*
|
||||||
IN_CREATE | IN_ATTRIB | IN_DELETE | IN_MODIFY);
|
* The bootmisc plugin is responsible for setting up /var/run.
|
||||||
if (ctx->wd < 0) {
|
* and/or /run, with proper symlinks etc. We depend on bootmisc
|
||||||
_pe("inotify_add_watch()");
|
* so it's safe here to query realpath() and set up inotify.
|
||||||
close(ctx->fd);
|
*/
|
||||||
|
path = realpath(_PATH_VARRUN, NULL);
|
||||||
|
if (!path) {
|
||||||
|
_pe("Failed ");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TAILQ_INIT(&pidfile_ctx.wd_list);
|
||||||
|
if (watcher_add(&pidfile_ctx, path))
|
||||||
|
close(pidfile_ctx.fd);
|
||||||
_d("pidfile monitor active");
|
_d("pidfile monitor active");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +316,7 @@ static struct context pidfile_ctx;
|
|||||||
*/
|
*/
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
.name = __FILE__,
|
.name = __FILE__,
|
||||||
.hook[HOOK_BASEFS_UP] = { .arg = &pidfile_ctx, .cb = pidfile_init },
|
.hook[HOOK_BASEFS_UP] = { .cb = pidfile_init },
|
||||||
.hook[HOOK_SVC_RECONF] = { .cb = pidfile_reconf },
|
.hook[HOOK_SVC_RECONF] = { .cb = pidfile_reconf },
|
||||||
.io = {
|
.io = {
|
||||||
.cb = pidfile_callback,
|
.cb = pidfile_callback,
|
||||||
@@ -164,7 +339,13 @@ PLUGIN_INIT(plugin_init)
|
|||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(plugin_exit)
|
||||||
{
|
{
|
||||||
inotify_rm_watch(pidfile_ctx.fd, pidfile_ctx.wd);
|
struct wd_entry *wde, *tmp;
|
||||||
|
|
||||||
|
TAILQ_FOREACH_SAFE(wde, &pidfile_ctx.wd_list, link, tmp) {
|
||||||
|
inotify_rm_watch(pidfile_ctx.fd, wde->fd);
|
||||||
|
free(wde->path);
|
||||||
|
free(wde);
|
||||||
|
}
|
||||||
close(pidfile_ctx.fd);
|
close(pidfile_ctx.fd);
|
||||||
|
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
|
|||||||
+160
@@ -0,0 +1,160 @@
|
|||||||
|
/* Save and restore RTC using hwclock
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012-2019 Joachim Nilsson <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 <time.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <linux/rtc.h>
|
||||||
|
#include <lite/lite.h>
|
||||||
|
|
||||||
|
#include "finit.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
#include "plugin.h"
|
||||||
|
|
||||||
|
/* Kernel RTC driver validates against this date for sanity check */
|
||||||
|
#define RTC_TIMESTAMP_BEGIN_2000 946684800LL /* 2000-01-01 00:00:00 */
|
||||||
|
|
||||||
|
static int rtc_open(void)
|
||||||
|
{
|
||||||
|
char *alt[] = {
|
||||||
|
"/dev/rtc",
|
||||||
|
"/dev/rtc0",
|
||||||
|
"/dev/misc/rtc"
|
||||||
|
};
|
||||||
|
size_t i;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
for (i = 0; i < NELEMS(alt); i++) {
|
||||||
|
fd = open(alt[i], O_RDONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rtc_save(void *arg)
|
||||||
|
{
|
||||||
|
struct timeval tv = { 0 };
|
||||||
|
struct tm tm = { 0 };
|
||||||
|
int fd, rc = 0;
|
||||||
|
|
||||||
|
fd = rtc_open();
|
||||||
|
if (fd < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
rc = gettimeofday(&tv, NULL);
|
||||||
|
if (rc < 0 || tv.tv_sec < RTC_TIMESTAMP_BEGIN_2000) {
|
||||||
|
print_desc(NULL, "System clock invalid, not saving to RTC");
|
||||||
|
invalid:
|
||||||
|
logit(LOG_ERR, "System clock invalid, before 2000-01-01 00:00, not saving to RTC");
|
||||||
|
rc = 2;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_desc(NULL, "Saving system time (UTC) to RTC");
|
||||||
|
gmtime_r(&tv.tv_sec, &tm);
|
||||||
|
if (ioctl(fd, RTC_SET_TIME, &tm) < 0) {
|
||||||
|
if (EINVAL == errno)
|
||||||
|
goto invalid;
|
||||||
|
rc = 1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
print(rc, NULL);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rtc_restore(void *arg)
|
||||||
|
{
|
||||||
|
struct timeval tv = { 0 };
|
||||||
|
struct tm tm = { 0 };
|
||||||
|
int fd, rc = 0;
|
||||||
|
|
||||||
|
fd = rtc_open();
|
||||||
|
if (fd < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ioctl(fd, RTC_RD_TIME, &tm) < 0) {
|
||||||
|
char msg[120];
|
||||||
|
|
||||||
|
snprintf(msg, sizeof(msg), "Failed restoring system clock, %s",
|
||||||
|
EINVAL == errno ? "RTC time is too old" :
|
||||||
|
ENOENT == errno ? "RTC has no saved time" : "see log for details");
|
||||||
|
print_desc(NULL, msg);
|
||||||
|
|
||||||
|
invalid:
|
||||||
|
logit(LOG_ERR, "Failed restoring system clock from RTC.");
|
||||||
|
if (EINVAL == errno)
|
||||||
|
logit(LOG_ERR, "RTC time is too old (before 2000-01-01 00:00)");
|
||||||
|
else if (ENOENT == errno)
|
||||||
|
logit(LOG_ERR, "RTC has no previously saved (valid) time.");
|
||||||
|
else
|
||||||
|
logit(LOG_ERR, "RTC error code %d: %m", errno);
|
||||||
|
rc = 2;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_desc(NULL, "Restoring system clock (UTC) from RTC");
|
||||||
|
tv.tv_sec = mktime(&tm);
|
||||||
|
if (tv.tv_sec < RTC_TIMESTAMP_BEGIN_2000) {
|
||||||
|
errno = EINVAL;
|
||||||
|
goto invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settimeofday(&tv, NULL) == -1)
|
||||||
|
rc = 1;
|
||||||
|
|
||||||
|
out:
|
||||||
|
print(rc, NULL);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static plugin_t plugin = {
|
||||||
|
.name = __FILE__,
|
||||||
|
.hook[HOOK_BASEFS_UP] = {
|
||||||
|
.cb = rtc_restore
|
||||||
|
},
|
||||||
|
.hook[HOOK_SHUTDOWN] = {
|
||||||
|
.cb = rtc_save
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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:
|
||||||
|
*/
|
||||||
+5
-5
@@ -57,7 +57,7 @@ static void watcher(void *arg, int fd, int events)
|
|||||||
{
|
{
|
||||||
int len = 0;
|
int len = 0;
|
||||||
char buf[EVENT_SIZE], name[42];
|
char buf[EVENT_SIZE], name[42];
|
||||||
tty_node_t *entry;
|
struct tty *entry;
|
||||||
struct inotify_event *notified = (struct inotify_event *)buf;
|
struct inotify_event *notified = (struct inotify_event *)buf;
|
||||||
|
|
||||||
while ((len = read(fd, buf, sizeof(buf)))) {
|
while ((len = read(fd, buf, sizeof(buf)))) {
|
||||||
@@ -72,11 +72,11 @@ static void watcher(void *arg, int fd, int events)
|
|||||||
|
|
||||||
snprintf(name, sizeof(name), "/dev/%s", notified->name);
|
snprintf(name, sizeof(name), "/dev/%s", notified->name);
|
||||||
entry = tty_find(name);
|
entry = tty_find(name);
|
||||||
if (entry && tty_enabled(&entry->data)) {
|
if (entry && tty_enabled(entry)) {
|
||||||
if (notified->mask & IN_CREATE)
|
if (notified->mask & IN_CREATE)
|
||||||
tty_start(&entry->data);
|
tty_start(entry);
|
||||||
else if (entry->data.pid)
|
else if (entry->pid)
|
||||||
tty_stop(&entry->data);
|
tty_stop(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
.deps/*
|
.deps/*
|
||||||
finit
|
finit
|
||||||
initctl
|
initctl
|
||||||
|
logit
|
||||||
reboot
|
reboot
|
||||||
|
watchdogd
|
||||||
Makefile
|
Makefile
|
||||||
Makefile.in
|
Makefile.in
|
||||||
+35
-15
@@ -1,15 +1,26 @@
|
|||||||
|
EXTRA_DIST = rescue.conf cgreaper.sh
|
||||||
AM_CPPFLAGS = -U_FORTIFY_SOURCE
|
AM_CPPFLAGS = -U_FORTIFY_SOURCE
|
||||||
AM_CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
|
AM_CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
|
||||||
if STATIC
|
if STATIC
|
||||||
AM_CPPFLAGS += -DENABLE_STATIC
|
AM_CPPFLAGS += -DENABLE_STATIC
|
||||||
AM_LDFLAGS = -static-libtool-libs
|
AM_LDFLAGS = -static-libtool-libs
|
||||||
else
|
else
|
||||||
AM_CPPFLAGS += -DPLUGIN_PATH=\"$(pkglibdir)\"
|
|
||||||
AM_LDFLAGS = -export-dynamic
|
AM_LDFLAGS = -export-dynamic
|
||||||
endif
|
endif
|
||||||
|
|
||||||
sbin_PROGRAMS = finit initctl reboot
|
sbin_PROGRAMS = finit initctl reboot
|
||||||
finit_SOURCES = api.c \
|
pkglibexec_SCRIPTS = cgreaper.sh
|
||||||
|
if WATCHDOGD
|
||||||
|
pkglibexec_PROGRAMS = watchdogd
|
||||||
|
endif
|
||||||
|
|
||||||
|
if LOGIT
|
||||||
|
bin_PROGRAMS = logit
|
||||||
|
logit_SOURCES = logit.c
|
||||||
|
logit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||||
|
endif
|
||||||
|
|
||||||
|
finit_SOURCES = api.c cgroup.c cgroup.h \
|
||||||
cond.c cond-w.c cond.h \
|
cond.c cond-w.c cond.h \
|
||||||
telinit.c \
|
telinit.c \
|
||||||
conf.c conf.h \
|
conf.c conf.h \
|
||||||
@@ -17,8 +28,10 @@ finit_SOURCES = api.c \
|
|||||||
getty.c stty.c \
|
getty.c stty.c \
|
||||||
helpers.c helpers.h \
|
helpers.c helpers.h \
|
||||||
log.c log.h \
|
log.c log.h \
|
||||||
mdadm.c mount.c pid.c \
|
mdadm.c mount.c \
|
||||||
|
pid.c pid.h \
|
||||||
plugin.c plugin.h private.h \
|
plugin.c plugin.h private.h \
|
||||||
|
schedule.c schedule.h \
|
||||||
service.c service.h \
|
service.c service.h \
|
||||||
sig.c sig.h \
|
sig.c sig.h \
|
||||||
sm.c sm.h \
|
sm.c sm.h \
|
||||||
@@ -30,15 +43,12 @@ pkginclude_HEADERS = cond.h finit.h helpers.h inetd.h log.h plugin.h svc.h
|
|||||||
if INETD
|
if INETD
|
||||||
finit_SOURCES += inetd.c inetd.h
|
finit_SOURCES += inetd.c inetd.h
|
||||||
endif
|
endif
|
||||||
if WATCHDOGD
|
|
||||||
finit_SOURCES += watchdog.c watchdog.h
|
|
||||||
endif
|
|
||||||
|
|
||||||
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)
|
||||||
if STATIC
|
if STATIC
|
||||||
finit_LDADD += plugins/libplug.la
|
finit_LDADD += ../plugins/libplug.la
|
||||||
else
|
else
|
||||||
finit_LDADD += -ldl
|
finit_LDADD += -ldl
|
||||||
endif
|
endif
|
||||||
@@ -57,12 +67,19 @@ reboot_LDADD = $(lite_LIBS)
|
|||||||
INIT_LNKS = telinit init
|
INIT_LNKS = telinit init
|
||||||
REBOOT_LNKS = shutdown halt poweroff suspend
|
REBOOT_LNKS = shutdown halt poweroff suspend
|
||||||
|
|
||||||
|
if WATCHDOGD
|
||||||
|
watchdogd_SOURCES = watchdog.c watchdog.h
|
||||||
|
watchdogd_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||||
|
#log.c log.h
|
||||||
|
endif
|
||||||
|
|
||||||
# Hook in install to add finit and reboot symlink(s)
|
# Hook in install to add finit and reboot symlink(s)
|
||||||
install-exec-hook:
|
install-exec-hook:
|
||||||
|
@$(INSTALL_DATA) $(srcdir)/rescue.conf $(DESTDIR)$(pkglibdir)
|
||||||
@for file in $(INIT_LNKS); do \
|
@for file in $(INIT_LNKS); do \
|
||||||
lnk=$(DESTDIR)$(sbindir)/$$file; \
|
lnk=$(DESTDIR)$(sbindir)/$$file; \
|
||||||
if [ -e $$lnk ]; then \
|
if [ -e $$lnk ]; then \
|
||||||
echo "Skipping $$lnk exists already."; \
|
echo "Skipping $$lnk exists."; \
|
||||||
else \
|
else \
|
||||||
$(LN_S) finit $$lnk; \
|
$(LN_S) finit $$lnk; \
|
||||||
fi; \
|
fi; \
|
||||||
@@ -71,16 +88,17 @@ install-exec-hook:
|
|||||||
echo "Non-finit reboot, skipping install."; \
|
echo "Non-finit reboot, skipping install."; \
|
||||||
else \
|
else \
|
||||||
for file in $(REBOOT_LNKS); do \
|
for file in $(REBOOT_LNKS); do \
|
||||||
link=$(DESTDIR)$(sbindir)/$$file; \
|
lnk=$(DESTDIR)$(sbindir)/$$file; \
|
||||||
if [ -e $$link ]; then \
|
if [ -e $$lnk ]; then \
|
||||||
echo "$$link exists, skipping.";\
|
echo "Skipping $$lnk exists."; \
|
||||||
else \
|
else \
|
||||||
$(LN_S) reboot $$link; \
|
$(LN_S) reboot $$lnk; \
|
||||||
fi; \
|
fi; \
|
||||||
done; \
|
done; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
uninstall-hook:
|
uninstall-hook:
|
||||||
|
@$(RM) $(DESTDIR)$(pkglibdir)/rescue.conf
|
||||||
@for file in $(INIT_LNKS); do \
|
@for file in $(INIT_LNKS); do \
|
||||||
lnk=`readlink $(DESTDIR)$(sbindir)/$$file`; \
|
lnk=`readlink $(DESTDIR)$(sbindir)/$$file`; \
|
||||||
if [ "$$lnk" != "finit" ]; then \
|
if [ "$$lnk" != "finit" ]; then \
|
||||||
@@ -93,9 +111,11 @@ uninstall-hook:
|
|||||||
echo "Non-finit reboot, skipping uninstall."; \
|
echo "Non-finit reboot, skipping uninstall."; \
|
||||||
else \
|
else \
|
||||||
for file in $(REBOOT_LNKS); do \
|
for file in $(REBOOT_LNKS); do \
|
||||||
if [ "`readlink $$file`" != "reboot" ]; \
|
lnk=$(DESTDIR)$(sbindir)/$$file; \
|
||||||
then continue; \
|
dst=`readlink $$lnk`; \
|
||||||
|
if [ "$$dst" != "reboot" ]; then \
|
||||||
|
continue; \
|
||||||
fi; \
|
fi; \
|
||||||
$(RM) $(DESTDIR)$(sbindir)/$$file; \
|
$(RM) $$lnk; \
|
||||||
done; \
|
done; \
|
||||||
fi
|
fi
|
||||||
@@ -44,6 +44,7 @@
|
|||||||
#include "service.h"
|
#include "service.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 *), char *buf, size_t len)
|
static int call(int (*action)(svc_t *), char *buf, size_t len)
|
||||||
@@ -51,7 +52,7 @@ static int call(int (*action)(svc_t *), char *buf, size_t len)
|
|||||||
return svc_parse_jobstr(buf, len, action, NULL);
|
return svc_parse_jobstr(buf, len, action, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int service_stop(svc_t *svc)
|
static int stop(svc_t *svc)
|
||||||
{
|
{
|
||||||
if (!svc)
|
if (!svc)
|
||||||
return 1;
|
return 1;
|
||||||
@@ -62,7 +63,7 @@ static int service_stop(svc_t *svc)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int service_start(svc_t *svc)
|
static int start(svc_t *svc)
|
||||||
{
|
{
|
||||||
if (!svc)
|
if (!svc)
|
||||||
return 1;
|
return 1;
|
||||||
@@ -73,43 +74,45 @@ static int service_start(svc_t *svc)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int service_restart(svc_t *svc)
|
static int restart(svc_t *svc)
|
||||||
{
|
{
|
||||||
if (!svc)
|
if (!svc)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
if (svc_is_blocked(svc))
|
||||||
|
svc_start(svc);
|
||||||
|
|
||||||
svc_mark_dirty(svc);
|
svc_mark_dirty(svc);
|
||||||
service_step(svc);
|
service_step(svc);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_start (char *buf, size_t len) { return call(service_start, buf, len); }
|
static int do_start (char *buf, size_t len) { return call(start, buf, len); }
|
||||||
static int do_stop (char *buf, size_t len) { return call(service_stop, buf, len); }
|
static int do_stop (char *buf, size_t len) { return call(stop, buf, len); }
|
||||||
static int do_restart(char *buf, size_t len) { return call(service_restart, buf, len); }
|
static int do_restart(char *buf, size_t len) { return call(restart, buf, len); }
|
||||||
|
|
||||||
static char query_buf[368];
|
static char query_buf[368];
|
||||||
static int missing(char *job, int id)
|
static int missing(char *job, char *id)
|
||||||
{
|
{
|
||||||
char buf[20];
|
char buf[20];
|
||||||
char idstr[10] = "";
|
|
||||||
|
|
||||||
if (!job)
|
if (!job)
|
||||||
job = "";
|
job = "";
|
||||||
if (id > 1)
|
if (!id)
|
||||||
snprintf(idstr, sizeof(idstr), ":%d", id);
|
id = "";
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "%s%s ", job, idstr);
|
snprintf(buf, sizeof(buf), "%s:%s ", job, id);
|
||||||
strlcat(query_buf, buf, sizeof(query_buf));
|
strlcat(query_buf, buf, sizeof(query_buf));
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_query(struct init_request *rq, size_t len)
|
static int do_query(char *buf, size_t len)
|
||||||
{
|
{
|
||||||
memset(query_buf, 0, sizeof(query_buf));
|
memset(query_buf, 0, sizeof(query_buf));
|
||||||
if (svc_parse_jobstr(rq->data, strlen(rq->data) + 1, NULL, missing)) {
|
if (svc_parse_jobstr(buf, len, NULL, missing)) {
|
||||||
memcpy(rq->data, query_buf, sizeof(rq->data));
|
memcpy(buf, query_buf, len);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,8 +121,9 @@ static int do_query(struct init_request *rq, size_t len)
|
|||||||
|
|
||||||
static svc_t *do_find(char *buf, size_t len)
|
static svc_t *do_find(char *buf, size_t len)
|
||||||
{
|
{
|
||||||
int id = 1;
|
char *id = NULL;
|
||||||
char *ptr, *input;
|
char *ptr, *input;
|
||||||
|
svc_t *iter = NULL;
|
||||||
|
|
||||||
input = sanitize(buf, len);
|
input = sanitize(buf, len);
|
||||||
if (!input)
|
if (!input)
|
||||||
@@ -128,11 +132,28 @@ static svc_t *do_find(char *buf, size_t len)
|
|||||||
ptr = strchr(input, ':');
|
ptr = strchr(input, ':');
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
*ptr++ = 0;
|
*ptr++ = 0;
|
||||||
id = atonum(ptr);
|
id = ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isdigit(input[0]))
|
if (isdigit(input[0])) {
|
||||||
return svc_find_by_jobid(atonum(input), id);
|
char *ep;
|
||||||
|
long job = 0;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
job = strtol(input, &ep, 10);
|
||||||
|
if ((errno == ERANGE && (job == LONG_MAX || job == LONG_MIN)) ||
|
||||||
|
(errno != 0 && job == 0) ||
|
||||||
|
(input == ep))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!id)
|
||||||
|
return svc_job_iterator(&iter, 1, job);
|
||||||
|
|
||||||
|
return svc_find_by_jobid(job, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!id)
|
||||||
|
return svc_named_iterator(&iter, 1, input);
|
||||||
|
|
||||||
return svc_find_by_nameid(input, id);
|
return svc_find_by_nameid(input, id);
|
||||||
}
|
}
|
||||||
@@ -160,47 +181,6 @@ ev_t ev_list[] = {
|
|||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static int do_handle_event(char *event)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; ev_list[i].event; i++) {
|
|
||||||
ev_t *e = &ev_list[i];
|
|
||||||
size_t len = MAX(strlen(e->event), strlen(event));
|
|
||||||
|
|
||||||
if (!strncasecmp(e->event, event, len)) {
|
|
||||||
e->cb();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event[0] == '-')
|
|
||||||
cond_clear(&event[1]);
|
|
||||||
else if (event[0] == '+')
|
|
||||||
cond_set(&event[1]);
|
|
||||||
else
|
|
||||||
cond_set(event);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int do_handle_emit(char *buf, size_t len)
|
|
||||||
{
|
|
||||||
int result = 0;
|
|
||||||
char *input, *event, *pos;
|
|
||||||
|
|
||||||
input = sanitize(buf, len);
|
|
||||||
if (!input)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
event = strtok_r(input, " ", &pos);
|
|
||||||
while (event) {
|
|
||||||
result += do_handle_event(event);
|
|
||||||
event = strtok_r(NULL, " ", &pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void send_svc(int sd, svc_t *svc)
|
static void send_svc(int sd, svc_t *svc)
|
||||||
{
|
{
|
||||||
svc_t empty;
|
svc_t empty;
|
||||||
@@ -295,31 +275,30 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
|
|
||||||
case INIT_CMD_START_SVC:
|
case INIT_CMD_START_SVC:
|
||||||
_d("start %s", rq.data);
|
_d("start %s", 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_STOP_SVC:
|
case INIT_CMD_STOP_SVC:
|
||||||
_d("stop %s", rq.data);
|
_d("stop %s", rq.data);
|
||||||
|
strterm(rq.data, sizeof(rq.data));
|
||||||
result = do_stop(rq.data, sizeof(rq.data));
|
result = do_stop(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_RESTART_SVC:
|
case INIT_CMD_RESTART_SVC:
|
||||||
_d("restart %s", rq.data);
|
_d("restart %s", 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;
|
||||||
|
|
||||||
#ifdef INETD_ENABLED
|
#ifdef INETD_ENABLED
|
||||||
case INIT_CMD_QUERY_INETD:
|
case INIT_CMD_QUERY_INETD:
|
||||||
_d("query inetd");
|
_d("query inetd");
|
||||||
|
strterm(rq.data, sizeof(rq.data));
|
||||||
result = do_query_inetd(rq.data, sizeof(rq.data));
|
result = do_query_inetd(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case INIT_CMD_EMIT:
|
|
||||||
_d("emit %s", rq.data);
|
|
||||||
result = do_handle_emit(rq.data, sizeof(rq.data));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case INIT_CMD_GET_RUNLEVEL:
|
case INIT_CMD_GET_RUNLEVEL:
|
||||||
_d("get runlevel");
|
_d("get runlevel");
|
||||||
rq.runlevel = runlevel;
|
rq.runlevel = runlevel;
|
||||||
@@ -337,12 +316,23 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wdogpid > 0 && wdogpid != rq.runlevel) {
|
_e("Request to hand-over wdog ... to PID %d", rq.runlevel);
|
||||||
_d("Sending SIGTERM to %d", wdogpid);
|
svc = svc_find_by_pid(rq.runlevel);
|
||||||
kill(wdogpid, SIGTERM);
|
if (!svc) {
|
||||||
do_sleep(1);
|
logit(LOG_ERR, "Cannot find PID %d, not registered.", rq.runlevel);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
wdogpid = rq.runlevel;
|
|
||||||
|
/* Disable and allow Finit to collect bundled watchdog */
|
||||||
|
if (wdog) {
|
||||||
|
logit(LOG_NOTICE, "Stopping and removing %s (PID:%d)", wdog->cmd, wdog->pid);
|
||||||
|
stop(wdog);
|
||||||
|
if (wdog->protect) {
|
||||||
|
wdog->protect = 0;
|
||||||
|
wdog->runlevels = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wdog = svc;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_SVC_ITER:
|
case INIT_CMD_SVC_ITER:
|
||||||
@@ -358,11 +348,13 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
|
|
||||||
case INIT_CMD_SVC_QUERY:
|
case INIT_CMD_SVC_QUERY:
|
||||||
_d("svc query: %s", rq.data);
|
_d("svc query: %s", rq.data);
|
||||||
result = do_query(&rq, len);
|
strterm(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);
|
_d("svc find: %s", 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;
|
||||||
|
|
||||||
@@ -380,13 +372,11 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
_d("Failed sending ACK/NACK back to client");
|
_d("Failed sending ACK/NACK back to client");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UEV_ERROR == events)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
close(sd);
|
close(sd);
|
||||||
|
if (UEV_ERROR == events)
|
||||||
|
goto error;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
api_exit();
|
api_exit();
|
||||||
if (api_init(w->ctx))
|
if (api_init(w->ctx))
|
||||||
@@ -430,8 +420,9 @@ error:
|
|||||||
|
|
||||||
int api_exit(void)
|
int api_exit(void)
|
||||||
{
|
{
|
||||||
return shutdown(api_watcher.fd, SHUT_RDWR) ||
|
uev_io_stop(&api_watcher);
|
||||||
close(api_watcher.fd);
|
|
||||||
|
return close(api_watcher.fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Executable
+11
@@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Called by kernel when last child in cgroup exists
|
||||||
|
|
||||||
|
BASE=/sys/fs/cgroup/finit
|
||||||
|
PROC=`basename $1`
|
||||||
|
DIR="$BASE$1"
|
||||||
|
|
||||||
|
logit -p daemon.info -t finit "$PROC stopped, cleaning up control group $DIR"
|
||||||
|
rmdir $DIR
|
||||||
|
|
||||||
|
exit 0
|
||||||
+140
@@ -0,0 +1,140 @@
|
|||||||
|
/* Finit control group support functions
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Joachim Nilsson <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 <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <lite/lite.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static int cg_init = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called by Finit at early boot to mount initial cgroups
|
||||||
|
*/
|
||||||
|
void cgroup_init(void)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
char buf[80];
|
||||||
|
int opts = MS_NODEV | MS_NOEXEC | MS_NOSUID;
|
||||||
|
|
||||||
|
fp = fopen("/proc/cgroups", "r");
|
||||||
|
if (!fp) {
|
||||||
|
_d("No cgroup support");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mount("none", "/sys/fs/cgroup", "tmpfs", opts, NULL)) {
|
||||||
|
_d("Failed mounting cgroups");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip first line, header */
|
||||||
|
fgets(buf, sizeof(buf), fp);
|
||||||
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
char *cgroup;
|
||||||
|
char rc[80];
|
||||||
|
|
||||||
|
cgroup = strtok(buf, "\t ");
|
||||||
|
if (!cgroup)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
snprintf(rc, sizeof(rc), "/sys/fs/cgroup/%s", cgroup);
|
||||||
|
if (mkdir(rc, 0755) && EEXIST != errno)
|
||||||
|
continue;
|
||||||
|
if (mount("cgroup", rc, "cgroup", opts, cgroup))
|
||||||
|
_d("Failed mounting %s cgroup on %s", cgroup, rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Default cgroups for process monitoring */
|
||||||
|
if (mkdir("/sys/fs/cgroup/finit", 0755) && EEXIST != errno)
|
||||||
|
goto fail;
|
||||||
|
if (mount("none", "/sys/fs/cgroup/finit", "cgroup", opts, "none,name=finit")) {
|
||||||
|
_pe("Failed mounting Finit cgroup hierarchy");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set up reaper and enable callbacks */
|
||||||
|
echo("/sys/fs/cgroup/finit/release_agent", 0, FINIT_LIBPATH_ "/cgreaper.sh");
|
||||||
|
echo("/sys/fs/cgroup/finit/notify_on_release", 0, "1");
|
||||||
|
|
||||||
|
/* Default groups, PID 1, services, and user/login processes */
|
||||||
|
if (mkdir("/sys/fs/cgroup/finit/init", 0755) && EEXIST != errno)
|
||||||
|
goto fail;
|
||||||
|
if (mkdir("/sys/fs/cgroup/finit/system", 0755) && EEXIST != errno)
|
||||||
|
goto fail;
|
||||||
|
if (mkdir("/sys/fs/cgroup/finit/user", 0755) && EEXIST != errno)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* Move ourselves to init */
|
||||||
|
echo("/sys/fs/cgroup/finit/init/cgroup.procs", 0, "1");
|
||||||
|
|
||||||
|
/* We have signal, main screen turn on! */
|
||||||
|
cg_init = 1;
|
||||||
|
fail:
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int move_pid(char *group, char *name, char *id, int pid)
|
||||||
|
{
|
||||||
|
char path[256];
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "/sys/fs/cgroup/%s/%s:%s", group, name, id);
|
||||||
|
if (mkdir(path, 0755) && errno != EEXIST)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
strlcat(path, "/cgroup.procs", sizeof(path));
|
||||||
|
|
||||||
|
return echo(path, 0, "%d", pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cgroup_user(char *name)
|
||||||
|
{
|
||||||
|
if (!cg_init)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return move_pid("finit/user", name, "0", getpid());
|
||||||
|
}
|
||||||
|
|
||||||
|
int cgroup_service(char *nm, char *id, int pid)
|
||||||
|
{
|
||||||
|
if (!cg_init)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (pid <= 0) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return move_pid("finit/system", nm, id, pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Variables:
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/* Finit control group support functions
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Joachim Nilsson <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_CGROUP_H_
|
||||||
|
#define FINIT_CGROUP_H_
|
||||||
|
|
||||||
|
void cgroup_init (void);
|
||||||
|
|
||||||
|
int cgroup_user (char *name);
|
||||||
|
int cgroup_service (char *cmd, char *id, int pid);
|
||||||
|
|
||||||
|
#endif /* FINIT_CGROUP_H_ */
|
||||||
+1
-1
@@ -125,7 +125,7 @@ error:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
svc_t *client_svc_find(char *arg)
|
svc_t *client_svc_find(const char *arg)
|
||||||
{
|
{
|
||||||
int sd = -1;
|
int sd = -1;
|
||||||
struct init_request rq = {
|
struct init_request rq = {
|
||||||
|
|||||||
+1
-6
@@ -27,16 +27,11 @@
|
|||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "svc.h"
|
#include "svc.h"
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char *cmd;
|
|
||||||
int (*cb)(char *arg);
|
|
||||||
} command_t;
|
|
||||||
|
|
||||||
int client_connect (void);
|
int client_connect (void);
|
||||||
int client_disconnect (void);
|
int client_disconnect (void);
|
||||||
|
|
||||||
int client_send (struct init_request *rq, ssize_t len);
|
int client_send (struct init_request *rq, ssize_t len);
|
||||||
svc_t *client_svc_iterator (int first);
|
svc_t *client_svc_iterator (int first);
|
||||||
svc_t *client_svc_find (char *arg);
|
svc_t *client_svc_find (const char *arg);
|
||||||
|
|
||||||
#endif /* FINIT_CLIENT_H_ */
|
#endif /* FINIT_CLIENT_H_ */
|
||||||
+125
-16
@@ -28,14 +28,81 @@
|
|||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
|
#include "pid.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
|
|
||||||
static int cond_set_gen(const char *path, unsigned int gen)
|
/*
|
||||||
|
* The service condition name is constructed from the 'svc/' prefix, the
|
||||||
|
* dirname of the svc->cmd, e.g., '/usr/bin/teamd' => 'usr/bin', and the
|
||||||
|
* service's pid:filename, including an optional subdirectory, without
|
||||||
|
* the .pid extension.
|
||||||
|
*
|
||||||
|
* The following example uses the team (aggregate) service:
|
||||||
|
*
|
||||||
|
* service pid:!/run/teamd/a1.pid /usr/bin/teamd -f /etc/teamd/a1.conf
|
||||||
|
*
|
||||||
|
* => 'svc/' + 'usr/bin' + 'teamd/a1' => svc/usr/bin/teamd/a1
|
||||||
|
*
|
||||||
|
* The next example uses the dbus-daemon:
|
||||||
|
*
|
||||||
|
* service pid:!/run/dbus/pid /usr/bin/dbus-daemon
|
||||||
|
*
|
||||||
|
* => 'svc/' + 'usr/bin' + 'dbus' => svc/usr/bin/dbus
|
||||||
|
*
|
||||||
|
* The last example uses lxc-start to start container foo:
|
||||||
|
*
|
||||||
|
* service pid:!/run/lxc/foo.pid lxc-start -n foo -F -p /run/lxc/foo.pid -- Container foo
|
||||||
|
*
|
||||||
|
* => 'svc/' + '' + 'lxc/foo' => svc/lxc/foo
|
||||||
|
*/
|
||||||
|
char *mkcond(svc_t *svc, char *buf, size_t len)
|
||||||
{
|
{
|
||||||
|
char path[256];
|
||||||
|
char *pidfile;
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
strlcpy(path, svc->cmd, sizeof(path));
|
||||||
|
ptr = rindex(path, '/');
|
||||||
|
if (ptr)
|
||||||
|
*ptr = 0;
|
||||||
|
else
|
||||||
|
path[0] = 0;
|
||||||
|
|
||||||
|
pidfile = pid_file(svc);
|
||||||
|
ptr = strstr(pidfile, "run");
|
||||||
|
if (ptr)
|
||||||
|
ptr += 3;
|
||||||
|
else
|
||||||
|
ptr = rindex(pidfile, '/');
|
||||||
|
|
||||||
|
snprintf(buf, len, "svc%s%s%s", path[0] != 0 && path[0] != '/' ? "/" : "", path, ptr);
|
||||||
|
_d("Composed condition from cmd %s (path %s) and pidfile %s => %s", svc->cmd, path, ptr, buf);
|
||||||
|
|
||||||
|
/* Case: /var/run/dbus/pid */
|
||||||
|
ptr = strstr(buf, "/pid");
|
||||||
|
if (ptr && !strcmp(ptr, "/pid"))
|
||||||
|
*ptr = 0;
|
||||||
|
|
||||||
|
/* Case /var/run/teamd/a1.pid */
|
||||||
|
ptr = strstr(buf, ".pid");
|
||||||
|
if (ptr && !strcmp(ptr, ".pid"))
|
||||||
|
*ptr = 0;
|
||||||
|
|
||||||
|
_d("Creating condition => %s", buf);
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cond_set_gen(const char *file, unsigned int gen)
|
||||||
|
{
|
||||||
|
char *ptr, path[256];
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
fp = fopen(path, "w");
|
/* /var/run --> /run symlink may not exist (yet) */
|
||||||
|
ptr = pid_runpath(file, path, sizeof(path));
|
||||||
|
|
||||||
|
fp = fopen(ptr, "w");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@@ -59,9 +126,27 @@ static void cond_bump_reconf(void)
|
|||||||
cond_set_gen(COND_RECONF, rgen);
|
cond_set_gen(COND_RECONF, rgen);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cond_set_path(const char *path, enum cond_state new)
|
static int cond_checkpath(const char *path)
|
||||||
{
|
{
|
||||||
char buf[MAX_ARG_LEN], *dir;
|
char buf[MAX_ARG_LEN], *dir;
|
||||||
|
|
||||||
|
strlcpy(buf, path, sizeof(buf));
|
||||||
|
dir = dirname(buf);
|
||||||
|
if (!dir) {
|
||||||
|
_e("Invalid path '%s' for condition", path);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (makepath(dir) && errno != EEXIST) {
|
||||||
|
_pe("Failed creating dir '%s' for condition '%s'", dir, path);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cond_set_path(const char *path, enum cond_state new)
|
||||||
|
{
|
||||||
enum cond_state old;
|
enum cond_state old;
|
||||||
unsigned int rgen;
|
unsigned int rgen;
|
||||||
|
|
||||||
@@ -77,16 +162,8 @@ int cond_set_path(const char *path, enum cond_state new)
|
|||||||
|
|
||||||
switch (new) {
|
switch (new) {
|
||||||
case COND_ON:
|
case COND_ON:
|
||||||
strlcpy(buf, path, sizeof(buf));
|
if (cond_checkpath(path))
|
||||||
dir = dirname(buf);
|
return 0;
|
||||||
if (!dir) {
|
|
||||||
_e("Invalid path '%s' for condition", path);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (makepath(dir) && errno != EEXIST) {
|
|
||||||
_pe("Failed creating dir '%s' for condition '%s'", dir, path);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
cond_set_gen(path, rgen);
|
cond_set_gen(path, rgen);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -113,6 +190,7 @@ static int svc_has_cond(svc_t *svc)
|
|||||||
case SVC_TYPE_SERVICE:
|
case SVC_TYPE_SERVICE:
|
||||||
case SVC_TYPE_TASK:
|
case SVC_TYPE_TASK:
|
||||||
case SVC_TYPE_RUN:
|
case SVC_TYPE_RUN:
|
||||||
|
case SVC_TYPE_SYSV:
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -137,17 +215,40 @@ static void cond_update(const char *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void cond_set(const char *name)
|
void cond_set(const char *name)
|
||||||
{
|
{
|
||||||
_d("%s", name);
|
_d("%s", name);
|
||||||
|
if (string_compare(name, "nop"))
|
||||||
|
return;
|
||||||
|
|
||||||
if (!cond_set_path(cond_path(name), COND_ON))
|
if (!cond_set_path(cond_path(name), COND_ON))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cond_update(name);
|
cond_update(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cond_set_oneshot(const char *name)
|
||||||
|
{
|
||||||
|
const char *path;
|
||||||
|
|
||||||
|
if (string_compare(name, "nop"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
path = cond_path(name);
|
||||||
|
_d("%s => %s", name, path);
|
||||||
|
|
||||||
|
if (cond_checkpath(path))
|
||||||
|
return;
|
||||||
|
|
||||||
|
symlink(COND_RECONF, path);
|
||||||
|
cond_update(name);
|
||||||
|
}
|
||||||
|
|
||||||
void cond_clear(const char *name)
|
void cond_clear(const char *name)
|
||||||
{
|
{
|
||||||
_d("%s", name);
|
_d("%s", name);
|
||||||
|
if (string_compare(name, "nop"))
|
||||||
|
return;
|
||||||
|
|
||||||
if (!cond_set_path(cond_path(name), COND_OFF))
|
if (!cond_set_path(cond_path(name), COND_OFF))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -172,7 +273,13 @@ static int reassert(const char *fpath, const struct stat *sb, int tflg, struct F
|
|||||||
if (tflg != FTW_F)
|
if (tflg != FTW_F)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
nm = (char *)fpath + sizeof(COND_PATH);
|
nm = strstr((char *)fpath, COND_DIR);
|
||||||
|
if (!nm) {
|
||||||
|
_e("Incorrect condtion path %s, cannot reassert", fpath);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
nm += sizeof(COND_DIR);
|
||||||
_d("Reasserting %s => %s", fpath, nm);
|
_d("Reasserting %s => %s", fpath, nm);
|
||||||
cond_set(nm);
|
cond_set(nm);
|
||||||
|
|
||||||
@@ -191,7 +298,9 @@ void cond_reassert(const char *type)
|
|||||||
|
|
||||||
void cond_init(void)
|
void cond_init(void)
|
||||||
{
|
{
|
||||||
if (makepath(COND_PATH) && errno != EEXIST) {
|
char path[MAX_ARG_LEN];
|
||||||
|
|
||||||
|
if (makepath(pid_runpath(COND_PATH, path, sizeof(path))) && errno != EEXIST) {
|
||||||
_pe("Failed creating condition base directory '%s'", COND_PATH);
|
_pe("Failed creating condition base directory '%s'", COND_PATH);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-9
@@ -26,9 +26,9 @@
|
|||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
|
#include "pid.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
|
|
||||||
|
|
||||||
const char *condstr(enum cond_state s)
|
const char *condstr(enum cond_state s)
|
||||||
{
|
{
|
||||||
static const char *strs[] = {
|
static const char *strs[] = {
|
||||||
@@ -42,20 +42,25 @@ const char *condstr(enum cond_state s)
|
|||||||
|
|
||||||
const char *cond_path(const char *name)
|
const char *cond_path(const char *name)
|
||||||
{
|
{
|
||||||
static char file[MAX_ARG_LEN];
|
static char path[256];
|
||||||
|
char tmp[MAX_ARG_LEN];
|
||||||
|
|
||||||
snprintf(file, sizeof(file), COND_PATH "/%s", name);
|
snprintf(tmp, sizeof(tmp), COND_PATH "/%s", name);
|
||||||
|
|
||||||
return file;
|
return pid_runpath(tmp, path, sizeof(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int cond_get_gen(const char *path)
|
unsigned int cond_get_gen(const char *file)
|
||||||
{
|
{
|
||||||
unsigned int gen;
|
unsigned int gen;
|
||||||
|
char *ptr, path[256];
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
fp = fopen(path, "r");
|
/* /var/run --> /run symlink may not exist (yet) */
|
||||||
|
ptr = pid_runpath(file, path, sizeof(path));
|
||||||
|
|
||||||
|
fp = fopen(ptr, "r");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -87,9 +92,9 @@ 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)
|
||||||
{
|
{
|
||||||
char *cond;
|
static char conds[MAX_COND_LEN];
|
||||||
enum cond_state s = COND_ON;
|
enum cond_state s = COND_ON;
|
||||||
static char conds[MAX_ARG_LEN];
|
char *cond;
|
||||||
|
|
||||||
if (!names)
|
if (!names)
|
||||||
return COND_ON;
|
return COND_ON;
|
||||||
@@ -103,8 +108,8 @@ 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 *cond;
|
char *cond;
|
||||||
static char conds[MAX_ARG_LEN];
|
|
||||||
|
|
||||||
if (!name || !names)
|
if (!name || !names)
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+11
-8
@@ -2,9 +2,10 @@
|
|||||||
#define FINIT_COND_H_
|
#define FINIT_COND_H_
|
||||||
|
|
||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
|
#include <svc.h>
|
||||||
|
|
||||||
#define COND_PATH _PATH_VARRUN "finit/cond"
|
#define COND_DIR "finit/cond"
|
||||||
#define COND_SVC_PATH COND_PATH "/svc/"
|
#define COND_PATH _PATH_VARRUN COND_DIR
|
||||||
#define COND_RECONF COND_PATH "/reconf"
|
#define COND_RECONF COND_PATH "/reconf"
|
||||||
|
|
||||||
typedef enum cond_state {
|
typedef enum cond_state {
|
||||||
@@ -13,6 +14,7 @@ typedef enum cond_state {
|
|||||||
COND_ON
|
COND_ON
|
||||||
} cond_state_t;
|
} cond_state_t;
|
||||||
|
|
||||||
|
char *mkcond (svc_t *svc, char *buf, size_t len);
|
||||||
const char *condstr (enum cond_state s);
|
const char *condstr (enum cond_state s);
|
||||||
const char *cond_path (const char *name);
|
const char *cond_path (const char *name);
|
||||||
unsigned int cond_get_gen (const char *path);
|
unsigned int cond_get_gen (const char *path);
|
||||||
@@ -21,12 +23,13 @@ enum cond_state cond_get (const char *name);
|
|||||||
enum cond_state cond_get_agg (const char *names);
|
enum cond_state cond_get_agg (const char *names);
|
||||||
int cond_affects (const char *name, const char *names);
|
int cond_affects (const char *name, const char *names);
|
||||||
|
|
||||||
int cond_set_path(const char *path, enum cond_state new);
|
int cond_set_path (const char *path, enum cond_state new);
|
||||||
void cond_set (const char *name);
|
void cond_set (const char *name);
|
||||||
void cond_clear (const char *name);
|
void cond_set_oneshot (const char *name);
|
||||||
void cond_reload (void);
|
void cond_clear (const char *name);
|
||||||
void cond_reassert(const char *pat);
|
void cond_reload (void);
|
||||||
void cond_init (void);
|
void cond_reassert (const char *pat);
|
||||||
|
void cond_init (void);
|
||||||
|
|
||||||
#endif /* FINIT_COND_H_ */
|
#endif /* FINIT_COND_H_ */
|
||||||
|
|
||||||
|
|||||||
+200
-59
@@ -30,17 +30,22 @@
|
|||||||
#include <lite/lite.h>
|
#include <lite/lite.h>
|
||||||
#include <lite/queue.h> /* BSD sys/queue.h API */
|
#include <lite/queue.h> /* BSD sys/queue.h API */
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
#include <glob.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
#define BOOTSTRAP (runlevel == 0)
|
#define BOOTSTRAP (runlevel == 0)
|
||||||
#define MATCH_CMD(l, c, x) \
|
#define MATCH_CMD(l, c, x) \
|
||||||
(!strncasecmp(l, c, strlen(c)) && (x = (l) + strlen(c)))
|
(!strncasecmp(l, c, strlen(c)) && (x = (l) + strlen(c)))
|
||||||
|
|
||||||
|
int logfile_size_max = 200000; /* 200 kB */
|
||||||
|
int logfile_count_max = 5;
|
||||||
|
|
||||||
struct rlimit global_rlimit[RLIMIT_NLIMITS];
|
struct rlimit global_rlimit[RLIMIT_NLIMITS];
|
||||||
|
|
||||||
struct conf_change {
|
struct conf_change {
|
||||||
@@ -48,7 +53,7 @@ struct conf_change {
|
|||||||
char *name;
|
char *name;
|
||||||
};
|
};
|
||||||
|
|
||||||
static uev_t w1, w2, w3;
|
static uev_t w1, w2, w3, w4;
|
||||||
static TAILQ_HEAD(head, conf_change) conf_change_list = TAILQ_HEAD_INITIALIZER(conf_change_list);
|
static TAILQ_HEAD(head, conf_change) conf_change_list = TAILQ_HEAD_INITIALIZER(conf_change_list);
|
||||||
|
|
||||||
static int parse_conf(char *file);
|
static int parse_conf(char *file);
|
||||||
@@ -58,24 +63,85 @@ void conf_parse_cmdline(void)
|
|||||||
{
|
{
|
||||||
int dbg = 0;
|
int dbg = 0;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
char line[LINE_SIZE], *cmdline, *tok;
|
||||||
|
|
||||||
fp = fopen("/proc/cmdline", "r");
|
fp = fopen("/proc/cmdline", "r");
|
||||||
if (fp) {
|
if (!fp)
|
||||||
char line[LINE_SIZE];
|
goto done;
|
||||||
|
|
||||||
fgets(line, sizeof(line), fp);
|
|
||||||
chomp(line);
|
|
||||||
_d("%s", line);
|
|
||||||
|
|
||||||
if (strstr(line, "finit_debug") || strstr(line, "--debug"))
|
|
||||||
dbg = 1;
|
|
||||||
|
|
||||||
|
if (!fgets(line, sizeof(line), fp)) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmdline = chomp(line);
|
||||||
|
_d("%s", cmdline);
|
||||||
|
|
||||||
|
while ((tok = strtok(cmdline, " \t"))) {
|
||||||
|
cmdline = NULL;
|
||||||
|
|
||||||
|
/* Catches finit_debug (deprecated), --debug, and debug */
|
||||||
|
if (strstr(tok, "debug"))
|
||||||
|
dbg = 1;
|
||||||
|
|
||||||
|
if (string_compare(tok, "rescue") || string_compare(tok, "recover"))
|
||||||
|
rescue = 1;
|
||||||
|
|
||||||
|
if (string_compare(tok, "single") || string_compare(tok, "S"))
|
||||||
|
single = 1;
|
||||||
|
|
||||||
|
if (string_compare(tok, "splash"))
|
||||||
|
splash = 1;
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
done:
|
||||||
log_init(dbg);
|
log_init(dbg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int kmod_exists(char *mod)
|
||||||
|
{
|
||||||
|
int found = 0;
|
||||||
|
FILE *fp;
|
||||||
|
char buf[256];
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
for (len = 0; mod[len]; len++) {
|
||||||
|
if (mod[len] == ' ' || mod[len] == '\t')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp = fopen("/proc/modules", "r");
|
||||||
|
if (!fp)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while (!found && (fgets(buf, sizeof(buf), fp))) {
|
||||||
|
if (!strncmp(buf, mod, len))
|
||||||
|
found = 1;
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kmod_load(char *line)
|
||||||
|
{
|
||||||
|
char *mod;
|
||||||
|
char cmd[CMD_SIZE];
|
||||||
|
|
||||||
|
if (runlevel != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mod = strip_line(line);
|
||||||
|
if (kmod_exists(mod))
|
||||||
|
return;
|
||||||
|
|
||||||
|
strcpy(cmd, "modprobe ");
|
||||||
|
strlcat(cmd, mod, sizeof(cmd));
|
||||||
|
|
||||||
|
run_interactive(cmd, "Loading kernel module %s", mod);
|
||||||
|
}
|
||||||
|
|
||||||
/* Convert optional "[!123456789S]" string into a bitmask */
|
/* Convert optional "[!123456789S]" string into a bitmask */
|
||||||
int conf_parse_runlevels(char *runlevels)
|
int conf_parse_runlevels(char *runlevels)
|
||||||
{
|
{
|
||||||
@@ -200,11 +266,33 @@ char *rlim2str(int rlim)
|
|||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *lim2str(struct rlimit *rlim)
|
||||||
|
{
|
||||||
|
char tmp[25];
|
||||||
|
static char buf[42];
|
||||||
|
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
if (RLIM_INFINITY == rlim->rlim_cur)
|
||||||
|
snprintf(tmp, sizeof(tmp), "unlimited, ");
|
||||||
|
else
|
||||||
|
snprintf(tmp, sizeof(tmp), "%llu, ", (unsigned long long)rlim->rlim_cur);
|
||||||
|
strlcat(buf, tmp, sizeof(buf));
|
||||||
|
|
||||||
|
if (RLIM_INFINITY == rlim->rlim_max)
|
||||||
|
snprintf(tmp, sizeof(tmp), "unlimited, ");
|
||||||
|
else
|
||||||
|
snprintf(tmp, sizeof(tmp), "%llu, ", (unsigned long long)rlim->rlim_max);
|
||||||
|
strlcat(buf, tmp, sizeof(buf));
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First form: `rlimit <hard|soft> RESOURCE LIMIT` */
|
||||||
void conf_parse_rlimit(char *line, struct rlimit arr[])
|
void conf_parse_rlimit(char *line, struct rlimit arr[])
|
||||||
{
|
{
|
||||||
char *level, *limit, *val;
|
char *level, *limit, *val;
|
||||||
int resource = -1;
|
int resource = -1;
|
||||||
rlim_t cfg, *set;
|
rlim_t cfg;
|
||||||
|
|
||||||
level = strtok(line, " \t");
|
level = strtok(line, " \t");
|
||||||
if (!level)
|
if (!level)
|
||||||
@@ -214,21 +302,18 @@ void conf_parse_rlimit(char *line, struct rlimit arr[])
|
|||||||
if (!limit)
|
if (!limit)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
val = strtok(NULL, " \t");
|
||||||
|
if (!val) {
|
||||||
|
/* Second form: `rlimit RESOURCE LIMIT` */
|
||||||
|
val = limit;
|
||||||
|
limit = level;
|
||||||
|
level = "both";
|
||||||
|
}
|
||||||
|
|
||||||
resource = str2rlim(limit);
|
resource = str2rlim(limit);
|
||||||
if (resource < 0 || resource > RLIMIT_NLIMITS)
|
if (resource < 0 || resource > RLIMIT_NLIMITS)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
val = strtok(NULL, " \t");
|
|
||||||
if (!val)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (!strcmp(level, "soft"))
|
|
||||||
set = &arr[resource].rlim_cur;
|
|
||||||
else if (!strcmp(level, "hard"))
|
|
||||||
set = &arr[resource].rlim_max;
|
|
||||||
else
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
/* Official keyword from v3.1 is `unlimited`, from prlimit(1) */
|
/* Official keyword from v3.1 is `unlimited`, from prlimit(1) */
|
||||||
if (!strcmp(val, "unlimited") || !strcmp(val, "infinity")) {
|
if (!strcmp(val, "unlimited") || !strcmp(val, "infinity")) {
|
||||||
cfg = RLIM_INFINITY;
|
cfg = RLIM_INFINITY;
|
||||||
@@ -243,7 +328,15 @@ void conf_parse_rlimit(char *line, struct rlimit arr[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*set = cfg;
|
if (!strcmp(level, "soft"))
|
||||||
|
arr[resource].rlim_cur = cfg;
|
||||||
|
else if (!strcmp(level, "hard"))
|
||||||
|
arr[resource].rlim_max = cfg;
|
||||||
|
else if (!strcmp(level, "both"))
|
||||||
|
arr[resource].rlim_max = arr[resource].rlim_cur = cfg;
|
||||||
|
else
|
||||||
|
goto error;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
error:
|
error:
|
||||||
logit(LOG_WARNING, "rlimit: parse error");
|
logit(LOG_WARNING, "rlimit: parse error");
|
||||||
@@ -254,7 +347,7 @@ static void parse_static(char *line)
|
|||||||
char *x;
|
char *x;
|
||||||
char cmd[CMD_SIZE];
|
char cmd[CMD_SIZE];
|
||||||
|
|
||||||
if (BOOTSTRAP && MATCH_CMD(line, "host ", x)) {
|
if (BOOTSTRAP && (MATCH_CMD(line, "host ", x) || MATCH_CMD(line, "hostname ", x))) {
|
||||||
if (hostname) free(hostname);
|
if (hostname) free(hostname);
|
||||||
hostname = strdup(strip_line(x));
|
hostname = strdup(strip_line(x));
|
||||||
return;
|
return;
|
||||||
@@ -295,6 +388,26 @@ static void parse_static(char *line)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (MATCH_CMD(line, "log ", x)) {
|
||||||
|
char *tok;
|
||||||
|
static int size = 200000, count = 5;
|
||||||
|
|
||||||
|
tok = strtok(x, ":= ");
|
||||||
|
while (tok) {
|
||||||
|
if (!strncmp(tok, "size", 4))
|
||||||
|
size = strtobytes(strtok(NULL, ":= "));
|
||||||
|
else if (!strncmp(tok, "count", 5))
|
||||||
|
count = strtobytes(strtok(NULL, ":= "));
|
||||||
|
|
||||||
|
tok = strtok(NULL, ":= ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size >= 0)
|
||||||
|
logfile_size_max = size;
|
||||||
|
if (count >= 0)
|
||||||
|
logfile_count_max = count;
|
||||||
|
}
|
||||||
|
|
||||||
if (MATCH_CMD(line, "shutdown ", x)) {
|
if (MATCH_CMD(line, "shutdown ", x)) {
|
||||||
if (sdown) free(sdown);
|
if (sdown) free(sdown);
|
||||||
sdown = strdup(strip_line(x));
|
sdown = strdup(strip_line(x));
|
||||||
@@ -322,7 +435,6 @@ static void parse_static(char *line)
|
|||||||
static void parse_dynamic(char *line, struct rlimit rlimit[], char *file)
|
static void parse_dynamic(char *line, struct rlimit rlimit[], char *file)
|
||||||
{
|
{
|
||||||
char *x;
|
char *x;
|
||||||
char cmd[CMD_SIZE];
|
|
||||||
|
|
||||||
/* Skip comments, i.e. lines beginning with # */
|
/* Skip comments, i.e. lines beginning with # */
|
||||||
if (MATCH_CMD(line, "#", x))
|
if (MATCH_CMD(line, "#", x))
|
||||||
@@ -330,16 +442,7 @@ static void parse_dynamic(char *line, struct rlimit rlimit[], char *file)
|
|||||||
|
|
||||||
/* Kernel module to load at bootstrap */
|
/* Kernel module to load at bootstrap */
|
||||||
if (MATCH_CMD(line, "module ", x)) {
|
if (MATCH_CMD(line, "module ", x)) {
|
||||||
char *mod;
|
kmod_load(x);
|
||||||
|
|
||||||
if (runlevel != 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
mod = strip_line(x);
|
|
||||||
strcpy(cmd, "modprobe ");
|
|
||||||
strlcat(cmd, mod, sizeof(cmd));
|
|
||||||
run_interactive(cmd, "Loading kernel module %s", mod);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,6 +464,12 @@ static void parse_dynamic(char *line, struct rlimit rlimit[], char *file)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Similar to task but is treated like a SysV init script */
|
||||||
|
if (MATCH_CMD(line, "sysv ", x)) {
|
||||||
|
service_register(SVC_TYPE_SYSV, x, rlimit, file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Classic inetd service */
|
/* Classic inetd service */
|
||||||
if (MATCH_CMD(line, "inetd ", x)) {
|
if (MATCH_CMD(line, "inetd ", x)) {
|
||||||
#ifdef INETD_ENABLED
|
#ifdef INETD_ENABLED
|
||||||
@@ -463,7 +572,8 @@ static int parse_conf(char *file)
|
|||||||
/* Set global limits */
|
/* Set global limits */
|
||||||
for (int i = 0; i < RLIMIT_NLIMITS; i++) {
|
for (int i = 0; i < RLIMIT_NLIMITS; i++) {
|
||||||
if (setrlimit(i, &global_rlimit[i]) == -1)
|
if (setrlimit(i, &global_rlimit[i]) == -1)
|
||||||
logit(LOG_WARNING, "rlimit: Failed setting %s", rlim2str(i));
|
logit(LOG_WARNING, "rlimit: Failed setting %s: %s",
|
||||||
|
rlim2str(i), lim2str(&global_rlimit[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -474,35 +584,38 @@ static int parse_conf(char *file)
|
|||||||
*/
|
*/
|
||||||
int conf_reload(void)
|
int conf_reload(void)
|
||||||
{
|
{
|
||||||
int i, num;
|
size_t i;
|
||||||
struct dirent **e;
|
glob_t gl;
|
||||||
|
|
||||||
/* Mark and sweep */
|
/* Mark and sweep */
|
||||||
svc_mark_dynamic();
|
svc_mark_dynamic();
|
||||||
tty_mark();
|
tty_mark();
|
||||||
|
|
||||||
|
if (rescue) {
|
||||||
|
int rc;
|
||||||
|
char line[80] = "tty [12345] @console noclear nologin";
|
||||||
|
|
||||||
|
/* If rescue.conf is missing, fall back to a root shell */
|
||||||
|
rc = parse_conf(RESCUE_CONF);
|
||||||
|
if (rc)
|
||||||
|
tty_register(line, global_rlimit, NULL);
|
||||||
|
|
||||||
|
print(rc, "Entering rescue mode");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
/* First, read /etc/finit.conf */
|
/* First, read /etc/finit.conf */
|
||||||
parse_conf(FINIT_CONF);
|
parse_conf(FINIT_CONF);
|
||||||
|
|
||||||
/* Next, read all *.conf in /etc/finit.d/ */
|
/* Next, read all *.conf in /etc/finit.d/ */
|
||||||
num = scandir(rcsd, &e, NULL, alphasort);
|
glob("/etc/finit.d/*.conf", 0, NULL, &gl);
|
||||||
if (num < 0) {
|
glob("/etc/finit.d/enabled/*.conf", GLOB_APPEND, NULL, &gl);
|
||||||
_d("Skipping %s, no files found ...", rcsd);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update global limits in case operator used prlimit(1) on us */
|
for (i = 0; i < gl.gl_pathc; i++) {
|
||||||
for (i = 0; i < RLIMIT_NLIMITS; i++)
|
char *path = gl.gl_pathv[i];
|
||||||
getrlimit(i, &global_rlimit[i]);
|
|
||||||
|
|
||||||
for (i = 0; i < num; i++) {
|
|
||||||
char *name = e[i]->d_name;
|
|
||||||
char path[LINE_SIZE];
|
|
||||||
size_t len;
|
size_t len;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
snprintf(path, sizeof(path), "%s/%s", rcsd, name);
|
|
||||||
|
|
||||||
/* 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));
|
_d("Skipping %s, cannot access: %s", path, strerror(errno));
|
||||||
@@ -538,13 +651,16 @@ int conf_reload(void)
|
|||||||
parse_conf_dynamic(path);
|
parse_conf_dynamic(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (num--)
|
globfree(&gl);
|
||||||
free(e[num]);
|
|
||||||
free(e);
|
|
||||||
|
|
||||||
|
done:
|
||||||
/* Drop record of all .conf changes */
|
/* Drop record of all .conf changes */
|
||||||
drop_changes();
|
drop_changes();
|
||||||
|
|
||||||
|
/* Override configured runlevel, user said 'S' on /proc/cmdline */
|
||||||
|
if (BOOTSTRAP && single)
|
||||||
|
cfglevel = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set host name, from %DEFHOST, *.conf or /etc/hostname. The
|
* Set host name, from %DEFHOST, *.conf or /etc/hostname. The
|
||||||
* latter wins, if neither exists we default to "noname"
|
* latter wins, if neither exists we default to "noname"
|
||||||
@@ -589,6 +705,8 @@ static int do_change(char *name, uint32_t mask)
|
|||||||
{
|
{
|
||||||
struct conf_change *node;
|
struct conf_change *node;
|
||||||
|
|
||||||
|
_d("Change detected for %s, mask 0x%08x", name, mask);
|
||||||
|
|
||||||
node = conf_find(name);
|
node = conf_find(name);
|
||||||
if (mask & (IN_DELETE | IN_MOVED_FROM)) {
|
if (mask & (IN_DELETE | IN_MOVED_FROM)) {
|
||||||
drop_change(node);
|
drop_change(node);
|
||||||
@@ -610,16 +728,28 @@ static int do_change(char *name, uint32_t mask)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_d("Event registered for %s, mask 0x%x", name, mask);
|
||||||
TAILQ_INSERT_HEAD(&conf_change_list, node,link);
|
TAILQ_INSERT_HEAD(&conf_change_list, node,link);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int conf_any_change(void)
|
||||||
|
{
|
||||||
|
if (TAILQ_EMPTY(&conf_change_list))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int conf_changed(char *file)
|
int conf_changed(char *file)
|
||||||
{
|
{
|
||||||
char *ptr;
|
char *ptr;
|
||||||
|
|
||||||
if (file && (ptr = strrchr(file, '/')))
|
if (!file)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if ((ptr = strrchr(file, '/')))
|
||||||
file = ++ptr;
|
file = ++ptr;
|
||||||
|
|
||||||
if (conf_find(file))
|
if (conf_find(file))
|
||||||
@@ -654,6 +784,11 @@ static void conf_cb(uev_t *w, void *arg, int events)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_AUTO_RELOAD
|
||||||
|
if (conf_any_change())
|
||||||
|
service_reload_dynamic();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_watcher(uev_ctx_t *ctx, uev_t *w, char *path, uint32_t opt)
|
static int add_watcher(uev_ctx_t *ctx, uev_t *w, char *path, uint32_t opt)
|
||||||
@@ -706,6 +841,7 @@ static int add_watcher(uev_ctx_t *ctx, uev_t *w, char *path, uint32_t opt)
|
|||||||
close(fd);
|
close(fd);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
_d("Set up inotify watcher for %s ...", path);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -717,6 +853,10 @@ int conf_monitor(uev_ctx_t *ctx)
|
|||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
|
/* Skip second run, when called from finit.c in rescue mode */
|
||||||
|
if (ctx && rescue)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If only one watcher fails, that's OK. A user may have only
|
* If only one watcher fails, that's OK. A user may have only
|
||||||
* one of /etc/finit.conf or /etc/finit.d in use, and may also
|
* one of /etc/finit.conf or /etc/finit.d in use, and may also
|
||||||
@@ -724,8 +864,9 @@ int conf_monitor(uev_ctx_t *ctx)
|
|||||||
* changes to either symlink or target.
|
* changes to either symlink or target.
|
||||||
*/
|
*/
|
||||||
rc += add_watcher(ctx, &w1, FINIT_RCSD, 0);
|
rc += add_watcher(ctx, &w1, FINIT_RCSD, 0);
|
||||||
rc += add_watcher(ctx, &w2, FINIT_RCSD "/available", IN_DONT_FOLLOW);
|
rc += add_watcher(ctx, &w2, FINIT_RCSD "/available/", IN_DONT_FOLLOW);
|
||||||
rc += add_watcher(ctx, &w3, FINIT_CONF, 0);
|
rc += add_watcher(ctx, &w3, FINIT_RCSD "/enabled/", 0);
|
||||||
|
rc += add_watcher(ctx, &w4, FINIT_CONF, 0);
|
||||||
|
|
||||||
return rc + conf_reload();
|
return rc + conf_reload();
|
||||||
}
|
}
|
||||||
@@ -736,7 +877,7 @@ int conf_monitor(uev_ctx_t *ctx)
|
|||||||
int conf_init(void)
|
int conf_init(void)
|
||||||
{
|
{
|
||||||
hostname = strdup(DEFHOST);
|
hostname = strdup(DEFHOST);
|
||||||
w1.fd = w2.fd = w3.fd = -1;
|
w1.fd = w2.fd = w3.fd = w4.fd = -1;
|
||||||
|
|
||||||
return conf_monitor(NULL);
|
return conf_monitor(NULL);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,9 @@
|
|||||||
|
|
||||||
#include "svc.h"
|
#include "svc.h"
|
||||||
|
|
||||||
|
extern int logfile_size_max;
|
||||||
|
extern int logfile_count_max;
|
||||||
|
|
||||||
extern struct rlimit global_rlimit[];
|
extern struct rlimit global_rlimit[];
|
||||||
|
|
||||||
int str2rlim(char *str);
|
int str2rlim(char *str);
|
||||||
@@ -33,6 +36,7 @@ char *rlim2str(int rlim);
|
|||||||
|
|
||||||
int conf_init (void);
|
int conf_init (void);
|
||||||
void conf_reload (void);
|
void conf_reload (void);
|
||||||
|
int conf_any_change (void);
|
||||||
int conf_changed (char *file);
|
int conf_changed (char *file);
|
||||||
int conf_monitor (uev_ctx_t *ctx);
|
int conf_monitor (uev_ctx_t *ctx);
|
||||||
|
|
||||||
|
|||||||
+51
-32
@@ -231,6 +231,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);
|
||||||
|
|
||||||
return execvp(_PATH_BSHELL, argv);
|
return execvp(_PATH_BSHELL, argv);
|
||||||
}
|
}
|
||||||
@@ -239,6 +240,7 @@ static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit
|
|||||||
{
|
{
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
struct termios term;
|
struct termios term;
|
||||||
|
char name[80];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reset to sane defaults in case of messup from prev. session
|
* Reset to sane defaults in case of messup from prev. session
|
||||||
@@ -282,13 +284,16 @@ static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit
|
|||||||
|
|
||||||
/* Finit is responsible for the UTMP INIT_PROCESS record */
|
/* Finit is responsible for the UTMP INIT_PROCESS record */
|
||||||
utmp_set_init(tty, 0);
|
utmp_set_init(tty, 0);
|
||||||
prctl(PR_SET_NAME, procname, 0, 0, 0);
|
if (!strncmp("/dev/", tty, 5))
|
||||||
|
tty += 5;
|
||||||
|
snprintf(name, sizeof(name), "%s %s", procname, tty);
|
||||||
|
prctl(PR_SET_NAME, name, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int activate_console(int noclear, int nowait)
|
static int activate_console(int noclear, int nowait)
|
||||||
{
|
{
|
||||||
|
struct termios orig;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct termios term;
|
|
||||||
|
|
||||||
if (!noclear)
|
if (!noclear)
|
||||||
(void)write(STDERR_FILENO, "\e[r\e[H\e[J", 9);
|
(void)write(STDERR_FILENO, "\e[r\e[H\e[J", 9);
|
||||||
@@ -297,15 +302,20 @@ static int activate_console(int noclear, int nowait)
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* Disable ECHO, XON/OFF while waiting for <CR> */
|
/* Disable ECHO, XON/OFF while waiting for <CR> */
|
||||||
if (!tcgetattr(STDIN_FILENO, &term)) {
|
if (!tcgetattr(STDIN_FILENO, &orig)) {
|
||||||
term.c_iflag &= ~(IXON|IXOFF);
|
struct termios c = orig;
|
||||||
term.c_lflag &= ~ECHO;
|
|
||||||
tcsetattr(STDIN_FILENO, TCSANOW, &term);
|
c.c_iflag &= ~(BRKINT|ICRNL|INPCK|ISTRIP|IXON|IXOFF);
|
||||||
|
c.c_oflag &= ~(OPOST);
|
||||||
|
c.c_cflag |= (CS8);
|
||||||
|
c.c_lflag &= ~(ECHO|ICANON|IEXTEN|ISIG);
|
||||||
|
tcsetattr(STDIN_FILENO, TCSANOW, &c);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!fexist(SYNC_SHUTDOWN)) {
|
while (!fexist(SYNC_SHUTDOWN)) {
|
||||||
char c;
|
char c;
|
||||||
static const char clr[] = "\r\e[2K";
|
static const char clr[] = "\r\e[2K";
|
||||||
|
static const char cup[] = "\e[A";
|
||||||
static const char msg[] = "\nPlease press Enter to activate this console.";
|
static const char msg[] = "\nPlease press Enter to activate this console.";
|
||||||
|
|
||||||
if (fexist(SYNC_STOPPED)) {
|
if (fexist(SYNC_STOPPED)) {
|
||||||
@@ -315,23 +325,21 @@ static int activate_console(int noclear, int nowait)
|
|||||||
|
|
||||||
(void)write(STDERR_FILENO, clr, strlen(clr));
|
(void)write(STDERR_FILENO, clr, strlen(clr));
|
||||||
(void)write(STDERR_FILENO, msg, strlen(msg));
|
(void)write(STDERR_FILENO, msg, strlen(msg));
|
||||||
while (read(STDIN_FILENO, &c, 1) == 1 && c != '\n')
|
while (read(STDIN_FILENO, &c, 1) == 1 && c != '\r')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (fexist(SYNC_STOPPED))
|
if (fexist(SYNC_STOPPED))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
(void)write(STDERR_FILENO, clr, strlen(clr));
|
(void)write(STDERR_FILENO, clr, strlen(clr));
|
||||||
|
(void)write(STDERR_FILENO, cup, strlen(cup));
|
||||||
ret = 1;
|
ret = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Restore ECHO, XON/OFF */
|
/* Restore TTY */
|
||||||
if (!tcgetattr(STDIN_FILENO, &term)) {
|
if (tcsetattr(STDIN_FILENO, TCSANOW, &orig) == -1)
|
||||||
term.c_iflag |= IXON|IXOFF;
|
ret = 0;
|
||||||
term.c_lflag |= ECHO;
|
|
||||||
tcsetattr(STDIN_FILENO, TCSANOW, &term);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -363,13 +371,13 @@ pid_t run_getty(char *tty, char *baud, char *term, int noclear, int nowait, stru
|
|||||||
if (!pid) {
|
if (!pid) {
|
||||||
speed_t speed = B38400;
|
speed_t speed = B38400;
|
||||||
|
|
||||||
if (baud) {
|
if (baud && baud[0]) {
|
||||||
speed = stty_parse_speed(baud);
|
speed = stty_parse_speed(baud);
|
||||||
if (B0 == speed)
|
if (B0 == speed)
|
||||||
logit(LOG_CRIT, "TTY %s: Invalid speed %s", tty, baud);
|
logit(LOG_CRIT, "TTY %s: Invalid speed %s", tty, baud);
|
||||||
}
|
}
|
||||||
|
|
||||||
prepare_tty(tty, speed, "finit-getty", rlimit);
|
prepare_tty(tty, speed, "tty", rlimit);
|
||||||
if (activate_console(noclear, nowait))
|
if (activate_console(noclear, nowait))
|
||||||
_exit(getty(tty, speed, term, NULL));
|
_exit(getty(tty, speed, term, NULL));
|
||||||
}
|
}
|
||||||
@@ -423,6 +431,20 @@ pid_t run_getty2(char *tty, char *cmd, char *args[], int noclear, int nowait, st
|
|||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pid_t run_sh(char *tty, int noclear, int nowait, struct rlimit rlimit[])
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
pid = fork();
|
||||||
|
if (!pid) {
|
||||||
|
prepare_tty(tty, B0, "finit-sh", rlimit);
|
||||||
|
if (activate_console(noclear, nowait))
|
||||||
|
_exit(sh(tty));
|
||||||
|
}
|
||||||
|
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
|
||||||
int run_parts(char *dir, char *cmd)
|
int run_parts(char *dir, char *cmd)
|
||||||
{
|
{
|
||||||
struct dirent **e;
|
struct dirent **e;
|
||||||
@@ -435,12 +457,16 @@ int run_parts(char *dir, char *cmd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < num; i++) {
|
for (i = 0; i < num; i++) {
|
||||||
int j = 0;
|
|
||||||
pid_t pid = 0;
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
char *args[NUM_ARGS];
|
char path[512];
|
||||||
|
char *argv[4] = {
|
||||||
|
"sh",
|
||||||
|
"-c",
|
||||||
|
path,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
char *name = e[i]->d_name;
|
char *name = e[i]->d_name;
|
||||||
char path[LINE_SIZE];
|
pid_t pid = 0;
|
||||||
|
|
||||||
snprintf(path, sizeof(path), "%s/%s", dir, name);
|
snprintf(path, sizeof(path), "%s/%s", dir, name);
|
||||||
if (stat(path, &st)) {
|
if (stat(path, &st)) {
|
||||||
@@ -453,29 +479,22 @@ int run_parts(char *dir, char *cmd)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill in args[], starting with full path to executable */
|
|
||||||
args[j++] = path;
|
|
||||||
|
|
||||||
/* 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);
|
_d("Checking if %s is a sysvinit startstop script ...", name);
|
||||||
if (name[0] == 'S' && isdigit(name[1])) {
|
if (name[0] == 'S' && isdigit(name[1]))
|
||||||
args[j++] = "start";
|
strlcat(path, " start", sizeof(path));
|
||||||
} else if (name[0] == 'K' && isdigit(name[1])) {
|
else if (name[0] == 'K' && isdigit(name[1]))
|
||||||
args[j++] = "stop";
|
strlcat(path, " stop", sizeof(path));
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
args[j++] = cmd;
|
strlcat(path, cmd, sizeof(path));
|
||||||
}
|
}
|
||||||
args[j++] = NULL;
|
|
||||||
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
_d("Calling %s ...", path);
|
|
||||||
sig_unblock();
|
sig_unblock();
|
||||||
execv(path, args);
|
return execvp(_PATH_BSHELL, argv);
|
||||||
exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
complete(path, pid);
|
complete(path, pid);
|
||||||
|
|||||||
+212
-183
@@ -36,6 +36,7 @@
|
|||||||
#include <lite/lite.h>
|
#include <lite/lite.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
|
#include "cgroup.h"
|
||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
@@ -47,12 +48,14 @@
|
|||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "utmp-api.h"
|
#include "utmp-api.h"
|
||||||
#include "watchdog.h"
|
#include "schedule.h"
|
||||||
|
|
||||||
int wdogpid = 0; /* No watchdog by default */
|
|
||||||
int runlevel = 0; /* Bootstrap 'S' */
|
int runlevel = 0; /* Bootstrap 'S' */
|
||||||
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
|
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
|
||||||
int prevlevel = -1;
|
int prevlevel = -1;
|
||||||
|
int rescue = 0; /* rescue mode from kernel cmdline */
|
||||||
|
int single = 0; /* single user mode from kernel cmdline */
|
||||||
|
int splash = 0; /* splash + progress enabled on kernel cmdline */
|
||||||
char *sdown = NULL;
|
char *sdown = NULL;
|
||||||
char *network = NULL;
|
char *network = NULL;
|
||||||
char *hostname = NULL;
|
char *hostname = NULL;
|
||||||
@@ -60,15 +63,16 @@ char *rcsd = FINIT_RCSD;
|
|||||||
char *runparts = NULL;
|
char *runparts = NULL;
|
||||||
|
|
||||||
uev_ctx_t *ctx = NULL; /* Main loop context */
|
uev_ctx_t *ctx = NULL; /* Main loop context */
|
||||||
|
svc_t *wdog = NULL; /* No watchdog by default */
|
||||||
|
|
||||||
|
static int udev = 0; /* Runtime detection of udev */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Show user configured banner before service bootstrap progress
|
* Show user configured banner before service bootstrap progress
|
||||||
*/
|
*/
|
||||||
static void banner(void)
|
static void banner(void)
|
||||||
{
|
{
|
||||||
char *buf = INIT_HEADING;
|
|
||||||
char separator[SCREEN_WIDTH];
|
|
||||||
|
|
||||||
if (plugin_exists(HOOK_BANNER)) {
|
if (plugin_exists(HOOK_BANNER)) {
|
||||||
plugin_run_hooks(HOOK_BANNER);
|
plugin_run_hooks(HOOK_BANNER);
|
||||||
return;
|
return;
|
||||||
@@ -77,18 +81,16 @@ static void banner(void)
|
|||||||
if (log_is_silent())
|
if (log_is_silent())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
memset(separator, '=', sizeof(separator));
|
print_banner(INIT_HEADING);
|
||||||
fprintf(stderr, "\e[2K\e[1m%s %.*s\e[0m\n", buf, SCREEN_WIDTH - (int)strlen(buf) - 2, separator);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Requires /proc to be mounted */
|
static int ismnt(char *file, char *dir)
|
||||||
static int fismnt(char *dir)
|
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
int found = 0;
|
int found = 0;
|
||||||
struct mntent *mnt;
|
struct mntent *mnt;
|
||||||
|
|
||||||
fp = setmntent("/proc/mounts", "r");
|
fp = setmntent(file, "r");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return 0; /* Dunno, maybe not */
|
return 0; /* Dunno, maybe not */
|
||||||
|
|
||||||
@@ -103,6 +105,12 @@ static int fismnt(char *dir)
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Requires /proc to be mounted */
|
||||||
|
static int fismnt(char *dir)
|
||||||
|
{
|
||||||
|
return ismnt("/proc/mounts", dir);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check all filesystems in /etc/fstab with a fs_passno > 0
|
* Check all filesystems in /etc/fstab with a fs_passno > 0
|
||||||
*/
|
*/
|
||||||
@@ -150,54 +158,6 @@ static int fsck(int pass)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void networking(void)
|
|
||||||
{
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
/* Run user network start script if enabled */
|
|
||||||
if (network) {
|
|
||||||
run_interactive(network, "Starting networking: %s", network);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Debian/Ubuntu/Busybox/RH/Suse */
|
|
||||||
if (!whichp("ifup"))
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
fp = fopen("/etc/network/interfaces", "r");
|
|
||||||
if (fp) {
|
|
||||||
int i = 0;
|
|
||||||
char buf[160];
|
|
||||||
|
|
||||||
/* Bring up all 'auto' interfaces */
|
|
||||||
while (fgets(buf, sizeof(buf), fp)) {
|
|
||||||
char cmd[80];
|
|
||||||
char *line, *ifname = NULL;
|
|
||||||
|
|
||||||
chomp(buf);
|
|
||||||
line = strip_line(buf);
|
|
||||||
|
|
||||||
if (!strncmp(line, "auto", 4))
|
|
||||||
ifname = &line[5];
|
|
||||||
if (!strncmp(line, "allow-hotplug", 13))
|
|
||||||
ifname = &line[14];
|
|
||||||
|
|
||||||
if (!ifname)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
snprintf(cmd, 80, "ifup %s", ifname);
|
|
||||||
run_interactive(cmd, "Bringing up interface %s", ifname);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
/* Fall back to bring up at least loopback */
|
|
||||||
ifconfig("lo", "127.0.0.1", "255.0.0.0", 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If everything goes south we can use this to give the operator an
|
* If everything goes south we can use this to give the operator an
|
||||||
* emergency shell to debug the problem -- Finit should not crash!
|
* emergency shell to debug the problem -- Finit should not crash!
|
||||||
@@ -227,7 +187,7 @@ static void emergency_shell(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "\n=> Embarrassingly, Finit has crashed. Check /dev/kmsg for details.\n");
|
fprintf(stderr, "\n=> Embarrassingly, Finit has crashed. Check /dev/kmsg for details.\n");
|
||||||
fprintf(stderr, "=> To debug, add '--debug' to the kernel command line.\n\n");
|
fprintf(stderr, "=> To debug, add 'debug' to the kernel command line.\n\n");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Become session leader and set controlling TTY
|
* Become session leader and set controlling TTY
|
||||||
@@ -254,16 +214,20 @@ static void emergency_shell(void)
|
|||||||
*/
|
*/
|
||||||
static void finalize(void)
|
static void finalize(void)
|
||||||
{
|
{
|
||||||
/*
|
svc_t *svc;
|
||||||
* Network stuff
|
|
||||||
*/
|
|
||||||
_d("Setting up networking ...");
|
|
||||||
networking();
|
|
||||||
umask(022);
|
|
||||||
|
|
||||||
/* Hooks that rely on loopback, or basic networking being up. */
|
/*
|
||||||
_d("Calling all network up hooks ...");
|
* Track bundled watchdogd in case a better one turns up
|
||||||
plugin_run_hooks(HOOK_NETWORK_UP);
|
*/
|
||||||
|
svc = svc_find(FINIT_LIBPATH_ "/watchdogd", "1");
|
||||||
|
if (svc)
|
||||||
|
wdog = svc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Run startup scripts in the runparts directory, if any.
|
||||||
|
*/
|
||||||
|
if (runparts && fisdir(runparts) && !rescue)
|
||||||
|
run_parts(runparts, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Start all tasks/services in the configured runlevel
|
* Start all tasks/services in the configured runlevel
|
||||||
@@ -280,20 +244,9 @@ static void finalize(void)
|
|||||||
plugin_run_hooks(HOOK_SVC_UP);
|
plugin_run_hooks(HOOK_SVC_UP);
|
||||||
service_step_all(SVC_TYPE_ANY);
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
|
||||||
/*
|
|
||||||
* Run startup scripts in the runparts directory, if any.
|
|
||||||
*/
|
|
||||||
if (runparts && fisdir(runparts)) {
|
|
||||||
_d("Running startup scripts in %s ...", runparts);
|
|
||||||
run_parts(runparts, NULL);
|
|
||||||
service_reload_dynamic();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Convenient SysV compat for when you just don't care ... */
|
/* Convenient SysV compat for when you just don't care ... */
|
||||||
if (!access(FINIT_RC_LOCAL, X_OK)) {
|
if (!access(FINIT_RC_LOCAL, X_OK) && !rescue)
|
||||||
run_interactive(FINIT_RC_LOCAL, "Calling %s", FINIT_RC_LOCAL);
|
run_interactive(FINIT_RC_LOCAL, "Calling %s", FINIT_RC_LOCAL);
|
||||||
service_reload_dynamic();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hooks that should run at the very end */
|
/* Hooks that should run at the very end */
|
||||||
_d("Calling all system up hooks ...");
|
_d("Calling all system up hooks ...");
|
||||||
@@ -309,13 +262,61 @@ static void finalize(void)
|
|||||||
tty_runlevel();
|
tty_runlevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
/*
|
||||||
|
* Start cranking the big state machine
|
||||||
|
*/
|
||||||
|
static void crank_worker(void *unused)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* Initalize state machine and start all bootstrap tasks
|
||||||
|
* NOTE: no network available!
|
||||||
|
*/
|
||||||
|
sm_init(&sm);
|
||||||
|
sm_step(&sm);
|
||||||
|
|
||||||
|
/* Debian has this little script to copy generated rules while the system was read-only */
|
||||||
|
if (udev && fexist("/lib/udev/udev-finish"))
|
||||||
|
run_interactive("/lib/udev/udev-finish", "Finalizing udev");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wait for system bootstrap to complete, all SVC_TYPE_RUNTASK must be
|
||||||
|
* allowed to complete their work in [S], or timeout, before we call
|
||||||
|
* finalize(), should not take more than 120 sec.
|
||||||
|
*/
|
||||||
|
static void final_worker(void *work)
|
||||||
|
{
|
||||||
|
static int cnt = 120;
|
||||||
|
|
||||||
|
_d("Step all services ...");
|
||||||
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
|
||||||
|
if (cnt-- > 0 && !service_completed()) {
|
||||||
|
_d("Not all bootstrap run/tasks have completed yet ... %d", cnt);
|
||||||
|
schedule_work(work);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cnt > 0)
|
||||||
|
_d("All run/task have completed, resuming bootstrap.");
|
||||||
|
else
|
||||||
|
_d("Timeout, resuming bootstrap.");
|
||||||
|
|
||||||
|
finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct wq crank = {
|
||||||
|
.cb = crank_worker
|
||||||
|
};
|
||||||
|
struct wq final = {
|
||||||
|
.cb = final_worker,
|
||||||
|
.delay = 1000
|
||||||
|
};
|
||||||
|
uev_ctx_t loop;
|
||||||
char *path;
|
char *path;
|
||||||
char cmd[256];
|
char cmd[256];
|
||||||
int udev = 0;
|
|
||||||
uev_t timer; /* Bootstrap timer, on timeout call finalize() */
|
|
||||||
uev_ctx_t loop;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* finit/init/telinit client tool uses /dev/initctl pipe
|
* finit/init/telinit client tool uses /dev/initctl pipe
|
||||||
@@ -324,8 +325,57 @@ int main(int argc, char* argv[])
|
|||||||
if (getpid() != 1)
|
if (getpid() != 1)
|
||||||
return client(argc, argv);
|
return client(argc, argv);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hide command line arguments from ps (in particular for
|
||||||
|
* forked children that don't execv()). This is an ugly
|
||||||
|
* hack that only works on Linux.
|
||||||
|
* https://web.archive.org/web/20110227041321/http://netsplit.com/2007/01/10/hiding-arguments-from-ps/
|
||||||
|
*/
|
||||||
|
if (argc > 1) {
|
||||||
|
char *arg_end;
|
||||||
|
|
||||||
|
arg_end = argv[argc-1] + strlen (argv[argc-1]);
|
||||||
|
*arg_end = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initalize event context.
|
||||||
|
*/
|
||||||
|
uev_init1(&loop, 1);
|
||||||
|
ctx = &loop;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set PATH and SHELL early to something sane
|
||||||
|
*/
|
||||||
|
setenv("PATH", _PATH_STDPATH, 1);
|
||||||
|
setenv("SHELL", _PATH_BSHELL, 1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mount base file system, kernel is assumed to run devtmpfs for /dev
|
||||||
|
*/
|
||||||
|
chdir("/");
|
||||||
|
umask(0);
|
||||||
|
if (mount("none", "/proc", "proc", 0, NULL))
|
||||||
|
_pe("Failed mounting /proc");
|
||||||
|
if (mount("none", "/sys", "sysfs", 0, NULL))
|
||||||
|
_pe("Failed mounting /sysfs");
|
||||||
|
if (fisdir("/proc/bus/usb"))
|
||||||
|
mount("none", "/proc/bus/usb", "usbfs", 0, NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize default control groups, if available
|
||||||
|
*/
|
||||||
|
cgroup_init();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse kernel command line (debug, rescue, splash, etc.)
|
||||||
|
* Also calls log_init() to set correct log level
|
||||||
|
*/
|
||||||
|
conf_parse_cmdline();
|
||||||
|
|
||||||
/* Set up canvas */
|
/* Set up canvas */
|
||||||
screen_init();
|
if (!rescue && !log_is_debug())
|
||||||
|
screen_init();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In case of emergency.
|
* In case of emergency.
|
||||||
@@ -337,37 +387,11 @@ int main(int argc, char* argv[])
|
|||||||
*/
|
*/
|
||||||
sig_init();
|
sig_init();
|
||||||
|
|
||||||
/*
|
|
||||||
* Initalize event context.
|
|
||||||
*/
|
|
||||||
uev_init(&loop);
|
|
||||||
ctx = &loop;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set the PATH early to something sane
|
|
||||||
*/
|
|
||||||
setenv("PATH", _PATH_STDPATH, 1);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Mount base file system, kernel is assumed to run devtmpfs for /dev
|
|
||||||
*/
|
|
||||||
chdir("/");
|
|
||||||
umask(0);
|
|
||||||
mount("none", "/proc", "proc", 0, NULL);
|
|
||||||
mount("none", "/sys", "sysfs", 0, NULL);
|
|
||||||
if (fisdir("/proc/bus/usb"))
|
|
||||||
mount("none", "/proc/bus/usb", "usbfs", 0, NULL);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Parse kernel parameters, including log_init()
|
|
||||||
*/
|
|
||||||
conf_parse_cmdline();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Load plugins early, finit.conf may contain references to
|
* Load plugins early, finit.conf may contain references to
|
||||||
* features implemented by plugins.
|
* features implemented by plugins.
|
||||||
*/
|
*/
|
||||||
plugin_init(&loop, PLUGIN_PATH);
|
plugin_init(&loop);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hello world.
|
* Hello world.
|
||||||
@@ -377,11 +401,17 @@ int main(int argc, char* argv[])
|
|||||||
/*
|
/*
|
||||||
* Check file filesystems in /etc/fstab
|
* Check file filesystems in /etc/fstab
|
||||||
*/
|
*/
|
||||||
for (int pass = 1; pass < 10; pass++) {
|
for (int pass = 1; pass < 10 && !rescue; pass++) {
|
||||||
if (fsck(pass))
|
if (fsck(pass))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize .conf system and load static /etc/finit.conf
|
||||||
|
* Also initializes global_rlimit[] for udevd, below.
|
||||||
|
*/
|
||||||
|
conf_init();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some non-embedded systems without an initramfs may not have /dev mounted yet
|
* Some non-embedded systems without an initramfs may not have /dev mounted yet
|
||||||
* If they do, check if system has udevadm and perform cleanup from initramfs
|
* If they do, check if system has udevadm and perform cleanup from initramfs
|
||||||
@@ -395,8 +425,15 @@ int main(int argc, char* argv[])
|
|||||||
makedir("/dev/pts", 0755);
|
makedir("/dev/pts", 0755);
|
||||||
mount("devpts", "/dev/pts", "devpts", 0, "gid=5,mode=620");
|
mount("devpts", "/dev/pts", "devpts", 0, "gid=5,mode=620");
|
||||||
|
|
||||||
/* Some systems rely on /dev/shm being there, for `mount -a` below */
|
/*
|
||||||
|
* Some systems rely on us to both create /dev/shm and, to mount
|
||||||
|
* a tmpfs there. Any system with dbus needs shared memory, so
|
||||||
|
* mount it, unless its already mounted, but not if listed in
|
||||||
|
* the /etc/fstab file already.
|
||||||
|
*/
|
||||||
makedir("/dev/shm", 0755);
|
makedir("/dev/shm", 0755);
|
||||||
|
if (!fismnt("/dev/shm") && !ismnt("/etc/fstab", "/dev/shm"))
|
||||||
|
mount("shm", "/dev/shm", "tmpfs", 0, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* New tmpfs based /run for volatile runtime data
|
* New tmpfs based /run for volatile runtime data
|
||||||
@@ -406,118 +443,110 @@ int main(int argc, char* argv[])
|
|||||||
mount("tmpfs", "/run", "tmpfs", MS_NODEV, "mode=0755,size=10%");
|
mount("tmpfs", "/run", "tmpfs", MS_NODEV, "mode=0755,size=10%");
|
||||||
umask(022);
|
umask(022);
|
||||||
|
|
||||||
|
/* Bootstrap conditions, needed for hooks */
|
||||||
|
cond_init();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Populate /dev and prepare for runtime events from kernel.
|
* Populate /dev and prepare for runtime events from kernel.
|
||||||
|
* Prefer udev if mdev is also available on the system.
|
||||||
*/
|
*/
|
||||||
path = which("mdev");
|
path = which("udevd");
|
||||||
|
if (!path)
|
||||||
|
path = which("/lib/systemd/systemd-udevd");
|
||||||
if (path) {
|
if (path) {
|
||||||
/* Embedded Linux systems usually have BusyBox mdev */
|
|
||||||
if (log_is_debug())
|
|
||||||
touch("/dev/mdev.log");
|
|
||||||
|
|
||||||
snprintf(cmd, sizeof(cmd), "%s -s", path);
|
|
||||||
} else {
|
|
||||||
/* Desktop and server distros usually have a variant of udev */
|
/* Desktop and server distros usually have a variant of udev */
|
||||||
path = which("udevd");
|
udev = 1;
|
||||||
if (!path)
|
|
||||||
path = which("/lib/systemd/systemd-udevd");
|
|
||||||
if (path) {
|
|
||||||
udev = 1;
|
|
||||||
|
|
||||||
/* Register udevd as a monitored service, started much later */
|
/* Register udevd as a monitored service */
|
||||||
snprintf(cmd, sizeof(cmd), "[12345] %s -- Device event manager daemon", path);
|
snprintf(cmd, sizeof(cmd), "[S12345789] pid:udevd %s -- Device event managing daemon", path);
|
||||||
if (service_register(SVC_TYPE_SERVICE, cmd, global_rlimit, NULL)) {
|
if (service_register(SVC_TYPE_SERVICE, cmd, global_rlimit, NULL)) {
|
||||||
_pe("Failed registering %s", path);
|
_pe("Failed registering %s", path);
|
||||||
udev = 0;
|
udev = 0;
|
||||||
}
|
} else {
|
||||||
|
snprintf(cmd, sizeof(cmd), ":1 [S] <svc%s> "
|
||||||
|
"udevadm trigger -c add -t devices "
|
||||||
|
"-- Requesting device events", path);
|
||||||
|
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
||||||
|
|
||||||
/* Start a temporary udevd instance to populate /dev */
|
snprintf(cmd, sizeof(cmd), ":2 [S] <svc%s> "
|
||||||
snprintf(cmd, sizeof(cmd), "%s --daemon", path);
|
"udevadm trigger -c add -t subsystems "
|
||||||
|
"-- Requesting subsystem events", path);
|
||||||
|
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (path) {
|
|
||||||
free(path);
|
free(path);
|
||||||
|
} else {
|
||||||
|
path = which("mdev");
|
||||||
|
if (path) {
|
||||||
|
/* Embedded Linux systems usually have BusyBox mdev */
|
||||||
|
if (log_is_debug())
|
||||||
|
touch("/dev/mdev.log");
|
||||||
|
|
||||||
run_interactive(cmd, "Populating device tree");
|
snprintf(cmd, sizeof(cmd), "%s -s", path);
|
||||||
if (udev && whichp("udevadm")) {
|
free(path);
|
||||||
run("udevadm trigger --action=add --type=subsystems");
|
|
||||||
run("udevadm trigger --action=add --type=devices");
|
|
||||||
run("udevadm settle --timeout=120");
|
|
||||||
|
|
||||||
/* Tell temporary udevd to exit, we'll start a monitored instance later */
|
run_interactive(cmd, "Populating device tree");
|
||||||
run("udevadm control --exit");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize .conf system and load static /etc/finit.conf
|
* Start bundled watchdogd as soon as possible, if enabled
|
||||||
*/
|
*/
|
||||||
conf_init();
|
if (which(FINIT_LIBPATH_ "/watchdogd"))
|
||||||
|
service_register(SVC_TYPE_SERVICE, FINIT_LIBPATH_ "/watchdogd", global_rlimit, NULL);
|
||||||
/*
|
|
||||||
* Start built-in watchdog as soon as possible, if enabled
|
|
||||||
*/
|
|
||||||
wdogpid = watchdog(argv[0]);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mount filesystems
|
* Mount filesystems
|
||||||
*/
|
*/
|
||||||
|
if (!rescue) {
|
||||||
#ifdef REMOUNT_ROOTFS
|
#ifdef REMOUNT_ROOTFS
|
||||||
run("mount -n -o remount,rw /");
|
run("mount -n -o remount,rw /");
|
||||||
#endif
|
#endif
|
||||||
#ifdef SYSROOT
|
#ifdef SYSROOT
|
||||||
mount(SYSROOT, "/", NULL, MS_MOVE, NULL);
|
mount(SYSROOT, "/", NULL, MS_MOVE, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* Debian has this little script to copy generated rules while the system was read-only */
|
if (!rescue) {
|
||||||
if (fexist("/lib/udev/udev-finish"))
|
_d("Root FS up, calling hooks ...");
|
||||||
run_interactive("/lib/udev/udev-finish", "Finalizing udev");
|
plugin_run_hooks(HOOK_ROOTFS_UP);
|
||||||
|
|
||||||
/* Bootstrap conditions, needed for hooks */
|
umask(0);
|
||||||
cond_init();
|
if (run_interactive("mount -na", "Mounting filesystems"))
|
||||||
|
plugin_run_hooks(HOOK_MOUNT_ERROR);
|
||||||
|
|
||||||
_d("Root FS up, calling hooks ...");
|
_d("Calling extra mount hook, after mount -a ...");
|
||||||
plugin_run_hooks(HOOK_ROOTFS_UP);
|
plugin_run_hooks(HOOK_MOUNT_POST);
|
||||||
|
|
||||||
umask(0);
|
run("swapon -ea");
|
||||||
if (run_interactive("mount -na", "Mounting filesystems"))
|
umask(0022);
|
||||||
plugin_run_hooks(HOOK_MOUNT_ERROR);
|
}
|
||||||
|
|
||||||
run("swapon -ea");
|
|
||||||
umask(0022);
|
|
||||||
|
|
||||||
/* Base FS up, enable standard SysV init signals */
|
/* Base FS up, enable standard SysV init signals */
|
||||||
sig_setup(&loop);
|
sig_setup(&loop);
|
||||||
|
|
||||||
|
if (!rescue) {
|
||||||
|
_d("Base FS up, calling hooks ...");
|
||||||
|
plugin_run_hooks(HOOK_BASEFS_UP);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up inotify watcher for /etc/finit.d and read all .conf
|
* Set up inotify watcher for /etc/finit.d and read all .conf
|
||||||
* files to figure out how to bootstrap the system.
|
* files to figure out how to bootstrap the system.
|
||||||
*/
|
*/
|
||||||
conf_monitor(&loop);
|
conf_monitor(&loop);
|
||||||
|
|
||||||
_d("Base FS up, calling hooks ...");
|
_d("Starting initctl API responder ...");
|
||||||
plugin_run_hooks(HOOK_BASEFS_UP);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initalize state machine and start all bootstrap tasks
|
|
||||||
* NOTE: no network available!
|
|
||||||
*/
|
|
||||||
sm_init(&sm);
|
|
||||||
sm_step(&sm);
|
|
||||||
|
|
||||||
/* Start new initctl API responder */
|
|
||||||
api_init(&loop);
|
api_init(&loop);
|
||||||
|
umask(022);
|
||||||
|
|
||||||
|
_d("Starting the big state machine ...");
|
||||||
|
schedule_work(&crank);
|
||||||
|
|
||||||
/*
|
|
||||||
* Wait for all SVC_TYPE_RUNTASK to have completed their work in
|
|
||||||
* [S], or timeout, before calling finalize()
|
|
||||||
*/
|
|
||||||
_d("Starting bootstrap finalize timer ...");
|
_d("Starting bootstrap finalize timer ...");
|
||||||
uev_timer_init(&loop, &timer, service_bootstrap_cb, finalize, 1000, 1000);
|
schedule_work(&final);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enter main loop to monior /dev/initctl and services
|
* Enter main loop to monitor /dev/initctl and services
|
||||||
*/
|
*/
|
||||||
_d("Entering main loop ...");
|
_d("Entering main loop ...");
|
||||||
return uev_run(&loop, 0);
|
return uev_run(&loop, 0);
|
||||||
|
|||||||
+5
-3
@@ -45,7 +45,6 @@
|
|||||||
#define _PATH_VARRUN "/var/run/"
|
#define _PATH_VARRUN "/var/run/"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define CMD_SIZE 256
|
#define CMD_SIZE 256
|
||||||
#define LINE_SIZE 1024
|
#define LINE_SIZE 1024
|
||||||
#define BUF_SIZE 4096
|
#define BUF_SIZE 4096
|
||||||
@@ -75,7 +74,7 @@
|
|||||||
#define INIT_CMD_RELOAD_SVC 12 /* SIGHUP service */
|
#define INIT_CMD_RELOAD_SVC 12 /* SIGHUP service */
|
||||||
#define INIT_CMD_RESTART_SVC 13 /* STOP + START service */
|
#define INIT_CMD_RESTART_SVC 13 /* STOP + START service */
|
||||||
#define INIT_CMD_QUERY_INETD 14
|
#define INIT_CMD_QUERY_INETD 14
|
||||||
#define INIT_CMD_EMIT 15
|
#define INIT_CMD_UNUSED1 15 /* Unused, was INIT_CMD_EMIT */
|
||||||
#define INIT_CMD_GET_RUNLEVEL 16
|
#define INIT_CMD_GET_RUNLEVEL 16
|
||||||
#define INIT_CMD_WDOG_HELLO 128 /* Watchdog register and hello */
|
#define INIT_CMD_WDOG_HELLO 128 /* Watchdog register and hello */
|
||||||
#define INIT_CMD_SVC_ITER 129
|
#define INIT_CMD_SVC_ITER 129
|
||||||
@@ -84,6 +83,7 @@
|
|||||||
#define INIT_CMD_NACK 254
|
#define INIT_CMD_NACK 254
|
||||||
#define INIT_CMD_ACK 255
|
#define INIT_CMD_ACK 255
|
||||||
|
|
||||||
|
/* Traditionally aligned on 384 bytes */
|
||||||
struct init_request {
|
struct init_request {
|
||||||
int magic; /* Magic number */
|
int magic; /* Magic number */
|
||||||
int cmd; /* What kind of request */
|
int cmd; /* What kind of request */
|
||||||
@@ -92,10 +92,12 @@ struct init_request {
|
|||||||
char data[368];
|
char data[368];
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int wdogpid;
|
|
||||||
extern int runlevel;
|
extern int runlevel;
|
||||||
extern int cfglevel;
|
extern int cfglevel;
|
||||||
extern int prevlevel;
|
extern int prevlevel;
|
||||||
|
extern int rescue;
|
||||||
|
extern int single;
|
||||||
|
extern int splash;
|
||||||
extern char *rcsd;
|
extern char *rcsd;
|
||||||
extern char *sdown;
|
extern char *sdown;
|
||||||
extern char *network;
|
extern char *network;
|
||||||
|
|||||||
+68
-10
@@ -32,6 +32,7 @@
|
|||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
|
#include "cgroup.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "sig.h"
|
#include "sig.h"
|
||||||
#include "utmp-api.h"
|
#include "utmp-api.h"
|
||||||
@@ -192,6 +193,7 @@ static int do_login(char *name)
|
|||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
|
cgroup_user(name);
|
||||||
execl(_PATH_LOGIN, _PATH_LOGIN, name, NULL);
|
execl(_PATH_LOGIN, _PATH_LOGIN, name, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -209,8 +211,52 @@ static int do_login(char *name)
|
|||||||
|
|
||||||
int getty(char *tty, speed_t speed, char *term, char *user)
|
int getty(char *tty, speed_t speed, char *term, char *user)
|
||||||
{
|
{
|
||||||
int fd;
|
const char cln[] = "\r\e[2K\n";
|
||||||
char name[30];
|
char name[30];
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
/* Detach from initial controlling TTY */
|
||||||
|
vhangup();
|
||||||
|
|
||||||
|
fd = open(tty, O_RDWR);
|
||||||
|
if (fd < 0)
|
||||||
|
err(1, "Failed opening %s", tty);
|
||||||
|
|
||||||
|
dup2(fd, STDIN_FILENO);
|
||||||
|
dup2(fd, STDOUT_FILENO);
|
||||||
|
dup2(fd, STDERR_FILENO);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0)
|
||||||
|
warn("Failed TIOCSCTTY");
|
||||||
|
|
||||||
|
/* Set up TTY, re-enabling ISIG et al. */
|
||||||
|
stty(STDIN_FILENO, speed);
|
||||||
|
(void)write(STDOUT_FILENO, cln, strlen(cln));
|
||||||
|
|
||||||
|
/* The getty process is responsible for the UTMP login record */
|
||||||
|
utmp_set_login(tty, NULL);
|
||||||
|
if (!user)
|
||||||
|
do_getty(tty, name, sizeof(name));
|
||||||
|
else
|
||||||
|
strlcpy(name, user, sizeof(name));
|
||||||
|
|
||||||
|
if (term && term[0])
|
||||||
|
setenv("TERM", term, 1);
|
||||||
|
|
||||||
|
return do_login(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sh(char *tty)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
char *arg0;
|
||||||
|
char *args[2] = {
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
size_t len;
|
||||||
|
struct termios term;
|
||||||
|
|
||||||
/* Detach from initial controlling TTY */
|
/* Detach from initial controlling TTY */
|
||||||
vhangup();
|
vhangup();
|
||||||
@@ -226,21 +272,33 @@ int getty(char *tty, speed_t speed, char *term, char *user)
|
|||||||
if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0)
|
if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0)
|
||||||
warn("Failed TIOCSCTTY");
|
warn("Failed TIOCSCTTY");
|
||||||
|
|
||||||
/* The getty process is responsible for the UTMP login record */
|
/* The getty process is usually responsible for the UTMP login record */
|
||||||
utmp_set_login(tty, NULL);
|
utmp_set_login(tty, NULL);
|
||||||
if (!user)
|
|
||||||
do_getty(tty, name, sizeof(name));
|
|
||||||
else
|
|
||||||
strlcpy(name, user, sizeof(name));
|
|
||||||
|
|
||||||
/* Set up TTY, re-enabling ISIG et al. */
|
/* Set up TTY, re-enabling ISIG et al. */
|
||||||
stty(fd, speed);
|
stty(fd, B0);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
if (term)
|
/* Start /bin/sh as a login shell, i.e. with a prefix '-' */
|
||||||
setenv("TERM", term, 1);
|
len = strlen(_PATH_BSHELL) + 2;
|
||||||
|
arg0 = malloc(len);
|
||||||
|
if (!arg0)
|
||||||
|
err(1, "Failed allocating memory");
|
||||||
|
snprintf(arg0, len, "-%s", _PATH_BSHELL);
|
||||||
|
args[0] = arg0;
|
||||||
|
|
||||||
return do_login(name);
|
/* Reenable Ctrl-D and Ctrl-C, and ... */
|
||||||
|
if (!tcgetattr(STDIN_FILENO, &term)) {
|
||||||
|
term.c_lflag |= ISIG;
|
||||||
|
term.c_cc[VEOF] = CTL('D');
|
||||||
|
term.c_cc[VINTR] = CTL('C');
|
||||||
|
tcsetattr(STDIN_FILENO, TCSANOW, &term);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ... unblock signals in general */
|
||||||
|
sig_unblock();
|
||||||
|
|
||||||
|
return execv(_PATH_BSHELL, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+211
-32
@@ -39,6 +39,30 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "utmp-api.h"
|
#include "utmp-api.h"
|
||||||
|
|
||||||
|
static int progress_style = PROGRESS_STYLE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: the pending status (⋯) must be last item. Also, ⋯ is not
|
||||||
|
* off-by-one, it's a multi-byte character.
|
||||||
|
*/
|
||||||
|
#define STATUS_CLASS { \
|
||||||
|
CHOOSE(" OK ", " OK ", "\e[1;32m"), /* Green */ \
|
||||||
|
CHOOSE("FAIL", "FAIL", "\e[1;31m"), /* Red */ \
|
||||||
|
CHOOSE("WARN", "WARN", "\e[1;31m"), /* Red */ \
|
||||||
|
CHOOSE(" \\/ ", " ⋯ ", "\e[1;33m"), /* Yellow */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CHOOSE(x,y,z) x
|
||||||
|
static const char *status1[] = STATUS_CLASS;
|
||||||
|
#undef CHOOSE
|
||||||
|
|
||||||
|
#define CHOOSE(x,y,z) y
|
||||||
|
static const char *status2[] = STATUS_CLASS;
|
||||||
|
#undef CHOOSE
|
||||||
|
|
||||||
|
#define CHOOSE(x,y,z) z
|
||||||
|
static const char *color[] = STATUS_CLASS;
|
||||||
|
|
||||||
|
|
||||||
char *strip_line(char *line)
|
char *strip_line(char *line)
|
||||||
{
|
{
|
||||||
@@ -57,6 +81,81 @@ char *strip_line(char *line)
|
|||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return screen length of string, not counting escape chars, and
|
||||||
|
* accounting for unicode characters as only one screen byte wide
|
||||||
|
*/
|
||||||
|
size_t slen(char *string)
|
||||||
|
{
|
||||||
|
unsigned char *buf = (unsigned char *)string;
|
||||||
|
size_t len = 0;
|
||||||
|
|
||||||
|
while (*buf) {
|
||||||
|
/* Skip ANSI escape sequences */
|
||||||
|
if (*buf == '\e') {
|
||||||
|
while (*buf && !isalpha(*buf))
|
||||||
|
buf++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Skip 3-byte unicode */
|
||||||
|
if (*buf == 0xe2) {
|
||||||
|
for (int cnt = 3; *buf && cnt >= 0; cnt--)
|
||||||
|
buf++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
len++;
|
||||||
|
buf++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ch may be an ascii or unicode character
|
||||||
|
*/
|
||||||
|
static char *pad(char *buf, size_t len, char *ch, size_t width)
|
||||||
|
{
|
||||||
|
size_t i = slen(buf);
|
||||||
|
|
||||||
|
strlcat(buf, " ", len);
|
||||||
|
|
||||||
|
width -= 8; /* Skip leading '[ STAT ]' */
|
||||||
|
while (i < width) {
|
||||||
|
strlcat(buf, ch, len);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_banner(const char *heading)
|
||||||
|
{
|
||||||
|
char buf[4 * SCREEN_WIDTH];
|
||||||
|
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
strlcat(buf, "\r\e[2K", sizeof(buf));
|
||||||
|
if (progress_style == 1) {
|
||||||
|
strlcat(buf, "\e[1m", sizeof(buf));
|
||||||
|
strlcat(buf, heading, sizeof(buf));
|
||||||
|
pad(buf, sizeof(buf), "=", SCREEN_WIDTH - 2);
|
||||||
|
} else {
|
||||||
|
size_t wmax = 80 <= SCREEN_WIDTH ? 80 : SCREEN_WIDTH;
|
||||||
|
|
||||||
|
strlcat(buf, "\e[1;31m⏺ \e[1;33m⏺ \e[1;32m⏺ \e[0m\e[1m ", sizeof(buf));
|
||||||
|
strlcat(buf, heading, sizeof(buf));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Padding with full-width '═' sign from unicode,
|
||||||
|
* we could also use '―' or something else.
|
||||||
|
*/
|
||||||
|
pad(buf, sizeof(buf), "═", wmax);
|
||||||
|
}
|
||||||
|
strlcat(buf, "\e[0m\n", sizeof(buf));
|
||||||
|
|
||||||
|
(void)write(STDERR_FILENO, buf, strlen(buf));
|
||||||
|
}
|
||||||
|
|
||||||
static size_t print_timestamp(char *buf, size_t len)
|
static size_t print_timestamp(char *buf, size_t len)
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_PRINTK_TIME)
|
#if defined(CONFIG_PRINTK_TIME)
|
||||||
@@ -77,6 +176,26 @@ static size_t print_timestamp(char *buf, size_t len)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *status(int rc)
|
||||||
|
{
|
||||||
|
static char buf[64];
|
||||||
|
|
||||||
|
if (rc < 0 || rc >= (int)NELEMS(status1))
|
||||||
|
rc = NELEMS(status1) - 1; /* Default to "⋯" (pending) */
|
||||||
|
|
||||||
|
if (progress_style == 1) {
|
||||||
|
int hl = 1;
|
||||||
|
|
||||||
|
if (rc == 1 || rc == 2)
|
||||||
|
hl = 7;
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf), "\e[%dm[%s]\e[0m", hl, status1[rc]);
|
||||||
|
} else
|
||||||
|
snprintf(buf, sizeof(buf), "\e[1m[%s%s\e[0m\e[1m]\e[0m ", color[rc], status2[rc]);
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
void printv(const char *fmt, va_list ap)
|
void printv(const char *fmt, va_list ap)
|
||||||
{
|
{
|
||||||
char buf[SCREEN_WIDTH];
|
char buf[SCREEN_WIDTH];
|
||||||
@@ -91,51 +210,32 @@ void printv(const char *fmt, va_list ap)
|
|||||||
len = print_timestamp(buf, sizeof(buf));
|
len = print_timestamp(buf, sizeof(buf));
|
||||||
vsnprintf(&buf[len], sizeof(buf) - len, fmt, ap);
|
vsnprintf(&buf[len], sizeof(buf) - len, fmt, ap);
|
||||||
|
|
||||||
len = strlen(buf);
|
if (progress_style == 1)
|
||||||
buf[len++] = ' ';
|
fprintf(stderr, "\r%s ", pad(buf, sizeof(buf), ".", sizeof(buf)));
|
||||||
for (size_t i = len; i < (sizeof(buf) - 8); i++)
|
else
|
||||||
buf[i] = '.'; /* pad with dots. */
|
fprintf(stderr, "\r\e[2K%s%s", status(3), buf);
|
||||||
|
|
||||||
fprintf(stderr, "\r%s ", buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void print(int action, const char *fmt, ...)
|
void print(int rc, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
|
||||||
const char success[] = "\e[1m[ OK ]\e[0m\n";
|
|
||||||
const char failure[] = "\e[7m[FAIL]\e[0m\n";
|
|
||||||
const char warning[] = "\e[7m[WARN]\e[0m\n";
|
|
||||||
const char pending[] = "\e[1m[ \\/ ]\e[0m\n";
|
|
||||||
|
|
||||||
if (log_is_silent())
|
if (log_is_silent())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (fmt) {
|
if (fmt) {
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
printv(fmt, ap);
|
printv(fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (action) {
|
if (rc < 0)
|
||||||
case -1:
|
return;
|
||||||
break;
|
|
||||||
|
|
||||||
case 0:
|
if (progress_style == 1)
|
||||||
write(STDERR_FILENO, success, sizeof(success));
|
fprintf(stderr, "%s\n", status(rc));
|
||||||
break;
|
else
|
||||||
|
fprintf(stderr, ".\r%s\n", status(rc));
|
||||||
case 1:
|
|
||||||
write(STDERR_FILENO, failure, sizeof(failure));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
write(STDERR_FILENO, warning, sizeof(warning));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
write(STDERR_FILENO, pending, sizeof(pending));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_desc(char *action, char *desc)
|
void print_desc(char *action, char *desc)
|
||||||
@@ -184,6 +284,9 @@ void set_hostname(char **hostname)
|
|||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
|
if (rescue)
|
||||||
|
goto done;
|
||||||
|
|
||||||
fp = fopen("/etc/hostname", "r");
|
fp = fopen("/etc/hostname", "r");
|
||||||
if (fp) {
|
if (fp) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
@@ -204,10 +307,86 @@ void set_hostname(char **hostname)
|
|||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
if (*hostname)
|
if (*hostname)
|
||||||
sethostname(*hostname, strlen(*hostname));
|
sethostname(*hostname, strlen(*hostname));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ifup(char *ifname, int updown)
|
||||||
|
{
|
||||||
|
char cmd[80];
|
||||||
|
|
||||||
|
if (updown) {
|
||||||
|
snprintf(cmd, sizeof(cmd), "ifup %s", ifname);
|
||||||
|
run_interactive(cmd, "Bringing up interface %s", ifname);
|
||||||
|
} else {
|
||||||
|
snprintf(cmd, sizeof(cmd), "ifdown -f %s", ifname);
|
||||||
|
run_interactive(cmd, "Taking down interface %s", ifname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bring up networking, but only if not single-user or rescue mode
|
||||||
|
*/
|
||||||
|
void networking(int updown)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
/* No need to report errors if network is already down */
|
||||||
|
if (!prevlevel && !updown)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (updown)
|
||||||
|
_d("Setting up networking ...");
|
||||||
|
else
|
||||||
|
_d("Taking down networking ...");
|
||||||
|
|
||||||
|
/* Run user network start script if enabled */
|
||||||
|
if (updown && network) {
|
||||||
|
run_interactive(network, "Starting networking: %s", network);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Debian/Ubuntu/Busybox/RH/Suse */
|
||||||
|
if (!whichp("ifup"))
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
fp = fopen("/etc/network/interfaces", "r");
|
||||||
|
if (fp) {
|
||||||
|
char buf[160];
|
||||||
|
|
||||||
|
/* Bring up, or down, all 'auto' interfaces */
|
||||||
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
char *line, *ifname = NULL;
|
||||||
|
|
||||||
|
chomp(buf);
|
||||||
|
line = strip_line(buf);
|
||||||
|
|
||||||
|
if (!strncmp(line, "auto", 4))
|
||||||
|
ifname = &line[5];
|
||||||
|
if (!strncmp(line, "allow-hotplug", 13))
|
||||||
|
ifname = &line[14];
|
||||||
|
|
||||||
|
if (!ifname)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ifup(ifname, updown);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
/* Fall back to bring up at least loopback */
|
||||||
|
ifconfig("lo", "127.0.0.1", "255.0.0.0", updown);
|
||||||
|
|
||||||
|
/* Hooks that rely on loopback, or basic networking being up. */
|
||||||
|
if (updown) {
|
||||||
|
_d("Calling all network up hooks ...");
|
||||||
|
plugin_run_hooks(HOOK_NETWORK_UP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef HAVE_GETFSENT
|
#ifndef HAVE_GETFSENT
|
||||||
static lfile_t *fstab = NULL;
|
static lfile_t *fstab = NULL;
|
||||||
|
|
||||||
|
|||||||
+4
-3
@@ -52,13 +52,12 @@ struct fstab *getfsent (void);
|
|||||||
char *strip_line (char *line);
|
char *strip_line (char *line);
|
||||||
|
|
||||||
int getty (char *tty, speed_t speed, char *term, char *user);
|
int getty (char *tty, speed_t speed, char *term, char *user);
|
||||||
|
int sh (char *tty);
|
||||||
|
|
||||||
int stty (int fd, speed_t speed);
|
int stty (int fd, speed_t speed);
|
||||||
speed_t stty_parse_speed(char *baud);
|
speed_t stty_parse_speed(char *baud);
|
||||||
|
|
||||||
int pid_alive (pid_t pid);
|
void print_banner (const char *heading);
|
||||||
char *pid_get_name (pid_t pid, char *name, size_t len);
|
|
||||||
|
|
||||||
void printv (const char *fmt, va_list ap);
|
void printv (const char *fmt, va_list ap);
|
||||||
void print (int action, const char *fmt, ...);
|
void print (int action, const char *fmt, ...);
|
||||||
void print_desc (char *action, char *desc);
|
void print_desc (char *action, char *desc);
|
||||||
@@ -67,6 +66,7 @@ int print_result (int fail);
|
|||||||
int getuser (char *username, char **home);
|
int getuser (char *username, char **home);
|
||||||
int getgroup (char *group);
|
int getgroup (char *group);
|
||||||
void set_hostname (char **hostname);
|
void set_hostname (char **hostname);
|
||||||
|
void networking (int updown);
|
||||||
|
|
||||||
int complete (char *cmd, int pid);
|
int complete (char *cmd, int pid);
|
||||||
int run (char *cmd);
|
int run (char *cmd);
|
||||||
@@ -74,6 +74,7 @@ int run_interactive (char *cmd, char *fmt, ...);
|
|||||||
int exec_runtask (char *cmd, char *args[]);
|
int exec_runtask (char *cmd, char *args[]);
|
||||||
pid_t run_getty (char *tty, char *baud, char *term, int noclear, int nowait, struct rlimit rlimit[]);
|
pid_t run_getty (char *tty, char *baud, char *term, int noclear, int nowait, struct rlimit rlimit[]);
|
||||||
pid_t run_getty2 (char *tty, char *cmd, char *args[], int noclear, int nowait, struct rlimit rlimit[]);
|
pid_t run_getty2 (char *tty, char *cmd, char *args[], int noclear, int nowait, struct rlimit rlimit[]);
|
||||||
|
pid_t run_sh (char *tty, int noclear, int nowait, struct rlimit rlimit[]);
|
||||||
int run_parts (char *dir, char *cmd);
|
int run_parts (char *dir, char *cmd);
|
||||||
|
|
||||||
static inline void create(char *path, mode_t mode, uid_t uid, gid_t gid)
|
static inline void create(char *path, mode_t mode, uid_t uid, gid_t gid)
|
||||||
|
|||||||
+65
-25
@@ -43,12 +43,13 @@
|
|||||||
} while (0);
|
} while (0);
|
||||||
|
|
||||||
/* Peek into SOCK_DGRAM socket to figure out where an inbound packet comes from. */
|
/* Peek into SOCK_DGRAM socket to figure out where an inbound packet comes from. */
|
||||||
static int inetd_dgram_peek(int sd, char *ifname)
|
static int inetd_dgram_peek(int sd, char *ifname, size_t len)
|
||||||
{
|
{
|
||||||
char cmbuf[0x100];
|
|
||||||
struct msghdr msgh;
|
|
||||||
struct cmsghdr *cmsg;
|
struct cmsghdr *cmsg;
|
||||||
|
struct msghdr msgh;
|
||||||
|
char cmbuf[0x100];
|
||||||
|
|
||||||
|
memset(ifname, 0, len);
|
||||||
memset(&msgh, 0, sizeof(msgh));
|
memset(&msgh, 0, sizeof(msgh));
|
||||||
msgh.msg_control = cmbuf;
|
msgh.msg_control = cmbuf;
|
||||||
msgh.msg_controllen = sizeof(cmbuf);
|
msgh.msg_controllen = sizeof(cmbuf);
|
||||||
@@ -56,13 +57,15 @@ static int inetd_dgram_peek(int sd, char *ifname)
|
|||||||
if (recvmsg(sd, &msgh, MSG_PEEK) < 0)
|
if (recvmsg(sd, &msgh, MSG_PEEK) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg; cmsg = CMSG_NXTHDR(&msgh,cmsg)) {
|
for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg; cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
|
||||||
struct in_pktinfo *ipi = (struct in_pktinfo *)CMSG_DATA(cmsg);
|
struct in_pktinfo *ipi = (struct in_pktinfo *)CMSG_DATA(cmsg);
|
||||||
|
char tmp[IF_NAMESIZE + 1] = { 0 };
|
||||||
|
|
||||||
if (cmsg->cmsg_level != SOL_IP || cmsg->cmsg_type != IP_PKTINFO)
|
if (cmsg->cmsg_level != SOL_IP || cmsg->cmsg_type != IP_PKTINFO)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if_indextoname(ipi->ipi_ifindex, ifname);
|
if_indextoname(ipi->ipi_ifindex, tmp);
|
||||||
|
strlcpy(ifname, tmp, len);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -73,26 +76,28 @@ static int inetd_dgram_peek(int sd, char *ifname)
|
|||||||
/* Peek into SOCK_DGRAM socket to figure out where an inbound packet comes from. */
|
/* Peek into SOCK_DGRAM socket to figure out where an inbound packet comes from. */
|
||||||
static void inetd_dgram_drop(int sd, const char *ifname)
|
static void inetd_dgram_drop(int sd, const char *ifname)
|
||||||
{
|
{
|
||||||
char pkt_interface[17];
|
char pkt_interface[IF_NAMESIZE + 1];
|
||||||
char buf[BUFSIZ];
|
char buf[BUFSIZ];
|
||||||
|
|
||||||
do {
|
while (1) {
|
||||||
inetd_dgram_peek(sd, pkt_interface);
|
inetd_dgram_peek(sd, pkt_interface, sizeof(pkt_interface));
|
||||||
if(string_compare(pkt_interface, ifname)) {
|
if (string_compare(pkt_interface, ifname)) {
|
||||||
recv(sd, buf, sizeof(buf), 0);
|
if (recv(sd, buf, sizeof(buf), 0) < 0)
|
||||||
|
break;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
} while (0);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Peek into SOCK_STREAM on accepted client socket to figure out inbound interface */
|
/* Peek into SOCK_STREAM on accepted client socket to figure out inbound interface */
|
||||||
static int inetd_stream_peek(int sd, char *ifname)
|
static int inetd_stream_peek(int sd, char *ifname, size_t ilen)
|
||||||
{
|
{
|
||||||
struct ifaddrs *ifaddr, *ifa;
|
struct ifaddrs *ifaddr, *ifa;
|
||||||
struct sockaddr_in sin;
|
struct sockaddr_in sin;
|
||||||
socklen_t len = sizeof(sin);
|
socklen_t len = sizeof(sin);
|
||||||
|
|
||||||
|
memset(ifname, 0, ilen);
|
||||||
if (-1 == getsockname(sd, (struct sockaddr *)&sin, &len))
|
if (-1 == getsockname(sd, (struct sockaddr *)&sin, &len))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@@ -111,7 +116,7 @@ static int inetd_stream_peek(int sd, char *ifname)
|
|||||||
|
|
||||||
iin = (struct sockaddr_in *)ifa->ifa_addr;
|
iin = (struct sockaddr_in *)ifa->ifa_addr;
|
||||||
if (!memcmp(&sin.sin_addr, &iin->sin_addr, len)) {
|
if (!memcmp(&sin.sin_addr, &iin->sin_addr, len)) {
|
||||||
strncpy(ifname, ifa->ifa_name, IF_NAMESIZE);
|
strlcpy(ifname, ifa->ifa_name, ilen);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,11 +126,12 @@ static int inetd_stream_peek(int sd, char *ifname)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_stdin(svc_t *svc)
|
static int get_stdin(svc_t *svc, char *iifname, size_t len)
|
||||||
{
|
{
|
||||||
int stdin = svc->inetd.watcher.fd;
|
int stdin = svc->inetd.watcher.fd;
|
||||||
char ifname[IF_NAMESIZE] = "UNKNOWN";
|
char ifname[IF_NAMESIZE + 1] = "UNKNOWN";
|
||||||
|
|
||||||
|
memset(iifname, 0, len);
|
||||||
if (svc->inetd.type == SOCK_STREAM) {
|
if (svc->inetd.type == SOCK_STREAM) {
|
||||||
/* Open new client socket from server socket */
|
/* Open new client socket from server socket */
|
||||||
stdin = accept(stdin, NULL, NULL);
|
stdin = accept(stdin, NULL, NULL);
|
||||||
@@ -136,9 +142,9 @@ static int get_stdin(svc_t *svc)
|
|||||||
|
|
||||||
_d("New client socket %d accepted for inetd service %d/tcp", stdin, svc->inetd.port);
|
_d("New client socket %d accepted for inetd service %d/tcp", stdin, svc->inetd.port);
|
||||||
|
|
||||||
inetd_stream_peek(stdin, ifname);
|
inetd_stream_peek(stdin, ifname, sizeof(ifname));
|
||||||
} else { /* SOCK_DGRAM */
|
} else { /* SOCK_DGRAM */
|
||||||
inetd_dgram_peek(stdin, ifname);
|
inetd_dgram_peek(stdin, ifname, sizeof(ifname));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!inetd_is_allowed(&svc->inetd, ifname)) {
|
if (!inetd_is_allowed(&svc->inetd, ifname)) {
|
||||||
@@ -151,6 +157,9 @@ static int get_stdin(svc_t *svc)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return ingress interface */
|
||||||
|
strlcpy(iifname, ifname, len);
|
||||||
|
|
||||||
return stdin;
|
return stdin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,6 +167,9 @@ static int get_stdin(svc_t *svc)
|
|||||||
static void socket_cb(uev_t *w, void *arg, int events)
|
static void socket_cb(uev_t *w, void *arg, int events)
|
||||||
{
|
{
|
||||||
svc_t *svc = (svc_t *)arg, *task;
|
svc_t *svc = (svc_t *)arg, *task;
|
||||||
|
const char *conn = " connection";
|
||||||
|
char iifname[IF_NAMESIZE + 1] = "UNKNOWN";
|
||||||
|
char id[MAX_ID_LEN];
|
||||||
int stdin;
|
int stdin;
|
||||||
|
|
||||||
_d("%s: Got socket event ...", svc->cmd);
|
_d("%s: Got socket event ...", svc->cmd);
|
||||||
@@ -166,7 +178,7 @@ static void socket_cb(uev_t *w, void *arg, int events)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
stdin = get_stdin(svc);
|
stdin = get_stdin(svc, iifname, sizeof(iifname));
|
||||||
if (stdin < 0) {
|
if (stdin < 0) {
|
||||||
logit(LOG_CRIT, "%s: Unable to accept incoming connection", svc->cmd);
|
logit(LOG_CRIT, "%s: Unable to accept incoming connection", svc->cmd);
|
||||||
return;
|
return;
|
||||||
@@ -183,7 +195,8 @@ static void socket_cb(uev_t *w, void *arg, int events)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
task = svc_new(svc->cmd, svc->inetd.next_id++, SVC_TYPE_INETD_CONN);
|
snprintf(id, sizeof(id), "%d", svc->inetd.next_id++);
|
||||||
|
task = svc_new(svc->cmd, id, SVC_TYPE_INETD_CONN);
|
||||||
if (!task) {
|
if (!task) {
|
||||||
logit(LOG_CRIT, "%s: Unable to allocate service for inetd client", svc->cmd);
|
logit(LOG_CRIT, "%s: Unable to allocate service for inetd client", svc->cmd);
|
||||||
if (svc->inetd.type == SOCK_STREAM)
|
if (svc->inetd.type == SOCK_STREAM)
|
||||||
@@ -207,11 +220,15 @@ static void socket_cb(uev_t *w, void *arg, int events)
|
|||||||
task->inetd.cmd = svc->inetd.cmd;
|
task->inetd.cmd = svc->inetd.cmd;
|
||||||
task->inetd.type = svc->inetd.type;
|
task->inetd.type = svc->inetd.type;
|
||||||
|
|
||||||
|
memcpy(task->rlimit, svc->rlimit, sizeof(task->rlimit));
|
||||||
memcpy(task->cond, svc->cond, sizeof(task->cond));
|
memcpy(task->cond, svc->cond, sizeof(task->cond));
|
||||||
memcpy(task->username, svc->username, sizeof(task->username));
|
memcpy(task->username, svc->username, sizeof(task->username));
|
||||||
memcpy(task->group, svc->group, sizeof(task->group));
|
memcpy(task->group, svc->group, sizeof(task->group));
|
||||||
memcpy(task->args, svc->args, sizeof(task->args));
|
memcpy(task->args, svc->args, sizeof(task->args));
|
||||||
snprintf(task->desc, sizeof(task->desc), "%52.52s connection", svc->desc);
|
strlcpy(task->desc, svc->desc, sizeof(task->desc) - strlen(conn));
|
||||||
|
strlcat(task->desc, conn, sizeof(task->desc));
|
||||||
|
strlcpy(task->iifname, iifname, sizeof(task->iifname));
|
||||||
|
strlcpy(task->name, svc->name, sizeof(task->name));
|
||||||
|
|
||||||
task->stdin_fd = stdin;
|
task->stdin_fd = stdin;
|
||||||
service_step(task);
|
service_step(task);
|
||||||
@@ -331,20 +348,43 @@ int inetd_start(inetd_t *inetd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void inetd_stop_children(inetd_t *inetd, int check_allowed)
|
||||||
|
{
|
||||||
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
|
svc = svc_job_iterator(&iter, 1, inetd->svc->job);
|
||||||
|
while (svc) {
|
||||||
|
if (!svc_is_inetd(svc)) {
|
||||||
|
if (!check_allowed || !inetd_is_allowed(inetd, svc->iifname)) {
|
||||||
|
svc_stop(svc);
|
||||||
|
service_step(svc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
svc = svc_job_iterator(&iter, 0, inetd->svc->job);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void inetd_stop(inetd_t *inetd)
|
void inetd_stop(inetd_t *inetd)
|
||||||
{
|
{
|
||||||
|
if (!inetd || !inetd->svc) {
|
||||||
|
_e("Invalid inetd, cannot stop it...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (inetd->watcher.fd != -1) {
|
if (inetd->watcher.fd != -1) {
|
||||||
_d("Stopping %s socket watcher ...", inetd->svc->cmd);
|
_d("Stopping %s socket watcher ...", inetd->svc->cmd);
|
||||||
uev_io_stop(&inetd->watcher);
|
uev_io_stop(&inetd->watcher);
|
||||||
|
|
||||||
/* For dgram inetd services we block the parent SVC
|
/*
|
||||||
* and halt the watcher, so don't close the socket! */
|
* For dgram inetd services we block the parent SVC
|
||||||
|
* and halt the watcher, so don't close the socket!
|
||||||
|
*/
|
||||||
if (!svc_is_busy(inetd->svc)) {
|
if (!svc_is_busy(inetd->svc)) {
|
||||||
_d("Shutting down inet socket %d ...", inetd->watcher.fd);
|
_d("Shutting down inet socket %d ...", inetd->watcher.fd);
|
||||||
if (inetd->type == SOCK_STREAM)
|
|
||||||
shutdown(inetd->watcher.fd, SHUT_RDWR);
|
|
||||||
close(inetd->watcher.fd);
|
close(inetd->watcher.fd);
|
||||||
inetd->watcher.fd = -1;
|
inetd->watcher.fd = -1;
|
||||||
|
|
||||||
|
inetd_stop_children(inetd, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ int inetd_check_loop(struct sockaddr *sa, socklen_t len, char *name);
|
|||||||
|
|
||||||
int inetd_start (inetd_t *inetd);
|
int inetd_start (inetd_t *inetd);
|
||||||
void inetd_stop (inetd_t *inetd);
|
void inetd_stop (inetd_t *inetd);
|
||||||
|
void inetd_stop_children (inetd_t *inetd, int check_allowed);
|
||||||
|
|
||||||
int inetd_new (inetd_t *inetd, char *name, char *service, char *proto, int forking, svc_t *svc);
|
int inetd_new (inetd_t *inetd, char *name, char *service, char *proto, int forking, svc_t *svc);
|
||||||
int inetd_del (inetd_t *inetd);
|
int inetd_del (inetd_t *inetd);
|
||||||
|
|||||||
+110
-39
@@ -43,6 +43,11 @@
|
|||||||
|
|
||||||
#define _PATH_COND _PATH_VARRUN "finit/cond/"
|
#define _PATH_COND _PATH_VARRUN "finit/cond/"
|
||||||
|
|
||||||
|
struct command {
|
||||||
|
char *cmd;
|
||||||
|
int (*cb)(char *arg);
|
||||||
|
};
|
||||||
|
|
||||||
int verbose = 0;
|
int verbose = 0;
|
||||||
int runlevel = 0;
|
int runlevel = 0;
|
||||||
|
|
||||||
@@ -135,7 +140,6 @@ static int do_svc(int cmd, char *arg)
|
|||||||
return client_send(&rq, sizeof(rq));
|
return client_send(&rq, sizeof(rq));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_emit (char *arg) { return do_svc(INIT_CMD_EMIT, arg); }
|
|
||||||
static int do_reload (char *arg) { return do_svc(INIT_CMD_RELOAD, arg); }
|
static int do_reload (char *arg) { return do_svc(INIT_CMD_RELOAD, arg); }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -168,7 +172,7 @@ static int do_restart(char *arg) { return do_startstop(INIT_CMD_RESTART_SVC, arg
|
|||||||
|
|
||||||
static void show_cond_one(const char *_conds)
|
static void show_cond_one(const char *_conds)
|
||||||
{
|
{
|
||||||
static char conds[MAX_ARG_LEN];
|
static char conds[MAX_COND_LEN];
|
||||||
char *cond;
|
char *cond;
|
||||||
|
|
||||||
strlcpy(conds, _conds, sizeof(conds));
|
strlcpy(conds, _conds, sizeof(conds));
|
||||||
@@ -197,22 +201,6 @@ static void show_cond_one(const char *_conds)
|
|||||||
putchar('>');
|
putchar('>');
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_cond_magic(char op, char *cond)
|
|
||||||
{
|
|
||||||
char event[368]; /* sizeof(init_request.data) */
|
|
||||||
|
|
||||||
if (!cond || strlen(cond) < 1)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
event[0] = op;
|
|
||||||
strlcpy(&event[1], cond, sizeof(event) - 1);
|
|
||||||
|
|
||||||
return do_emit(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int do_cond_set (char *cond) { return do_cond_magic('+', cond); }
|
|
||||||
static int do_cond_clear(char *cond) { return do_cond_magic('-', cond); }
|
|
||||||
|
|
||||||
static int dump_one_cond(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftwbuf)
|
static int dump_one_cond(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftwbuf)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
@@ -272,10 +260,8 @@ static int do_cond(char *cmd)
|
|||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
char *arg;
|
char *arg;
|
||||||
command_t command[] = {
|
struct command command[] = {
|
||||||
{ "show", do_cond_show },
|
{ "show", do_cond_show },
|
||||||
{ "set", do_cond_set },
|
|
||||||
{ "clear", do_cond_clear },
|
|
||||||
{ "dump", do_cond_dump },
|
{ "dump", do_cond_dump },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
@@ -411,6 +397,9 @@ static int show_status(char *arg)
|
|||||||
runlevel = runlevel_get(NULL);
|
runlevel = runlevel_get(NULL);
|
||||||
|
|
||||||
if (arg && arg[0]) {
|
if (arg && arg[0]) {
|
||||||
|
long now = jiffies();
|
||||||
|
char buf[42] = "N/A";
|
||||||
|
|
||||||
svc = client_svc_find(arg);
|
svc = client_svc_find(arg);
|
||||||
if (!svc)
|
if (!svc)
|
||||||
return 1;
|
return 1;
|
||||||
@@ -418,6 +407,7 @@ static int show_status(char *arg)
|
|||||||
printf("Service : %s\n", svc->cmd);
|
printf("Service : %s\n", svc->cmd);
|
||||||
printf("Description : %s\n", svc->desc);
|
printf("Description : %s\n", svc->desc);
|
||||||
printf("PID : %d\n", svc->pid);
|
printf("PID : %d\n", svc->pid);
|
||||||
|
printf("Uptime : %s\n", svc->pid ? uptime(now - svc->start_time, buf, sizeof(buf)) : buf);
|
||||||
printf("Runlevels : %s\n", runlevel_string(runlevel, svc->runlevels));
|
printf("Runlevels : %s\n", runlevel_string(runlevel, svc->runlevels));
|
||||||
printf("Status : %s\n", svc_status(svc));
|
printf("Status : %s\n", svc_status(svc));
|
||||||
printf("\n");
|
printf("\n");
|
||||||
@@ -426,17 +416,17 @@ static int show_status(char *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!verbose)
|
if (!verbose)
|
||||||
printheader(NULL, "# STATUS PID RUNLEVELS SERVICE DESCRIPTION", 0);
|
printheader(NULL, "# STATUS PID RUNLEVELS SERVICE DESCRIPTION", 0);
|
||||||
|
|
||||||
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
|
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
|
||||||
char jobid[10], args[512] = "", *lvls;
|
char jobid[20], args[512] = "", *lvls;
|
||||||
|
|
||||||
// if (svc_is_unique(svc))
|
// if (svc_is_unique(svc))
|
||||||
// snprintf(jobid, sizeof(jobid), "%d", svc->job);
|
// snprintf(jobid, sizeof(jobid), "%d", svc->job);
|
||||||
// else
|
// else
|
||||||
snprintf(jobid, sizeof(jobid), "%d:%d", svc->job, svc->id);
|
snprintf(jobid, sizeof(jobid), "%d:%s", svc->job, svc->id);
|
||||||
|
|
||||||
printf("%-5s %7s ", jobid, svc_status(svc));
|
printf("%-9s %8s ", jobid, svc_status(svc));
|
||||||
if (svc_is_inetd(svc))
|
if (svc_is_inetd(svc))
|
||||||
printf("inetd ");
|
printf("inetd ");
|
||||||
else
|
else
|
||||||
@@ -450,14 +440,7 @@ static int show_status(char *arg)
|
|||||||
|
|
||||||
if (!verbose) {
|
if (!verbose) {
|
||||||
int adj = screen_cols - 60;
|
int adj = screen_cols - 60;
|
||||||
char *name = strrchr(svc->cmd, '/');
|
printf("%-16.16s %-*.*s\n", svc->name, adj, adj, svc->desc);
|
||||||
|
|
||||||
if (!name)
|
|
||||||
name = svc->cmd;
|
|
||||||
else
|
|
||||||
name++;
|
|
||||||
|
|
||||||
printf("%-20.20s %-*.*s\n", name, adj, adj, svc->desc);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -507,12 +490,78 @@ static int show_status(char *arg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dump_cgroup(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftwbuf)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
char *group;
|
||||||
|
char path[256];
|
||||||
|
char buf[256];
|
||||||
|
int user = 0;
|
||||||
|
int num = 0;
|
||||||
|
|
||||||
|
if (tflag == FTW_F)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "%s/cgroup.procs", fpath);
|
||||||
|
fp = fopen(path, "r");
|
||||||
|
if (!fp)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (strstr(fpath, "finit/user"))
|
||||||
|
user = 1;
|
||||||
|
|
||||||
|
group = strrchr(fpath, '/');
|
||||||
|
if (!group)
|
||||||
|
goto err;
|
||||||
|
group++;
|
||||||
|
|
||||||
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
FILE *cfp;
|
||||||
|
int pid;
|
||||||
|
|
||||||
|
if (num == 0)
|
||||||
|
printf("%c :- %s/", user ? ' ' : '|', group);
|
||||||
|
num++;
|
||||||
|
|
||||||
|
pid = atoi(chomp(buf));
|
||||||
|
snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
|
||||||
|
cfp = fopen(path, "r");
|
||||||
|
if (!cfp)
|
||||||
|
continue;
|
||||||
|
fgets(buf, sizeof(buf), cfp);
|
||||||
|
fclose(cfp);
|
||||||
|
|
||||||
|
printf("\n%c :- %d %s", user ? ' ' : '|', pid, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
err:
|
||||||
|
fclose(fp);
|
||||||
|
if (num)
|
||||||
|
printf("\r%c\n", user ? ' ' : '|');
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int show_cgroup(char *arg)
|
||||||
|
{
|
||||||
|
puts("finit/");
|
||||||
|
puts("|- init/");
|
||||||
|
nftw("/sys/fs/cgroup/finit/init", dump_cgroup, 20, 0);
|
||||||
|
puts("|- system/");
|
||||||
|
nftw("/sys/fs/cgroup/finit/system", dump_cgroup, 20, 0);
|
||||||
|
puts("`- user/");
|
||||||
|
nftw("/sys/fs/cgroup/finit/user", dump_cgroup, 20, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int usage(int rc)
|
static int usage(int rc)
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Usage: %s [OPTIONS] [COMMAND]\n"
|
"Usage: %s [OPTIONS] [COMMAND]\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
|
" -b, --batch Batch mode, no screen size probing\n"
|
||||||
" -v, --verbose Verbose output\n"
|
" -v, --verbose Verbose output\n"
|
||||||
" -h, --help This help text\n"
|
" -h, --help This help text\n"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -528,8 +577,6 @@ static int usage(int rc)
|
|||||||
" reload Reload *.conf in /etc/finit.d/ (activates changes)\n"
|
" reload Reload *.conf in /etc/finit.d/ (activates changes)\n"
|
||||||
// " reload <JOB|NAME>[:ID] Reload (SIGHUP) service by job# or name\n"
|
// " reload <JOB|NAME>[:ID] Reload (SIGHUP) service by job# or name\n"
|
||||||
"\n"
|
"\n"
|
||||||
" cond set <COND> Set (assert) condition => +COND\n"
|
|
||||||
" cond clear <COND> Clear (deassert) condition => -COND\n"
|
|
||||||
" cond show Show condition status\n"
|
" cond show Show condition status\n"
|
||||||
" cond dump Dump all conditions and their status\n"
|
" cond dump Dump all conditions and their status\n"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -537,8 +584,11 @@ static int usage(int rc)
|
|||||||
" start <JOB|NAME>[:ID] Start service by job# or name, with optional ID\n"
|
" start <JOB|NAME>[:ID] Start service by job# or name, with optional ID\n"
|
||||||
" stop <JOB|NAME>[:ID] Stop/Pause a running service by job# or name\n"
|
" stop <JOB|NAME>[:ID] Stop/Pause a running service by job# or name\n"
|
||||||
" restart <JOB|NAME>[:ID] Restart (stop/start) service by job# or name\n"
|
" restart <JOB|NAME>[:ID] Restart (stop/start) service by job# or name\n"
|
||||||
|
" status <JOB|NAME>[:ID] Show service status, by job# or name\n"
|
||||||
" status | show Show status of services, default command\n"
|
" status | show Show status of services, default command\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
" ps List processes based on cgroups\n"
|
||||||
|
"\n"
|
||||||
" runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot\n"
|
" runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot\n"
|
||||||
" reboot Reboot system\n"
|
" reboot Reboot system\n"
|
||||||
" halt Halt system\n"
|
" halt Halt system\n"
|
||||||
@@ -557,9 +607,9 @@ static int do_help(char *arg)
|
|||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int c;
|
int interactive = 1, c;
|
||||||
char *cmd, arg[120];
|
char *cmd, arg[120];
|
||||||
command_t command[] = {
|
struct command command[] = {
|
||||||
{ "debug", toggle_debug },
|
{ "debug", toggle_debug },
|
||||||
{ "help", do_help },
|
{ "help", do_help },
|
||||||
{ "version", show_version },
|
{ "version", show_version },
|
||||||
@@ -579,6 +629,8 @@ int main(int argc, char *argv[])
|
|||||||
{ "status", show_status },
|
{ "status", show_status },
|
||||||
{ "show", show_status }, /* Convenience alias */
|
{ "show", show_status }, /* Convenience alias */
|
||||||
|
|
||||||
|
{ "ps", show_cgroup },
|
||||||
|
|
||||||
{ "runlevel", do_runlevel },
|
{ "runlevel", do_runlevel },
|
||||||
{ "reboot", do_reboot },
|
{ "reboot", do_reboot },
|
||||||
{ "halt", do_halt },
|
{ "halt", do_halt },
|
||||||
@@ -588,6 +640,7 @@ int main(int argc, char *argv[])
|
|||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
struct option long_options[] = {
|
struct option long_options[] = {
|
||||||
|
{"batch", 0, NULL, 'b'},
|
||||||
{"help", 0, NULL, 'h'},
|
{"help", 0, NULL, 'h'},
|
||||||
{"debug", 0, NULL, 'd'},
|
{"debug", 0, NULL, 'd'},
|
||||||
{"verbose", 0, NULL, 'v'},
|
{"verbose", 0, NULL, 'v'},
|
||||||
@@ -595,8 +648,12 @@ int main(int argc, char *argv[])
|
|||||||
};
|
};
|
||||||
|
|
||||||
progname(argv[0]);
|
progname(argv[0]);
|
||||||
while ((c = getopt_long(argc, argv, "h?v", long_options, NULL)) != EOF) {
|
while ((c = getopt_long(argc, argv, "bh?v", long_options, NULL)) != EOF) {
|
||||||
switch(c) {
|
switch(c) {
|
||||||
|
case 'b':
|
||||||
|
interactive = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
case '?':
|
case '?':
|
||||||
return usage(0);
|
return usage(0);
|
||||||
@@ -607,7 +664,8 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
screen_init();
|
if (interactive)
|
||||||
|
screen_init();
|
||||||
|
|
||||||
if (optind >= argc)
|
if (optind >= argc)
|
||||||
return show_status(NULL);
|
return show_status(NULL);
|
||||||
@@ -630,6 +688,19 @@ int main(int argc, char *argv[])
|
|||||||
return usage(1);
|
return usage(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void logit(int prio, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
if (prio <= LOG_ERR)
|
||||||
|
verrx(1, fmt, ap);
|
||||||
|
else
|
||||||
|
vwarnx(fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
|
|||||||
@@ -29,12 +29,22 @@
|
|||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
static int up = 0;
|
static int up = 0;
|
||||||
static int debug = 0;
|
static int debug = 0;
|
||||||
static int silent = SILENT_MODE; /* Completely silent, including boot */
|
static int silent = SILENT_MODE; /* Completely silent, including boot */
|
||||||
static int loglevel = LOG_NOTICE;
|
static int loglevel = LOG_NOTICE;
|
||||||
|
|
||||||
|
static void muffler(void)
|
||||||
|
{
|
||||||
|
silent = SILENT_MODE;
|
||||||
|
|
||||||
|
/* User override from kernel cmdline */
|
||||||
|
if (splash)
|
||||||
|
silent = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void log_init(int dbg)
|
void log_init(int dbg)
|
||||||
{
|
{
|
||||||
if (dbg)
|
if (dbg)
|
||||||
@@ -44,16 +54,25 @@ void log_init(int dbg)
|
|||||||
loglevel = LOG_DEBUG;
|
loglevel = LOG_DEBUG;
|
||||||
else
|
else
|
||||||
loglevel = LOG_NOTICE;
|
loglevel = LOG_NOTICE;
|
||||||
|
|
||||||
|
muffler();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we enabled terse mode at boot, restore to previous setting at shutdown */
|
/* If we enabled terse mode at boot, restore to previous setting at shutdown */
|
||||||
void log_exit(void)
|
void log_exit(void)
|
||||||
{
|
{
|
||||||
silent = SILENT_MODE;
|
muffler();
|
||||||
if (!silent) {
|
if (!silent)
|
||||||
sched_yield();
|
sched_yield();
|
||||||
fputs("\n", stderr);
|
|
||||||
}
|
/*
|
||||||
|
* Unless in debug mode at shutdown, Reinitialize screen,
|
||||||
|
* terminal may have been resized at runtime
|
||||||
|
*/
|
||||||
|
if (debug)
|
||||||
|
screen_exit();
|
||||||
|
else
|
||||||
|
screen_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_open(void)
|
void log_open(void)
|
||||||
@@ -91,12 +110,19 @@ void log_debug(void)
|
|||||||
if (debug) {
|
if (debug) {
|
||||||
silent = 0;
|
silent = 0;
|
||||||
loglevel = LOG_DEBUG;
|
loglevel = LOG_DEBUG;
|
||||||
|
|
||||||
|
screen_exit();
|
||||||
} else {
|
} else {
|
||||||
silent = SILENT_MODE;
|
silent = SILENT_MODE;
|
||||||
loglevel = LOG_NOTICE;
|
loglevel = LOG_NOTICE;
|
||||||
|
|
||||||
|
screen_init();
|
||||||
}
|
}
|
||||||
log_open();
|
log_open();
|
||||||
|
|
||||||
|
/* Also toggle silent mode (progress) */
|
||||||
|
log_silent();
|
||||||
|
|
||||||
logit(LOG_NOTICE, "Debug mode %s", debug ? "enabled" : "disabled");
|
logit(LOG_NOTICE, "Debug mode %s", debug ? "enabled" : "disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,11 @@
|
|||||||
|
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
|
|
||||||
|
/* Local facility, unused in GNU but available in FreeBSD or sysklogd >= 2.0 */
|
||||||
|
#ifndef LOG_CONSOLE
|
||||||
|
#define LOG_CONSOLE (14<<3)
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Developer error and debug messages, otherwise --> use logit() <--
|
* Developer error and debug messages, otherwise --> use logit() <--
|
||||||
* ~~~~~~~~~~~
|
* ~~~~~~~~~~~
|
||||||
@@ -33,7 +38,7 @@
|
|||||||
* errors and debug messages. For all other user messages, see logit()
|
* errors and debug messages. For all other user messages, see logit()
|
||||||
*
|
*
|
||||||
* The default log level is LOG_NOTICE. To toggle LOG_DEBUG messages,
|
* The default log level is LOG_NOTICE. To toggle LOG_DEBUG messages,
|
||||||
* use `initctl debug` or add `--debug` to the kernel cmdline.
|
* use `initctl debug` or add `debug` to the kernel cmdline.
|
||||||
*/
|
*/
|
||||||
#define _d(fmt, args...) logit(LOG_DEBUG, "%s():" fmt "\n", __func__, ##args)
|
#define _d(fmt, args...) logit(LOG_DEBUG, "%s():" fmt "\n", __func__, ##args)
|
||||||
#define _w(fmt, args...) logit(LOG_WARNING, "%s():" fmt "\n", __func__, ##args)
|
#define _w(fmt, args...) logit(LOG_WARNING, "%s():" fmt "\n", __func__, ##args)
|
||||||
|
|||||||
+286
@@ -0,0 +1,286 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Joachim Nilsson <troglobit@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#define SYSLOG_NAMES
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
static const char version_info[] = PACKAGE_NAME " v" PACKAGE_VERSION;
|
||||||
|
|
||||||
|
|
||||||
|
static int create(char *path, mode_t mode, uid_t uid, gid_t gid)
|
||||||
|
{
|
||||||
|
return mknod(path, S_IFREG | mode, 0) || chown(path, uid, gid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function triggers a log rotates of @file when size >= @sz bytes
|
||||||
|
* At most @num old versions are kept and by default it starts gzipping
|
||||||
|
* .2 and older log files. If gzip is not available in $PATH then @num
|
||||||
|
* files are kept uncompressed.
|
||||||
|
*/
|
||||||
|
static int logrotate(char *file, int num, off_t sz)
|
||||||
|
{
|
||||||
|
int cnt;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if (stat(file, &st))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (sz > 0 && S_ISREG(st.st_mode) && st.st_size > sz) {
|
||||||
|
if (num > 0) {
|
||||||
|
size_t len = strlen(file) + 10 + 1;
|
||||||
|
char ofile[len];
|
||||||
|
char nfile[len];
|
||||||
|
|
||||||
|
/* First age zipped log files */
|
||||||
|
for (cnt = num; cnt > 2; cnt--) {
|
||||||
|
snprintf(ofile, len, "%s.%d.gz", file, cnt - 1);
|
||||||
|
snprintf(nfile, len, "%s.%d.gz", file, cnt);
|
||||||
|
|
||||||
|
/* May fail because ofile doesn't exist yet, ignore. */
|
||||||
|
(void)rename(ofile, nfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (cnt = num; cnt > 0; cnt--) {
|
||||||
|
snprintf(ofile, len, "%s.%d", file, cnt - 1);
|
||||||
|
snprintf(nfile, len, "%s.%d", file, cnt);
|
||||||
|
|
||||||
|
/* May fail because ofile doesn't exist yet, ignore. */
|
||||||
|
(void)rename(ofile, nfile);
|
||||||
|
|
||||||
|
if (cnt == 2 && !access(nfile, F_OK)) {
|
||||||
|
size_t len = 5 + strlen(nfile) + 1;
|
||||||
|
char cmd[len];
|
||||||
|
|
||||||
|
snprintf(cmd, len, "gzip %s", nfile);
|
||||||
|
system(cmd);
|
||||||
|
|
||||||
|
remove(nfile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rename(file, nfile))
|
||||||
|
(void)truncate(file, 0);
|
||||||
|
else
|
||||||
|
create(file, st.st_mode, st.st_uid, st.st_gid);
|
||||||
|
} else {
|
||||||
|
if (truncate(file, 0))
|
||||||
|
syslog(LOG_ERR | LOG_PERROR, "Failed truncating %s during logrotate: %s", file, strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int checksz(FILE *fp, off_t sz)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if (sz <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!fstat(fileno(fp), &st) && st.st_size > sz) {
|
||||||
|
fclose(fp);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int flogit(char *logfile, int num, off_t sz, char *buf, size_t len)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
reopen:
|
||||||
|
fp = fopen(logfile, "a");
|
||||||
|
if (!fp) {
|
||||||
|
syslog(LOG_ERR | LOG_PERROR, "Failed opening %s: %s", logfile, strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf[0]) {
|
||||||
|
fprintf(fp, "%s\n", buf);
|
||||||
|
fsync(fileno(fp));
|
||||||
|
if (checksz(fp, sz))
|
||||||
|
return logrotate(logfile, num, sz);
|
||||||
|
} else {
|
||||||
|
while ((fgets(buf, len, stdin))) {
|
||||||
|
fputs(buf, fp);
|
||||||
|
fsync(fileno(fp));
|
||||||
|
|
||||||
|
if (checksz(fp, sz)) {
|
||||||
|
logrotate(logfile, num, sz);
|
||||||
|
buf[0] = 0;
|
||||||
|
goto reopen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int logit(int level, char *buf, size_t len)
|
||||||
|
{
|
||||||
|
if (buf[0]) {
|
||||||
|
syslog(level, "%s", buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((fgets(buf, len, stdin)))
|
||||||
|
syslog(level, "%s", buf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_prio(char *arg, int *f, int *l)
|
||||||
|
{
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
ptr = strchr(arg, '.');
|
||||||
|
if (ptr) {
|
||||||
|
*ptr++ = 0;
|
||||||
|
|
||||||
|
for (int i = 0; facilitynames[i].c_name; i++) {
|
||||||
|
if (!strcmp(facilitynames[i].c_name, arg)) {
|
||||||
|
*f = facilitynames[i].c_val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
arg = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; prioritynames[i].c_name; i++) {
|
||||||
|
if (!strcmp(prioritynames[i].c_name, arg)) {
|
||||||
|
*l = prioritynames[i].c_val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int usage(int code)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage: logit [OPTIONS] [MESSAGE]\n"
|
||||||
|
"\n"
|
||||||
|
"Write MESSAGE (or stdin) to syslog, or file (with logrotate)\n"
|
||||||
|
"\n"
|
||||||
|
" -h This help text\n"
|
||||||
|
" -p PRIO Priority (numeric or facility.level pair)\n"
|
||||||
|
" -t TAG Log using the specified tag (defaults to user name)\n"
|
||||||
|
" -s Log to stderr as well as the system log\n"
|
||||||
|
"\n"
|
||||||
|
" -f FILE File to write log messages to, instead of syslog\n"
|
||||||
|
" -n SIZE Number of bytes before rotating, default: 200 kB\n"
|
||||||
|
" -r NUM Number of rotated files to keep, default: 5\n"
|
||||||
|
" -v Show program version\n"
|
||||||
|
"\n"
|
||||||
|
"This version of logit is distributed as part of Finit.\n"
|
||||||
|
"Bug report address: %s\n", PACKAGE_BUGREPORT);
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int c, rc, num = 5;
|
||||||
|
int facility = LOG_USER;
|
||||||
|
int level = LOG_INFO;
|
||||||
|
int log_opts = LOG_NOWAIT;
|
||||||
|
off_t size = 200 * 1024;
|
||||||
|
char *ident = NULL, *logfile = NULL;
|
||||||
|
char buf[512] = "";
|
||||||
|
|
||||||
|
while ((c = getopt(argc, argv, "f:hn:p:r:st:v")) != EOF) {
|
||||||
|
switch (c) {
|
||||||
|
case 'f':
|
||||||
|
logfile = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'h':
|
||||||
|
return usage(0);
|
||||||
|
|
||||||
|
case 'n':
|
||||||
|
size = atoi(optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'p':
|
||||||
|
if (parse_prio(optarg, &facility, &level))
|
||||||
|
return usage(1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'r':
|
||||||
|
num = atoi(optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
log_opts |= LOG_PERROR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 't':
|
||||||
|
ident = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'v': /* version */
|
||||||
|
fprintf(stderr, "%s\n", version_info);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return usage(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ident)
|
||||||
|
ident = getenv("LOGNAME") ?: getenv("USER");
|
||||||
|
|
||||||
|
if (optind < argc) {
|
||||||
|
size_t pos = 0, len = sizeof(buf);
|
||||||
|
|
||||||
|
while (optind < argc) {
|
||||||
|
size_t bytes;
|
||||||
|
|
||||||
|
bytes = snprintf(&buf[pos], len, "%s ", argv[optind++]);
|
||||||
|
pos += bytes;
|
||||||
|
len -= bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
openlog(ident, log_opts, facility);
|
||||||
|
|
||||||
|
if (logfile)
|
||||||
|
rc = flogit(logfile, num, size, buf, sizeof(buf));
|
||||||
|
else
|
||||||
|
rc = logit(level, buf, sizeof(buf));
|
||||||
|
|
||||||
|
closelog();
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/* Misc. utility functions and C-library extensions for finit and its plugins
|
/* 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-2015 Joachim Nilsson <troglobit@gmail.com>
|
* Copyright (c) 2008-2018 Joachim Nilsson <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
|
||||||
@@ -23,11 +23,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <paths.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <lite/lite.h>
|
#include <lite/lite.h>
|
||||||
|
|
||||||
|
#include "pid.h"
|
||||||
|
#include "svc.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -42,7 +45,7 @@ int pid_alive(pid_t pid)
|
|||||||
{
|
{
|
||||||
char name[24]; /* Enough for max pid_t */
|
char name[24]; /* Enough for max pid_t */
|
||||||
|
|
||||||
snprintf(name, sizeof(name), "/proc/%d", pid);
|
snprintf(name, sizeof(name), "/proc/%d/status", pid);
|
||||||
|
|
||||||
return fexist(name);
|
return fexist(name);
|
||||||
}
|
}
|
||||||
@@ -90,6 +93,136 @@ char *pid_get_name(pid_t pid, char *name, size_t len)
|
|||||||
return pname;
|
return pname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *pid_file(svc_t *svc)
|
||||||
|
{
|
||||||
|
static char path[256];
|
||||||
|
char fn[MAX_ARG_LEN];
|
||||||
|
|
||||||
|
if (svc->pidfile[0]) {
|
||||||
|
if (svc->pidfile[0] == '!')
|
||||||
|
return &svc->pidfile[1];
|
||||||
|
return svc->pidfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(fn, sizeof(fn), "%s%s.pid", _PATH_VARRUN, basename(svc->cmd));
|
||||||
|
|
||||||
|
return pid_runpath(fn, path, sizeof(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_t pid_file_read(const char *fn)
|
||||||
|
{
|
||||||
|
pid_t pid = 0;
|
||||||
|
FILE *fp;
|
||||||
|
char buf[42];
|
||||||
|
|
||||||
|
fp = fopen(fn, "r");
|
||||||
|
if (!fp)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
chomp(buf);
|
||||||
|
pid = atoi(buf);
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pid_file_create(svc_t *svc)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
if (!svc->pidfile[0] || svc->pidfile[0] == '!')
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
fp = fopen(svc->pidfile, "w");
|
||||||
|
if (!fp)
|
||||||
|
return 1;
|
||||||
|
fprintf(fp, "%d\n", svc->pid);
|
||||||
|
|
||||||
|
return fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pid_realpath(svc_t *svc, char *file)
|
||||||
|
{
|
||||||
|
int not = 0;
|
||||||
|
|
||||||
|
if (!file)
|
||||||
|
file = pid_file(svc);
|
||||||
|
|
||||||
|
if (file[0] == '!') {
|
||||||
|
not = 1;
|
||||||
|
file++;
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_runpath(file, &svc->pidfile[not], sizeof(svc->pidfile) - not);
|
||||||
|
if (not)
|
||||||
|
svc->pidfile[0] = '!';
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function parses a PID file @arg for @svc.
|
||||||
|
*
|
||||||
|
* The logic is explained below. Please note that using the first form
|
||||||
|
* of the syntax not only creates and removes the PID file, but it also
|
||||||
|
* calls touch to update the mtime on service_restart(), only applicable
|
||||||
|
* to processes that accept SIGHUP. This to ensure dependant services
|
||||||
|
* are sent SIGCONT properly on reload, otherwise their condition would
|
||||||
|
* never be asserted again after `initctl reload`.
|
||||||
|
*
|
||||||
|
* pid --> /run/$(basename).pid
|
||||||
|
* pid:foo --> /run/foo.pid
|
||||||
|
* pid:foo.pid --> /run/foo.pid
|
||||||
|
* pid:foo.tla --> /run/foo.tla.pid
|
||||||
|
* pid:/tmp/foo --> /tmp/foo.pid (Not handled by pidfile plugin!)
|
||||||
|
*
|
||||||
|
* An exclamation mark, or logial NOT, in the first character position
|
||||||
|
* indicates that Finit should *not* manage the PID file, and that the
|
||||||
|
* process uses a "non-standard" location. Eg. if service is 'bar'
|
||||||
|
* Finit would assume the PID file is /run/bar.pid and the below simply
|
||||||
|
* 'redirects' Finit to use the correct PID file.
|
||||||
|
*
|
||||||
|
* pid:!foo --> !/run/foo.pid
|
||||||
|
* pid:!/run/foo.pid --> !/run/foo.pid
|
||||||
|
*
|
||||||
|
* Note, nothing is created or removed by Finit in this latter form.
|
||||||
|
*/
|
||||||
|
int pid_file_parse(svc_t *svc, char *arg)
|
||||||
|
{
|
||||||
|
/* Sanity check ... */
|
||||||
|
if (!arg || !arg[0])
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* 'pid:' implies argument following*/
|
||||||
|
if (!strncmp(arg, "pid:", 4)) {
|
||||||
|
int len, not = 0;
|
||||||
|
char path[MAX_ARG_LEN];
|
||||||
|
|
||||||
|
arg += 4;
|
||||||
|
if ((arg[0] == '!' && arg[1] == '/') || arg[0] == '/')
|
||||||
|
return pid_realpath(svc, arg);
|
||||||
|
|
||||||
|
if (arg[0] == '!') {
|
||||||
|
arg++;
|
||||||
|
not++;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = snprintf(path, sizeof(path), "%s%s%s", not ? "!" : "", _PATH_VARRUN, arg);
|
||||||
|
if (len > 4 && strcmp(&path[len - 4], ".pid"))
|
||||||
|
strlcat(path, ".pid", sizeof(path));
|
||||||
|
|
||||||
|
return pid_realpath(svc, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 'pid' arg, no argument following */
|
||||||
|
if (!strcmp(arg, "pid"))
|
||||||
|
return pid_realpath(svc, NULL);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/* PID and PID file helpers
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||||
|
* Copyright (c) 2008-2018 Joachim Nilsson <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_PID_H_
|
||||||
|
#define FINIT_PID_H_
|
||||||
|
|
||||||
|
#include "svc.h"
|
||||||
|
|
||||||
|
int pid_alive (pid_t pid);
|
||||||
|
char *pid_get_name (pid_t pid, char *name, size_t len);
|
||||||
|
|
||||||
|
char *pid_file (svc_t *svc);
|
||||||
|
pid_t pid_file_read (const char *fn);
|
||||||
|
int pid_file_create (svc_t *svc);
|
||||||
|
int pid_file_parse (svc_t *svc, char *arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pid_runpath - Adjust /var/run --> /run path depending on system
|
||||||
|
* @file: Path to file in /run/path or /var/run/path
|
||||||
|
* @path: Pointer to buffer to write correct path
|
||||||
|
* @len: Length, in bytes, of @path buffer
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* Always returns a valid pointer, which can be either @path with a /run
|
||||||
|
* or /var/run prefix to @file, or it may be @file if the prefix is OK.
|
||||||
|
*/
|
||||||
|
static inline char *pid_runpath(const char *file, char *path, size_t len)
|
||||||
|
{
|
||||||
|
static char *prefix = "/var/run";
|
||||||
|
static int unknown = 1;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (unknown) {
|
||||||
|
if (fisdir("/run"))
|
||||||
|
prefix = "/run";
|
||||||
|
unknown = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strncmp(file, "/var/run/", 9))
|
||||||
|
file += 9;
|
||||||
|
else if (!strncmp(file, "/run/", 5))
|
||||||
|
file += 5;
|
||||||
|
|
||||||
|
rc = snprintf(path, len, "%s/%s", prefix, file);
|
||||||
|
if (rc < 0 || (size_t)rc >= len)
|
||||||
|
_e("File path '%s' truncated, should end with '%s'", path, file);
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* FINIT_PID_H_ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Variables:
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
+7
-21
@@ -108,6 +108,9 @@ int plugin_register(plugin_t *plugin)
|
|||||||
/* Not called, at the moment plugins cannot be unloaded. */
|
/* Not called, at the moment plugins cannot be unloaded. */
|
||||||
int plugin_unregister(plugin_t *plugin)
|
int plugin_unregister(plugin_t *plugin)
|
||||||
{
|
{
|
||||||
|
if (is_io_plugin(plugin))
|
||||||
|
uev_io_stop(&plugin->watcher);
|
||||||
|
|
||||||
#ifndef ENABLE_STATIC
|
#ifndef ENABLE_STATIC
|
||||||
TAILQ_REMOVE(&plugins, plugin, link);
|
TAILQ_REMOVE(&plugins, plugin, link);
|
||||||
|
|
||||||
@@ -186,21 +189,11 @@ int plugin_exists(hook_point_t no)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Some hooks are called with a fixed argument, like HOOK_SVC_LOST */
|
/* 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)
|
||||||
{
|
{
|
||||||
static int last = -1;
|
|
||||||
plugin_t *p, *tmp;
|
plugin_t *p, *tmp;
|
||||||
|
|
||||||
/*
|
|
||||||
* End recursion: any plugin hook => start service => SVC start
|
|
||||||
* hook => start service ... err ... wait a second
|
|
||||||
*/
|
|
||||||
if (HOOK_SVC_START == last) {
|
|
||||||
_d("End plugin recursion in our lifetime!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
_d("Calling %s hook n:o %d (arg: %p) ...", basename(p->name), no, arg);
|
||||||
@@ -208,15 +201,8 @@ void plugin_run_hook(hook_point_t no, void *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Guard against infinite recursion */
|
cond_set_oneshot(hook_cond[no]);
|
||||||
if (HOOK_SVC_START == no)
|
|
||||||
last = no;
|
|
||||||
|
|
||||||
cond_set(hook_cond[no]);
|
|
||||||
service_step_all(SVC_TYPE_RUNTASK);
|
service_step_all(SVC_TYPE_RUNTASK);
|
||||||
|
|
||||||
if (HOOK_SVC_START == no)
|
|
||||||
last = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Regular hooks are called with the registered plugin's argument */
|
/* Regular hooks are called with the registered plugin's argument */
|
||||||
@@ -384,11 +370,11 @@ static int load_plugins(char *path)
|
|||||||
}
|
}
|
||||||
#endif /* ENABLE_STATIC */
|
#endif /* ENABLE_STATIC */
|
||||||
|
|
||||||
int plugin_init(uev_ctx_t *ctx, char *path)
|
int plugin_init(uev_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
int fail = 1;
|
int fail = 1;
|
||||||
|
|
||||||
if (!load_plugins(path))
|
if (!load_plugins(PLUGIN_PATH))
|
||||||
fail = init_plugins(ctx);
|
fail = init_plugins(ctx);
|
||||||
|
|
||||||
return fail;
|
return fail;
|
||||||
|
|||||||
+13
-8
@@ -29,10 +29,6 @@
|
|||||||
|
|
||||||
#include "svc.h"
|
#include "svc.h"
|
||||||
|
|
||||||
#ifndef PLUGIN_PATH /* Fallback for --enable-static builds */
|
|
||||||
#define PLUGIN_PATH "/dev/null"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define PLUGIN_DEP_MAX 10
|
#define PLUGIN_DEP_MAX 10
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -54,22 +50,31 @@
|
|||||||
* Predefined hook points and corresponding conditions in Finit,
|
* Predefined hook points and corresponding conditions in Finit,
|
||||||
* for use by plugins and scripts. Recommended to use the task
|
* for use by plugins and scripts. Recommended to use the task
|
||||||
* or run stanzas: task <hook/mount/error> /bin/rescue.sh
|
* or run stanzas: task <hook/mount/error> /bin/rescue.sh
|
||||||
|
*
|
||||||
|
* Some of the below hooks cannot (currently) be realized as conditions.
|
||||||
|
* The idea was to rename them action scripts, with optional argument,
|
||||||
|
* according to the following scheme:
|
||||||
|
*
|
||||||
|
* - HOOK_SVC_RECONF :: action/svc/reconf
|
||||||
|
* - HOOK_RUNLEVEL_CHANGE :: action/sys/runlevel
|
||||||
|
*
|
||||||
|
* However, the implementation did not turn out to be stable enough for
|
||||||
|
* general release, so it was pulled.
|
||||||
*/
|
*/
|
||||||
#define HOOK_TYPES { \
|
#define HOOK_TYPES { \
|
||||||
/* Bootstrap hooks, runlevel [S] */ \
|
/* Bootstrap hooks, runlevel [S] */ \
|
||||||
CHOOSE(HOOK_BANNER = 0, "hook/sys/banner"), \
|
CHOOSE(HOOK_BANNER = 0, "hook/sys/banner"), \
|
||||||
CHOOSE(HOOK_ROOTFS_UP, "hook/mount/root"), \
|
CHOOSE(HOOK_ROOTFS_UP, "hook/mount/root"), \
|
||||||
CHOOSE(HOOK_MOUNT_ERROR, "hook/mount/error"), \
|
CHOOSE(HOOK_MOUNT_ERROR, "hook/mount/error"), \
|
||||||
|
CHOOSE(HOOK_MOUNT_POST, "hook/mount/post"), \
|
||||||
CHOOSE(HOOK_BASEFS_UP, "hook/mount/all"), \
|
CHOOSE(HOOK_BASEFS_UP, "hook/mount/all"), \
|
||||||
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"), \
|
||||||
\
|
\
|
||||||
/* Runtime hooks, runlevel [S1-9] */ \
|
/* Runtime hooks, runlevel [S1-9] */ \
|
||||||
CHOOSE(HOOK_SVC_RECONF, "hook/svc/reconf"), \
|
CHOOSE(HOOK_SVC_RECONF, "nop"), \
|
||||||
CHOOSE(HOOK_SVC_LOST, "hook/svc/lost"), \
|
CHOOSE(HOOK_RUNLEVEL_CHANGE, "nop"), \
|
||||||
CHOOSE(HOOK_SVC_START, "hook/svc/start"), \
|
|
||||||
CHOOSE(HOOK_RUNLEVEL_CHANGE, "hook/sys/runlevel"), \
|
|
||||||
\
|
\
|
||||||
/* Shutdown hooks, runlevel [06] */ \
|
/* Shutdown hooks, runlevel [06] */ \
|
||||||
CHOOSE(HOOK_SHUTDOWN, "hook/sys/shutdown"), \
|
CHOOSE(HOOK_SHUTDOWN, "hook/sys/shutdown"), \
|
||||||
|
|||||||
+2
-7
@@ -28,24 +28,19 @@
|
|||||||
#include "svc.h"
|
#include "svc.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
|
||||||
/*
|
|
||||||
* Main loop context
|
|
||||||
*/
|
|
||||||
uev_ctx_t *ctx;
|
|
||||||
|
|
||||||
int api_init (uev_ctx_t *ctx);
|
int api_init (uev_ctx_t *ctx);
|
||||||
int api_exit (void);
|
int api_exit (void);
|
||||||
|
|
||||||
int client (int argc, char *argv[]);
|
int client (int argc, char *argv[]);
|
||||||
|
|
||||||
void service_monitor (pid_t lost);
|
void service_monitor (pid_t lost, int status);
|
||||||
|
|
||||||
const char *plugin_hook_str(hook_point_t no);
|
const char *plugin_hook_str(hook_point_t no);
|
||||||
int plugin_exists (hook_point_t no);
|
int plugin_exists (hook_point_t no);
|
||||||
void plugin_run_hook (hook_point_t no, void *arg);
|
void plugin_run_hook (hook_point_t no, void *arg);
|
||||||
void plugin_run_hooks (hook_point_t no);
|
void plugin_run_hooks (hook_point_t no);
|
||||||
|
|
||||||
int plugin_init (uev_ctx_t *ctx, char *path);
|
int plugin_init (uev_ctx_t *ctx);
|
||||||
void plugin_exit (void);
|
void plugin_exit (void);
|
||||||
|
|
||||||
#endif /* FINIT_PRIVATE_H_ */
|
#endif /* FINIT_PRIVATE_H_ */
|
||||||
|
|||||||
+1
-1
@@ -207,7 +207,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
if (c)
|
if (c)
|
||||||
err(1, "Failed signalling init to %s", msg);
|
err(1, "Failed signalling init to %s", msg);
|
||||||
do_sleep(2);
|
do_sleep(5);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
runlevel 1
|
||||||
|
hostname rescue
|
||||||
|
tty [12345] @console noclear nologin
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/* Example HOOK_SVC_LOST plugin, very noisy do not use as-is!
|
/* Work queue helper functions
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016 Joachim Nilsson <troglobit@gmail.com>
|
* Copyright (c) 2018 Joachim Nilsson <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,35 +21,44 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "svc.h"
|
#include "schedule.h"
|
||||||
#include "plugin.h"
|
|
||||||
|
|
||||||
static void lost_pid(void *arg)
|
#define SC_INIT 0x494E4954 /* "INIT", see ascii(7) */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* libuEv callback wrapper
|
||||||
|
*/
|
||||||
|
static void cb(uev_t *w, void *arg, int events)
|
||||||
{
|
{
|
||||||
pid_t pid = (uintptr_t)arg;
|
struct wq *work = (struct wq *)arg;
|
||||||
svc_t *svc;
|
|
||||||
|
|
||||||
svc = svc_find_by_pid(pid);
|
if (UEV_ERROR == events) {
|
||||||
if (!svc)
|
uev_timer_start(w);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
logit(LOG_INFO, "Lost PID %u, svc %s", pid, svc->cmd);
|
work->cb(work);
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
/*
|
||||||
.name = __FILE__,
|
* Place work on event queue
|
||||||
.hook[HOOK_SVC_LOST] = { .cb = lost_pid },
|
*/
|
||||||
};
|
int schedule_work(struct wq *work)
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
|
||||||
{
|
{
|
||||||
plugin_register(&plugin);
|
int msec;
|
||||||
}
|
|
||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
if (!work)
|
||||||
{
|
return errno = EINVAL;
|
||||||
plugin_unregister(&plugin);
|
|
||||||
|
msec = work->delay;
|
||||||
|
if (work->init != SC_INIT) {
|
||||||
|
work->init = SC_INIT;
|
||||||
|
return uev_timer_init(ctx, &work->watcher, cb, work, msec, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return uev_timer_set(&work->watcher, msec, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/* Save and restore RTC using hwclock
|
/* Work queue helper functions
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com>
|
* Copyright (c) 2018 Joachim Nilsson <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,49 +21,17 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <lite/lite.h>
|
#ifndef FINIT_SCHEDULE_H_
|
||||||
|
#define FINIT_SCHEDULE_H_
|
||||||
|
|
||||||
#include "finit.h"
|
struct wq {
|
||||||
#include "helpers.h"
|
uev_t watcher;
|
||||||
#include "plugin.h"
|
int init;
|
||||||
|
int delay; /* msec delay before starting work */
|
||||||
static void save(void *arg)
|
void (*cb)(void *);
|
||||||
{
|
void *arg;
|
||||||
_d("Saving system clock to RTC ...");
|
|
||||||
/* -w,--systohc, -u,--utc */
|
|
||||||
run_interactive("hwclock -w -u", "Saving system time (UTC) to RTC");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void restore(void *arg)
|
|
||||||
{
|
|
||||||
_d("Restoring system clock from RTC ...");
|
|
||||||
/* -s,--hctosys, -u,--utc */
|
|
||||||
run_interactive("hwclock -s -u", "Restoring system clock (UTC) from RTC");
|
|
||||||
}
|
|
||||||
|
|
||||||
static plugin_t plugin = {
|
|
||||||
.name = __FILE__,
|
|
||||||
.hook[HOOK_BASEFS_UP] = {
|
|
||||||
.cb = restore
|
|
||||||
},
|
|
||||||
.hook[HOOK_SHUTDOWN] = {
|
|
||||||
.cb = save
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
int schedule_work(struct wq *work);
|
||||||
{
|
|
||||||
plugin_register(&plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
#endif /* FINIT_SCHEDULE_H_ */
|
||||||
{
|
|
||||||
plugin_unregister(&plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Local Variables:
|
|
||||||
* indent-tabs-mode: t
|
|
||||||
* c-file-style: "linux"
|
|
||||||
* End:
|
|
||||||
*/
|
|
||||||
+19
-7
@@ -120,7 +120,7 @@ int serv_list(char *arg)
|
|||||||
if (fisdir(enabled))
|
if (fisdir(enabled))
|
||||||
do_list("ENABLED ", enabled);
|
do_list("ENABLED ", enabled);
|
||||||
if (fisdir(FINIT_RCSD))
|
if (fisdir(FINIT_RCSD))
|
||||||
do_list("ENABLED ", FINIT_RCSD);
|
do_list("STATIC ", FINIT_RCSD);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -128,8 +128,11 @@ int serv_list(char *arg)
|
|||||||
int serv_enable(char *arg)
|
int serv_enable(char *arg)
|
||||||
{
|
{
|
||||||
char corr[40];
|
char corr[40];
|
||||||
char link[80];
|
char link[256];
|
||||||
char path[80];
|
char path[256];
|
||||||
|
|
||||||
|
if (!arg || !arg[0])
|
||||||
|
return serv_list(NULL);
|
||||||
|
|
||||||
if (!strstr(arg, ".conf")) {
|
if (!strstr(arg, ".conf")) {
|
||||||
snprintf(corr, sizeof(corr), "%s.conf", arg);
|
snprintf(corr, sizeof(corr), "%s.conf", arg);
|
||||||
@@ -137,11 +140,14 @@ int serv_enable(char *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pushd(FINIT_RCSD);
|
pushd(FINIT_RCSD);
|
||||||
snprintf(path, sizeof(path), "available/%s", arg);
|
if (mkdir("enabled", 0755) && EEXIST != errno)
|
||||||
|
err(1, "Failed creating %s/enabled directory", FINIT_RCSD);
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "%s/%s", available, arg);
|
||||||
if (!fexist(path))
|
if (!fexist(path))
|
||||||
errx(1, "Cannot find %s", path);
|
errx(1, "Cannot find %s", path);
|
||||||
|
|
||||||
snprintf(link, sizeof(link), "%s/%s", FINIT_RCSD, arg);
|
snprintf(link, sizeof(link), "%s/%s", enabled, arg);
|
||||||
if (fexist(link))
|
if (fexist(link))
|
||||||
errx(1, "%s already exists", link);
|
errx(1, "%s already exists", link);
|
||||||
|
|
||||||
@@ -151,15 +157,18 @@ int serv_enable(char *arg)
|
|||||||
int serv_disable(char *arg)
|
int serv_disable(char *arg)
|
||||||
{
|
{
|
||||||
char corr[40];
|
char corr[40];
|
||||||
char link[80];
|
char link[256];
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
|
if (!arg || !arg[0])
|
||||||
|
return serv_list(NULL);
|
||||||
|
|
||||||
if (!strstr(arg, ".conf")) {
|
if (!strstr(arg, ".conf")) {
|
||||||
snprintf(corr, sizeof(corr), "%s.conf", arg);
|
snprintf(corr, sizeof(corr), "%s.conf", arg);
|
||||||
arg = corr;
|
arg = corr;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(link, sizeof(link), "%s/%s", FINIT_RCSD, arg);
|
snprintf(link, sizeof(link), "%s/%s", enabled, arg);
|
||||||
if (stat(link, &st))
|
if (stat(link, &st))
|
||||||
err(1, "Cannot find %s", link);
|
err(1, "Cannot find %s", link);
|
||||||
|
|
||||||
@@ -173,6 +182,9 @@ int serv_touch(char *arg)
|
|||||||
{
|
{
|
||||||
char corr[40];
|
char corr[40];
|
||||||
|
|
||||||
|
if (!arg || !arg[0])
|
||||||
|
return serv_list(NULL);
|
||||||
|
|
||||||
if (!strstr(arg, ".conf")) {
|
if (!strstr(arg, ".conf")) {
|
||||||
snprintf(corr, sizeof(corr), "%s.conf", arg);
|
snprintf(corr, sizeof(corr), "%s.conf", arg);
|
||||||
arg = corr;
|
arg = corr;
|
||||||
|
|||||||
+646
-217
File diff suppressed because it is too large.
Load diff
+3
-2
@@ -34,10 +34,11 @@ 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_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_bootstrap_cb (uev_t *w, void *arg, int events);
|
int service_completed (void);
|
||||||
|
|
||||||
#endif /* FINIT_SERVICE_H_ */
|
#endif /* FINIT_SERVICE_H_ */
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,8 @@
|
|||||||
*
|
*
|
||||||
* SIGHUP
|
* SIGHUP
|
||||||
* Same effect as init/telinit q, reloads *.conf in /etc/finit.d/
|
* Same effect as init/telinit q, reloads *.conf in /etc/finit.d/
|
||||||
|
* Also restarts API (initctl) socket, like SysV init and systemd
|
||||||
|
* does on USR1 with their FIFO/D-Bus.
|
||||||
*
|
*
|
||||||
* SIGUSR1
|
* SIGUSR1
|
||||||
* Calls shutdown hooks, including HOOK_SHUTDOWN, stops all running
|
* Calls shutdown hooks, including HOOK_SHUTDOWN, stops all running
|
||||||
@@ -81,6 +83,8 @@
|
|||||||
#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
|
||||||
@@ -94,6 +98,55 @@ static uev_t sighup_watcher, sigint_watcher, sigpwr_watcher;
|
|||||||
static uev_t sigchld_watcher;
|
static uev_t sigchld_watcher;
|
||||||
static uev_t sigstop_watcher, sigtstp_watcher, sigcont_watcher;
|
static uev_t sigstop_watcher, sigtstp_watcher, sigcont_watcher;
|
||||||
|
|
||||||
|
static struct sigmap {
|
||||||
|
int num;
|
||||||
|
char *name;
|
||||||
|
} signames[] = {
|
||||||
|
/* ISO C99 signals. */
|
||||||
|
{ SIGINT, "SIGINT" },
|
||||||
|
{ SIGILL, "SIGILL" },
|
||||||
|
{ SIGABRT, "SIGABRT" },
|
||||||
|
{ SIGFPE, "SIGFPE" },
|
||||||
|
{ SIGSEGV, "SIGSEGV" },
|
||||||
|
{ SIGTERM, "SIGTERM" },
|
||||||
|
/* Historical signals specified by POSIX. */
|
||||||
|
{ SIGHUP, "SIGHUP" },
|
||||||
|
{ SIGQUIT, "SIGQUIT" },
|
||||||
|
{ SIGTRAP, "SIGTRAP" },
|
||||||
|
{ SIGKILL, "SIGKILL" },
|
||||||
|
{ SIGBUS, "SIGBUS" },
|
||||||
|
{ SIGSYS, "SIGSYS" },
|
||||||
|
{ SIGPIPE, "SIGPIPE" },
|
||||||
|
{ SIGALRM, "SIGALRM" },
|
||||||
|
|
||||||
|
/* New(er) POSIX signals (1003.1-2008, 1003.1-2013). */
|
||||||
|
{ SIGURG, "SIGURG" },
|
||||||
|
{ SIGSTOP, "SIGSTOP" },
|
||||||
|
{ SIGTSTP, "SIGTSTP" },
|
||||||
|
{ SIGCONT, "SIGCONT" },
|
||||||
|
{ SIGCHLD, "SIGCHLD" },
|
||||||
|
{ SIGTTIN, "SIGTTIN" },
|
||||||
|
{ SIGTTOU, "SIGTTOU" },
|
||||||
|
{ SIGPOLL, "SIGPOLL" },
|
||||||
|
{ SIGXCPU, "SIGXCPU" },
|
||||||
|
{ SIGXFSZ, "SIGXFSZ" },
|
||||||
|
{ SIGVTALRM, "SIGVTALRM" },
|
||||||
|
{ SIGPROF, "SIGPROF" },
|
||||||
|
{ SIGUSR1, "SIGUSR1" },
|
||||||
|
{ SIGUSR2, "SIGUSR2" },
|
||||||
|
|
||||||
|
/* Nonstandard signals found in all modern POSIX systems
|
||||||
|
(including both BSD and Linux). */
|
||||||
|
{ SIGWINCH, "SIGWINCH" },
|
||||||
|
{ SIGSTKFLT, "SIGSTKFLT" },
|
||||||
|
{ SIGPWR, "SIGPWR" },
|
||||||
|
|
||||||
|
/* Archaic names for compatibility. */
|
||||||
|
{ SIGIO, "SIGIO" },
|
||||||
|
{ SIGIOT, "SIGIOT" },
|
||||||
|
{ SIGCLD, "SIGCLD" },
|
||||||
|
};
|
||||||
|
|
||||||
void mdadm_wait(void);
|
void mdadm_wait(void);
|
||||||
void unmount_tmpfs(void);
|
void unmount_tmpfs(void);
|
||||||
void unmount_regular(void);
|
void unmount_regular(void);
|
||||||
@@ -131,8 +184,12 @@ void do_kill(int signo)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (fgets(file, sizeof(file), fp)) {
|
if (fgets(file, sizeof(file), fp)) {
|
||||||
if (file[0] != '@')
|
if (strstr(file, "gdbserver"))
|
||||||
|
_d("Skipping %s ...", file);
|
||||||
|
else if (file[0] != '@')
|
||||||
kill(pid, signo);
|
kill(pid, signo);
|
||||||
|
else
|
||||||
|
_d("Skipping %s ...", &file[1]);
|
||||||
}
|
}
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
@@ -179,6 +236,11 @@ void do_shutdown(shutop_t op)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wdog) {
|
||||||
|
print(kill(wdog->pid, SIGPWR) == 1, "Advising watchdog, system going down");
|
||||||
|
do_sleep(2);
|
||||||
|
}
|
||||||
|
|
||||||
/* Unmount any tmpfs before unmounting swap ... */
|
/* Unmount any tmpfs before unmounting swap ... */
|
||||||
unmount_tmpfs();
|
unmount_tmpfs();
|
||||||
run("swapoff -e -a");
|
run("swapoff -e -a");
|
||||||
@@ -197,11 +259,11 @@ void do_shutdown(shutop_t op)
|
|||||||
|
|
||||||
/* Reboot via watchdog or kernel, or shutdown? */
|
/* Reboot via watchdog or kernel, or shutdown? */
|
||||||
if (op == SHUT_REBOOT) {
|
if (op == SHUT_REBOOT) {
|
||||||
if (wdogpid) {
|
if (wdog) {
|
||||||
int timeout = 10;
|
int timeout = 10;
|
||||||
|
|
||||||
/* Wait here until the WDT reboots, or timeout with fallback */
|
/* Wait here until the WDT reboots, or timeout with fallback */
|
||||||
print(kill(wdogpid, SIGPWR) == 1, "Pending watchdog reboot");
|
print(kill(wdog->pid, SIGTERM) == 1, "Pending watchdog reboot");
|
||||||
while (timeout--)
|
while (timeout--)
|
||||||
do_sleep(1);
|
do_sleep(1);
|
||||||
}
|
}
|
||||||
@@ -229,6 +291,10 @@ static void sighup_cb(uev_t *w, void *arg, int events)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Restart initctl API domain socket, similar to systemd/SysV init */
|
||||||
|
api_exit();
|
||||||
|
api_init(w->ctx);
|
||||||
|
|
||||||
/* INIT_CMD_RELOAD: 'init q', 'initctl reload', and SIGHUP */
|
/* INIT_CMD_RELOAD: 'init q', 'initctl reload', and SIGHUP */
|
||||||
service_reload_dynamic();
|
service_reload_dynamic();
|
||||||
}
|
}
|
||||||
@@ -299,6 +365,7 @@ static void sigterm_cb(uev_t *w, void *arg, int events)
|
|||||||
static void sigchld_cb(uev_t *w, void *arg, int events)
|
static void sigchld_cb(uev_t *w, void *arg, int events)
|
||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
int status;
|
||||||
|
|
||||||
if (UEV_ERROR == events) {
|
if (UEV_ERROR == events) {
|
||||||
_e("Unrecoverable error in signal watcher");
|
_e("Unrecoverable error in signal watcher");
|
||||||
@@ -307,10 +374,10 @@ static void sigchld_cb(uev_t *w, void *arg, int events)
|
|||||||
|
|
||||||
/* Reap all the children! */
|
/* Reap all the children! */
|
||||||
do {
|
do {
|
||||||
pid = waitpid(-1, NULL, WNOHANG);
|
pid = waitpid(-1, &status, WNOHANG);
|
||||||
if (pid > 0) {
|
if (pid > 0) {
|
||||||
_d("Collected child %d", pid);
|
_d("Collected child %d", pid);
|
||||||
service_monitor(pid);
|
service_monitor(pid, status);
|
||||||
}
|
}
|
||||||
} while (pid > 0);
|
} while (pid > 0);
|
||||||
}
|
}
|
||||||
@@ -351,6 +418,38 @@ int sig_stopped(void)
|
|||||||
return stopped;
|
return stopped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert SIGFOO to a number, if it exists
|
||||||
|
*/
|
||||||
|
int sig_num(const char *name)
|
||||||
|
{
|
||||||
|
size_t i, offset = 0;
|
||||||
|
|
||||||
|
if (strncasecmp(name, "SIG", 3))
|
||||||
|
offset = 3;
|
||||||
|
|
||||||
|
for (i = 0; i < NELEMS(signames); i++) {
|
||||||
|
if (strcasecmp(name, &signames[i].name[offset]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return signames[i].num;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *sig_name(int signo)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < NELEMS(signames); i++) {
|
||||||
|
if (signames[i].num == signo)
|
||||||
|
return signames[i].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "SIGUNKOWN";
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Inital signal setup - ignore everything but SIGCHLD until we're capable of responding
|
* Inital signal setup - ignore everything but SIGCHLD until we're capable of responding
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -70,10 +70,13 @@ extern shutop_t halt;
|
|||||||
|
|
||||||
void do_shutdown (shutop_t op);
|
void do_shutdown (shutop_t op);
|
||||||
int sig_stopped (void);
|
int sig_stopped (void);
|
||||||
|
int sig_num (const char *name);
|
||||||
void sig_init (void);
|
void sig_init (void);
|
||||||
void sig_unblock (void);
|
void sig_unblock (void);
|
||||||
void sig_setup (uev_ctx_t *ctx);
|
void sig_setup (uev_ctx_t *ctx);
|
||||||
|
|
||||||
|
const char *sig_name(int signo);
|
||||||
|
|
||||||
#endif /* FINIT_SIG_H_ */
|
#endif /* FINIT_SIG_H_ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -72,6 +72,22 @@ static char *sm_status(sm_state_t state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable login in single user mode and shutdown/reboot
|
||||||
|
*
|
||||||
|
* Re-enable only when going from these runlevels, this way a user can
|
||||||
|
* manage /etc/nologin manually within the other runlevels without us
|
||||||
|
* pulling the rug from under their feet.
|
||||||
|
*/
|
||||||
|
static void nologin(void)
|
||||||
|
{
|
||||||
|
if (runlevel == 1 || runlevel == 0 || runlevel == 6)
|
||||||
|
touch("/etc/nologin");
|
||||||
|
|
||||||
|
if (prevlevel == 1 || prevlevel == 0 || prevlevel == 6)
|
||||||
|
erase("/etc/nologin");
|
||||||
|
}
|
||||||
|
|
||||||
void sm_set_runlevel(sm_t *sm, int newlevel)
|
void sm_set_runlevel(sm_t *sm, int newlevel)
|
||||||
{
|
{
|
||||||
sm->newlevel = newlevel;
|
sm->newlevel = newlevel;
|
||||||
@@ -101,7 +117,7 @@ restart:
|
|||||||
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);
|
_d("Bootstrapping all services in runlevel S from %s", FINIT_CONF);
|
||||||
service_step_all(SVC_TYPE_RUN | SVC_TYPE_TASK | SVC_TYPE_SERVICE);
|
service_step_all(SVC_TYPE_RUNTASK | SVC_TYPE_SERVICE);
|
||||||
sm->state = SM_RUNNING_STATE;
|
sm->state = SM_RUNNING_STATE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -134,22 +150,20 @@ restart:
|
|||||||
}
|
}
|
||||||
|
|
||||||
_d("Setting new runlevel --> %d <-- previous %d", runlevel, prevlevel);
|
_d("Setting new runlevel --> %d <-- previous %d", runlevel, prevlevel);
|
||||||
|
logit(LOG_CONSOLE | LOG_NOTICE, "%s, entering runlevel %d", INIT_HEADING, 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 */
|
||||||
if (runlevel == 1 || runlevel == 0 || runlevel == 6)
|
nologin();
|
||||||
touch("/etc/nologin");
|
|
||||||
else
|
|
||||||
erase("/etc/nologin");
|
|
||||||
|
|
||||||
/* Make sure to (re)load all *.conf in /etc/finit.d/ */
|
/* Make sure to (re)load all *.conf in /etc/finit.d/ */
|
||||||
if (runlevel != 0 && runlevel != 6)
|
if (conf_any_change())
|
||||||
conf_reload();
|
conf_reload();
|
||||||
|
|
||||||
/* Reset once flag of runtasks */
|
/* Reset once flag of runtasks */
|
||||||
service_runtask_clean();
|
service_runtask_clean();
|
||||||
|
|
||||||
_d("Stopping services services not allowed in new runlevel ...");
|
_d("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);
|
||||||
|
|
||||||
@@ -171,7 +185,7 @@ restart:
|
|||||||
_d("All services have been stoppped, calling runlevel change hooks ...");
|
_d("All services have been stoppped, 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 services new to this runlevel ...");
|
_d("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);
|
||||||
|
|
||||||
@@ -205,7 +219,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 services not allowed after reconf ...");
|
_d("Stopping services not allowed after reconf ...");
|
||||||
sm->in_teardown = 1;
|
sm->in_teardown = 1;
|
||||||
cond_reload();
|
cond_reload();
|
||||||
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_INETD);
|
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_INETD);
|
||||||
|
|||||||
+8
-2
@@ -95,7 +95,7 @@ void stty(int fd, speed_t speed)
|
|||||||
tcflush(fd, TCIOFLUSH);
|
tcflush(fd, TCIOFLUSH);
|
||||||
|
|
||||||
/* Disable modem specific flags */
|
/* Disable modem specific flags */
|
||||||
term.c_cflag &= ~(0|CSTOPB|PARENB|PARODD);
|
term.c_cflag &= ~(0|CSTOPB|PARENB|PARODD|CBAUDEX);
|
||||||
term.c_cflag &= ~CRTSCTS;
|
term.c_cflag &= ~CRTSCTS;
|
||||||
term.c_cflag |= CLOCAL;
|
term.c_cflag |= CLOCAL;
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@ void stty(int fd, speed_t speed)
|
|||||||
term.c_cc[VMIN] = 1;
|
term.c_cc[VMIN] = 1;
|
||||||
term.c_iflag = ICRNL|IXON|IXOFF;
|
term.c_iflag = ICRNL|IXON|IXOFF;
|
||||||
term.c_oflag = OPOST|ONLCR;
|
term.c_oflag = OPOST|ONLCR;
|
||||||
term.c_cflag |= CS8|CREAD|HUPCL|CBAUDEX;
|
term.c_cflag |= CS8|CREAD|HUPCL;
|
||||||
term.c_lflag |= ICANON|ISIG|ECHO|ECHOE|ECHOK|ECHOKE;
|
term.c_lflag |= ICANON|ISIG|ECHO|ECHOE|ECHOK|ECHOKE;
|
||||||
|
|
||||||
/* Reset special characters to defaults */
|
/* Reset special characters to defaults */
|
||||||
@@ -115,6 +115,12 @@ void stty(int fd, speed_t speed)
|
|||||||
term.c_cc[VKILL] = CTRL('U');
|
term.c_cc[VKILL] = CTRL('U');
|
||||||
term.c_cc[VERASE] = CERASE;
|
term.c_cc[VERASE] = CERASE;
|
||||||
tcsetattr(fd, TCSANOW, &term);
|
tcsetattr(fd, TCSANOW, &term);
|
||||||
|
|
||||||
|
/* Show cursor again, if it was hidden previously */
|
||||||
|
write(fd, "\033[?25h", 6);
|
||||||
|
|
||||||
|
/* Enable line wrap, if disabled previously */
|
||||||
|
write(fd, "\033[7h", 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <ctype.h> /* isdigit() */
|
#include <ctype.h> /* isdigit() */
|
||||||
|
#include <time.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
@@ -32,11 +33,40 @@
|
|||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "svc.h"
|
#include "svc.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
#include "pid.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "cond.h"
|
||||||
|
#include "schedule.h"
|
||||||
|
|
||||||
/* Each svc_t needs a unique job# */
|
/* Each svc_t needs a unique job# */
|
||||||
static int jobcounter = 1;
|
static int jobcounter = 1;
|
||||||
static TAILQ_HEAD(head, svc) svc_list = TAILQ_HEAD_INITIALIZER(svc_list);
|
static TAILQ_HEAD(, svc) svc_list = TAILQ_HEAD_INITIALIZER(svc_list);
|
||||||
|
static TAILQ_HEAD(, svc) gc_list = TAILQ_HEAD_INITIALIZER(gc_list);
|
||||||
|
|
||||||
|
static void svc_gc(void *arg)
|
||||||
|
{
|
||||||
|
struct timespec now;
|
||||||
|
struct wq *work = (struct wq *)arg;
|
||||||
|
svc_t *svc, *next;
|
||||||
|
|
||||||
|
clock_gettime(CLOCK_MONOTONIC_COARSE, &now);
|
||||||
|
TAILQ_FOREACH_SAFE(svc, &gc_list, link, next) {
|
||||||
|
char cond[MAX_COND_LEN];
|
||||||
|
int msec;
|
||||||
|
|
||||||
|
msec = (now.tv_sec - svc->gc.tv_sec) * 1000 +
|
||||||
|
(now.tv_nsec - svc->gc.tv_nsec) / 1000000;
|
||||||
|
if (msec < SVC_TERM_TIMEOUT)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
TAILQ_REMOVE(&gc_list, svc, link);
|
||||||
|
cond_clear(mkcond(svc, cond, sizeof(cond)));
|
||||||
|
free(svc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TAILQ_EMPTY(&gc_list))
|
||||||
|
schedule_work(work);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* svc_new - Create a new service
|
* svc_new - Create a new service
|
||||||
@@ -47,10 +77,9 @@ static TAILQ_HEAD(head, svc) svc_list = TAILQ_HEAD_INITIALIZER(svc_list);
|
|||||||
* Returns:
|
* Returns:
|
||||||
* A pointer to a new &svc_t object, or %NULL if out of empty slots.
|
* A pointer to a new &svc_t object, or %NULL if out of empty slots.
|
||||||
*/
|
*/
|
||||||
svc_t *svc_new(char *cmd, int id, int type)
|
svc_t *svc_new(char *cmd, char *id, int type)
|
||||||
{
|
{
|
||||||
int job = -1;
|
int job = -1;
|
||||||
char *desc;
|
|
||||||
svc_t *svc, *iter = NULL;
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
/* Find first job n:o if registering multiple instances */
|
/* Find first job n:o if registering multiple instances */
|
||||||
@@ -69,24 +98,30 @@ svc_t *svc_new(char *cmd, int id, int type)
|
|||||||
|
|
||||||
svc->type = type;
|
svc->type = type;
|
||||||
svc->job = job;
|
svc->job = job;
|
||||||
svc->id = id;
|
strlcpy(svc->id, id, sizeof(svc->id));
|
||||||
strlcpy(svc->cmd, cmd, sizeof(svc->cmd));
|
strlcpy(svc->cmd, cmd, sizeof(svc->cmd));
|
||||||
|
|
||||||
/* Default description, if missing */
|
/* Default description, if missing */
|
||||||
desc = rindex(cmd, '/');
|
strlcpy(svc->desc, svc->name, sizeof(svc->desc));
|
||||||
if (desc)
|
|
||||||
desc++;
|
/* Default HALT signal to send */
|
||||||
else
|
svc->sighalt = SIGTERM;
|
||||||
desc = cmd;
|
|
||||||
strlcpy(svc->desc, desc, sizeof(svc->desc));
|
/* Default delay between SIGTERM and SIGKILL */
|
||||||
|
svc->killdelay = SVC_TERM_TIMEOUT;
|
||||||
|
|
||||||
TAILQ_INSERT_TAIL(&svc_list, svc, link);
|
TAILQ_INSERT_TAIL(&svc_list, svc, link);
|
||||||
|
|
||||||
return svc;
|
return svc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct wq work = {
|
||||||
|
.cb = svc_gc,
|
||||||
|
.delay = SVC_TERM_TIMEOUT
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* svc_del - Delete a service object
|
* svc_del - Mark a service object for deletion
|
||||||
* @svc: Pointer to an &svc_t object
|
* @svc: Pointer to an &svc_t object
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
@@ -95,8 +130,10 @@ svc_t *svc_new(char *cmd, int id, int type)
|
|||||||
int svc_del(svc_t *svc)
|
int svc_del(svc_t *svc)
|
||||||
{
|
{
|
||||||
TAILQ_REMOVE(&svc_list, svc, link);
|
TAILQ_REMOVE(&svc_list, svc, link);
|
||||||
memset(svc, 0, sizeof(*svc));
|
TAILQ_INSERT_TAIL(&gc_list, svc, link);
|
||||||
free(svc);
|
|
||||||
|
clock_gettime(CLOCK_MONOTONIC_COARSE, &svc->gc);
|
||||||
|
schedule_work(&work);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -167,7 +204,7 @@ svc_t *svc_named_iterator(svc_t **iter, int first, char *cmd)
|
|||||||
svc_t *svc;
|
svc_t *svc;
|
||||||
|
|
||||||
for (svc = svc_iterator(iter, first); svc; svc = svc_iterator(iter, 0)) {
|
for (svc = svc_iterator(iter, first); svc; svc = svc_iterator(iter, 0)) {
|
||||||
char *name = basename(svc->cmd);
|
char *name = svc->name;
|
||||||
|
|
||||||
if (!strncmp(name, cmd, strlen(name)))
|
if (!strncmp(name, cmd, strlen(name)))
|
||||||
return svc;
|
return svc;
|
||||||
@@ -205,7 +242,7 @@ svc_t *svc_job_iterator(svc_t **iter, int first, int job)
|
|||||||
* svc_foreach - Run a callback for each registered service
|
* svc_foreach - Run a callback for each registered service
|
||||||
* @cb: Callback to run for each service
|
* @cb: Callback to run for each service
|
||||||
*/
|
*/
|
||||||
void svc_foreach(void (*cb)(svc_t *))
|
void svc_foreach(int (*cb)(svc_t *))
|
||||||
{
|
{
|
||||||
svc_t *svc, *iter = NULL;
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
@@ -222,7 +259,7 @@ void svc_foreach(void (*cb)(svc_t *))
|
|||||||
* @types: Mask of service types
|
* @types: Mask of service types
|
||||||
* @cb: Callback to run for each matching type
|
* @cb: Callback to run for each matching type
|
||||||
*/
|
*/
|
||||||
void svc_foreach_type(int types, void (*cb)(svc_t *))
|
void svc_foreach_type(int types, int (*cb)(svc_t *))
|
||||||
{
|
{
|
||||||
svc_t *svc, *iter = NULL;
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
@@ -264,12 +301,12 @@ svc_t *svc_stop_completed(void)
|
|||||||
* Returns:
|
* Returns:
|
||||||
* A pointer to an &svc_t object, or %NULL if not found.
|
* A pointer to an &svc_t object, or %NULL if not found.
|
||||||
*/
|
*/
|
||||||
svc_t *svc_find(char *cmd, int id)
|
svc_t *svc_find(char *cmd, char *id)
|
||||||
{
|
{
|
||||||
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->id == id && !strncmp(svc->cmd, cmd, strlen(svc->cmd)))
|
if (!strcmp(svc->cmd, cmd) && !strcmp(svc->id, id))
|
||||||
return svc;
|
return svc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,12 +340,12 @@ svc_t *svc_find_by_pid(pid_t pid)
|
|||||||
* Returns:
|
* Returns:
|
||||||
* A pointer to an &svc_t object, or %NULL if not found.
|
* A pointer to an &svc_t object, or %NULL if not found.
|
||||||
*/
|
*/
|
||||||
svc_t *svc_find_by_jobid(int job, int id)
|
svc_t *svc_find_by_jobid(int job, char *id)
|
||||||
{
|
{
|
||||||
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->job == job && svc->id == id)
|
if (svc->job == job && !strcmp(svc->id, id))
|
||||||
return svc;
|
return svc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,19 +360,33 @@ svc_t *svc_find_by_jobid(int job, int id)
|
|||||||
* Returns:
|
* Returns:
|
||||||
* A pointer to an &svc_t object, or %NULL if not found.
|
* A pointer to an &svc_t object, or %NULL if not found.
|
||||||
*/
|
*/
|
||||||
svc_t *svc_find_by_nameid(char *name, int id)
|
svc_t *svc_find_by_nameid(char *name, char *id)
|
||||||
{
|
{
|
||||||
char *ptr;
|
|
||||||
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)) {
|
||||||
ptr = strrchr(svc->cmd, '/');
|
if (!strcmp(svc->id, id) && !strcmp(name, svc->name))
|
||||||
if (ptr)
|
return svc;
|
||||||
ptr++;
|
}
|
||||||
else
|
|
||||||
ptr = svc->cmd;
|
|
||||||
|
|
||||||
if (svc->id == id && !strcmp(name, ptr))
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* svc_find_by_plidfile - Find an service object by its PID file
|
||||||
|
* @fn: PID file, can be absolute path or relative to /run
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* A pointer to an &svc_t object, or %NULL if not found.
|
||||||
|
*/
|
||||||
|
svc_t *svc_find_by_pidfile(char *fn)
|
||||||
|
{
|
||||||
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
|
char path[MAX_ARG_LEN];
|
||||||
|
|
||||||
|
if (string_compare(pid_runpath(fn, path, sizeof(path)), pid_file(svc)))
|
||||||
return svc;
|
return svc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,8 +407,14 @@ 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)
|
||||||
|
continue;
|
||||||
|
if (svc_is_inetd_conn(svc))
|
||||||
|
continue;
|
||||||
|
|
||||||
*((int *)&svc->dirty) = -1;
|
*((int *)&svc->dirty) = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void svc_mark_dirty(svc_t *svc)
|
void svc_mark_dirty(svc_t *svc)
|
||||||
@@ -382,10 +439,8 @@ void svc_clean_dynamic(void (*cb)(svc_t *))
|
|||||||
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->dirty == -1 && cb) {
|
if (svc->dirty == -1 && cb)
|
||||||
cb(svc);
|
cb(svc);
|
||||||
svc_mark_clean(svc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -447,18 +502,24 @@ int svc_enabled(svc_t *svc)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Same base service, return unique ID */
|
/* Same base service, return unique ID as an integer */
|
||||||
int svc_next_id(char *cmd)
|
int svc_next_id_int(char *cmd)
|
||||||
{
|
{
|
||||||
int id = 0;
|
int n = 1;
|
||||||
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 (!strcmp(svc->cmd, cmd) && id < svc->id)
|
char id[MAX_ID_LEN];
|
||||||
id = svc->id;
|
|
||||||
|
snprintf(id, sizeof(id), "%d", n);
|
||||||
|
|
||||||
|
if (!strcmp(svc->cmd, cmd) && strcmp(svc->id, id))
|
||||||
|
return n;
|
||||||
|
|
||||||
|
n++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return id + 1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int svc_is_unique(svc_t *svc)
|
int svc_is_unique(svc_t *svc)
|
||||||
@@ -482,31 +543,76 @@ int svc_is_unique(svc_t *svc)
|
|||||||
return unique;
|
return unique;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* break up "job:id job:id job:id ..." into several "job:id" tokens */
|
||||||
|
static char *tokstr(char *str, size_t len)
|
||||||
|
{
|
||||||
|
static char *cur = NULL;
|
||||||
|
static size_t pos = 0;
|
||||||
|
char *token;
|
||||||
|
|
||||||
|
if (!cur && !str)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (str) {
|
||||||
|
cur = str;
|
||||||
|
pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos >= len)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
token = &cur[pos];
|
||||||
|
while (pos < len) {
|
||||||
|
if (isspace(cur[pos])) {
|
||||||
|
cur[pos++] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Used by api.c (to start/stop/restart) and initctl.c (for input validation)
|
* Used by api.c (to start/stop/restart) and initctl.c (for input validation)
|
||||||
*/
|
*/
|
||||||
int svc_parse_jobstr(char *str, size_t len, int (*found)(svc_t *), int (not_found)(char *, int))
|
int svc_parse_jobstr(char *str, size_t len, int (*found)(svc_t *), int (not_found)(char *, char *))
|
||||||
{
|
{
|
||||||
|
char *input, *token;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
char *input, *token, *pos;
|
|
||||||
|
|
||||||
input = sanitize(str, len);
|
_d("Got str:'%s'", str);
|
||||||
if (!input)
|
input = tokstr(str, len);
|
||||||
return -1;
|
while (input) {
|
||||||
|
char *id = NULL;
|
||||||
token = strtok_r(input, " ", &pos);
|
|
||||||
while (token) {
|
|
||||||
int id = 1;
|
|
||||||
svc_t *svc, *iter = NULL;
|
svc_t *svc, *iter = NULL;
|
||||||
char *ptr = strchr(token, ':');
|
char *ptr;
|
||||||
|
|
||||||
|
_d("Got token:'%s'", input);
|
||||||
|
token = sanitize(input, len);
|
||||||
|
if (!token) {
|
||||||
|
_d("Sanitation of token:'%s' failed", input);
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
ptr = strchr(token, ':');
|
||||||
|
|
||||||
if (isdigit(token[0])) {
|
if (isdigit(token[0])) {
|
||||||
int job = atonum(token);
|
char *ep;
|
||||||
|
long job = 0;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
job = strtol(token, &ep, 10);
|
||||||
|
if ((errno == ERANGE && (job == LONG_MAX || job == LONG_MIN)) ||
|
||||||
|
(errno != 0 && job == 0) ||
|
||||||
|
(token == ep)) {
|
||||||
|
result++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!ptr) {
|
if (!ptr) {
|
||||||
svc = svc_job_iterator(&iter, 1, job);
|
svc = svc_job_iterator(&iter, 1, job);
|
||||||
if (!svc && not_found)
|
if (!svc && not_found)
|
||||||
result += not_found(NULL, job);
|
result += not_found(NULL, token);
|
||||||
|
|
||||||
while (svc) {
|
while (svc) {
|
||||||
if (found)
|
if (found)
|
||||||
@@ -515,8 +621,7 @@ int svc_parse_jobstr(char *str, size_t len, int (*found)(svc_t *), int (not_foun
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
*ptr++ = 0;
|
*ptr++ = 0;
|
||||||
id = atonum(ptr);
|
id = ptr;
|
||||||
job = atonum(token);
|
|
||||||
|
|
||||||
svc = svc_find_by_jobid(job, id);
|
svc = svc_find_by_jobid(job, id);
|
||||||
if (!svc && not_found)
|
if (!svc && not_found)
|
||||||
@@ -537,7 +642,7 @@ int svc_parse_jobstr(char *str, size_t len, int (*found)(svc_t *), int (not_foun
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
*ptr++ = 0;
|
*ptr++ = 0;
|
||||||
id = atonum(ptr);
|
id = ptr;
|
||||||
|
|
||||||
svc = svc_find_by_nameid(token, id);
|
svc = svc_find_by_nameid(token, id);
|
||||||
if (!svc && not_found)
|
if (!svc && not_found)
|
||||||
@@ -547,7 +652,8 @@ int svc_parse_jobstr(char *str, size_t len, int (*found)(svc_t *), int (not_foun
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
token = strtok_r(NULL, " ", &pos);
|
next:
|
||||||
|
input = tokstr(NULL, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -43,10 +43,11 @@ typedef enum {
|
|||||||
SVC_TYPE_RUN = 4, /* Like task, but wait for completion */
|
SVC_TYPE_RUN = 4, /* Like task, but wait for completion */
|
||||||
SVC_TYPE_INETD = 8, /* Classic inetd service */
|
SVC_TYPE_INETD = 8, /* Classic inetd service */
|
||||||
SVC_TYPE_INETD_CONN = 16, /* Single inetd connection */
|
SVC_TYPE_INETD_CONN = 16, /* Single inetd connection */
|
||||||
|
SVC_TYPE_SYSV = 32, /* SysV style init.d script w/ start/stop */
|
||||||
} svc_type_t;
|
} svc_type_t;
|
||||||
|
|
||||||
#define SVC_TYPE_ANY (-1)
|
#define SVC_TYPE_ANY (-1)
|
||||||
#define SVC_TYPE_RUNTASK (6)
|
#define SVC_TYPE_RUNTASK (SVC_TYPE_RUN | SVC_TYPE_TASK | SVC_TYPE_SYSV)
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SVC_HALTED_STATE = 0, /* Not allowed in runlevel, or not enabled. */
|
SVC_HALTED_STATE = 0, /* Not allowed in runlevel, or not enabled. */
|
||||||
@@ -66,12 +67,16 @@ typedef enum {
|
|||||||
SVC_BLOCK_RESTARTING,
|
SVC_BLOCK_RESTARTING,
|
||||||
} svc_block_t;
|
} svc_block_t;
|
||||||
|
|
||||||
|
#define MAX_ID_LEN 16
|
||||||
#define MAX_ARG_LEN 64
|
#define MAX_ARG_LEN 64
|
||||||
#define MAX_STR_LEN 64
|
#define MAX_STR_LEN 64
|
||||||
#define MAX_COND_LEN (MAX_ARG_LEN * 3)
|
#define MAX_COND_LEN (MAX_ARG_LEN * 3)
|
||||||
#define MAX_USER_LEN 16
|
#define MAX_USER_LEN 16
|
||||||
#define MAX_NUM_FDS 64 /* Max number of I/O plugins */
|
#define MAX_NUM_FDS 64 /* Max number of I/O plugins */
|
||||||
#define MAX_NUM_SVC_ARGS 32
|
#define MAX_NUM_SVC_ARGS 64
|
||||||
|
|
||||||
|
/* Default kill delay (msec) after SIGTERM (svc->sighalt) that we SIGKILL processes */
|
||||||
|
#define SVC_TERM_TIMEOUT 3000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Default enable for all services, can be stopped by means
|
* Default enable for all services, can be stopped by means
|
||||||
@@ -83,21 +88,30 @@ typedef struct svc {
|
|||||||
TAILQ_ENTRY(svc) link;
|
TAILQ_ENTRY(svc) link;
|
||||||
|
|
||||||
/* Instance specifics */
|
/* Instance specifics */
|
||||||
int job, id; /* JOB:ID */
|
int job; /* JOB: */
|
||||||
|
char id[MAX_ID_LEN]; /* :ID */
|
||||||
|
|
||||||
/* Limits and scoping */
|
/* Limits and scoping */
|
||||||
struct rlimit rlimit[RLIMIT_NLIMITS];
|
struct rlimit rlimit[RLIMIT_NLIMITS];
|
||||||
|
|
||||||
/* Service details */
|
/* Service details */
|
||||||
pid_t pid;
|
int sighalt; /* Signal to stop prorcess, default: SIGTERM */
|
||||||
|
int killdelay; /* Delay in msec before sending SIGKILL */
|
||||||
|
pid_t pid;
|
||||||
|
char pidfile[256];
|
||||||
|
long start_time; /* Start time, as seconds since boot, from sysinfo() */
|
||||||
|
int started; /* Set for run/task/sysv to track if started */
|
||||||
|
int status; /* From waitpid() when process is collected */
|
||||||
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, inetd, ... */
|
svc_type_t type; /* Service, run, task, inetd, ... */
|
||||||
|
int protect; /* Services like dbus-daemon & udev by Finit */
|
||||||
const int dirty; /* -1: removal, 0: unmodified, 1: modified */
|
const int dirty; /* -1: removal, 0: unmodified, 1: modified */
|
||||||
int starting; /* ... waiting for pidfile to be re-asserted */
|
int starting; /* ... waiting for pidfile to be re-asserted */
|
||||||
int runlevels;
|
int runlevels;
|
||||||
int sighup; /* This service supports SIGHUP :) */
|
int sighup; /* This service supports SIGHUP :) */
|
||||||
svc_block_t block; /* Reason that this service is currently stopped */
|
svc_block_t block; /* Reason that this service is currently stopped */
|
||||||
char cond[MAX_COND_LEN];
|
char cond[MAX_COND_LEN];
|
||||||
|
char name[MAX_ARG_LEN];
|
||||||
|
|
||||||
/* Counters */
|
/* Counters */
|
||||||
char once; /* run/task, (at least) once per runlevel */
|
char once; /* run/task, (at least) once per runlevel */
|
||||||
@@ -106,9 +120,17 @@ typedef struct svc {
|
|||||||
/* For inetd services */
|
/* For inetd services */
|
||||||
inetd_t inetd;
|
inetd_t inetd;
|
||||||
int stdin_fd;
|
int stdin_fd;
|
||||||
|
char iifname[IF_NAMESIZE + 1]; /* Ingress interface for connection */
|
||||||
|
|
||||||
/* Set for services we need to redirect stdout/stderr to syslog */
|
/* Set for services we need to redirect stdout/stderr to syslog */
|
||||||
int log;
|
struct {
|
||||||
|
char enabled;
|
||||||
|
char null;
|
||||||
|
char console;
|
||||||
|
char file[64];
|
||||||
|
char prio[20];
|
||||||
|
char ident[20];
|
||||||
|
} log;
|
||||||
|
|
||||||
/* Identity */
|
/* Identity */
|
||||||
char username[MAX_USER_LEN];
|
char username[MAX_USER_LEN];
|
||||||
@@ -125,23 +147,27 @@ typedef struct svc {
|
|||||||
*/
|
*/
|
||||||
uev_t timer;
|
uev_t timer;
|
||||||
void (*timer_cb)(struct svc *svc);
|
void (*timer_cb)(struct svc *svc);
|
||||||
|
|
||||||
|
/* time at svc_del(), used by gc timer */
|
||||||
|
struct timespec gc;
|
||||||
} svc_t;
|
} svc_t;
|
||||||
|
|
||||||
svc_t *svc_new (char *cmd, int id, int type);
|
svc_t *svc_new (char *cmd, char *id, int type);
|
||||||
int svc_del (svc_t *svc);
|
int svc_del (svc_t *svc);
|
||||||
|
|
||||||
svc_t *svc_find (char *cmd, int id);
|
svc_t *svc_find (char *cmd, char *id);
|
||||||
svc_t *svc_find_by_pid (pid_t pid);
|
svc_t *svc_find_by_pid (pid_t pid);
|
||||||
svc_t *svc_find_by_jobid (int job, int id);
|
svc_t *svc_find_by_jobid (int job, char *id);
|
||||||
svc_t *svc_find_by_nameid (char *name, int id);
|
svc_t *svc_find_by_nameid (char *name, char *id);
|
||||||
|
svc_t *svc_find_by_pidfile (char *fn);
|
||||||
|
|
||||||
svc_t *svc_iterator (svc_t **iter, int first);
|
svc_t *svc_iterator (svc_t **iter, int first);
|
||||||
svc_t *svc_inetd_iterator (svc_t **iter, int first);
|
svc_t *svc_inetd_iterator (svc_t **iter, int first);
|
||||||
svc_t *svc_named_iterator (svc_t **iter, int first, char *cmd);
|
svc_t *svc_named_iterator (svc_t **iter, int first, char *cmd);
|
||||||
svc_t *svc_job_iterator (svc_t **iter, int first, int job);
|
svc_t *svc_job_iterator (svc_t **iter, int first, int job);
|
||||||
|
|
||||||
void svc_foreach (void (*cb)(svc_t *));
|
void svc_foreach (int (*cb)(svc_t *));
|
||||||
void svc_foreach_type (int types, void (*cb)(svc_t *));
|
void svc_foreach_type (int types, int (*cb)(svc_t *));
|
||||||
|
|
||||||
svc_t *svc_stop_completed (void);
|
svc_t *svc_stop_completed (void);
|
||||||
|
|
||||||
@@ -153,39 +179,45 @@ int svc_clean_bootstrap (svc_t *svc);
|
|||||||
void svc_prune_bootstrap (void);
|
void svc_prune_bootstrap (void);
|
||||||
|
|
||||||
int svc_enabled (svc_t *svc);
|
int svc_enabled (svc_t *svc);
|
||||||
int svc_next_id (char *cmd);
|
int svc_next_id_int (char *cmd);
|
||||||
int svc_is_unique (svc_t *svc);
|
int svc_is_unique (svc_t *svc);
|
||||||
|
|
||||||
int svc_parse_jobstr (char *str, size_t len, int (*found)(svc_t *), int (not_found)(char *, int));
|
int svc_parse_jobstr (char *str, size_t len, int (*found)(svc_t *), int (not_found)(char *, char *));
|
||||||
|
|
||||||
|
static inline int svc_is_inetd (svc_t *svc) { return svc && SVC_TYPE_INETD == svc->type; }
|
||||||
|
static inline int svc_is_inetd_conn(svc_t *svc) { return svc && SVC_TYPE_INETD_CONN == svc->type; }
|
||||||
|
static inline int svc_is_daemon (svc_t *svc) { return svc && SVC_TYPE_SERVICE == svc->type; }
|
||||||
|
static inline int svc_is_sysv (svc_t *svc) { return svc && SVC_TYPE_SYSV == 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_is_daemon(svc) || svc_is_sysv(svc)) && svc->pidfile[0] == '!'; }
|
||||||
|
|
||||||
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_has_sighup (svc_t *svc) { return svc && 0 != svc->sighup; }
|
static inline int svc_has_sighup (svc_t *svc) { return svc && 0 != svc->sighup; }
|
||||||
|
static inline int svc_has_pidfile (svc_t *svc) { return svc_is_daemon(svc) && svc->pidfile[0] != 0 && svc->pidfile[0] != '!'; }
|
||||||
|
|
||||||
static inline void svc_starting (svc_t *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) { svc->starting = 0; }
|
static inline void svc_started (svc_t *svc) { if (svc) svc->starting = 0; }
|
||||||
static inline int svc_is_starting (svc_t *svc) { return 0 != svc->starting; }
|
static inline int svc_is_starting (svc_t *svc) { return svc && 0 != svc->starting; }
|
||||||
|
|
||||||
static inline int svc_is_removed (svc_t *svc) { return svc && -1 == svc->dirty; }
|
static inline int svc_is_removed (svc_t *svc) { return svc && -1 == svc->dirty; }
|
||||||
static inline int svc_is_changed (svc_t *svc) { return svc && 0 != svc->dirty; }
|
static inline int svc_is_changed (svc_t *svc) { return svc && 0 != svc->dirty; }
|
||||||
static inline int svc_is_updated (svc_t *svc) { return svc && 1 == svc->dirty; }
|
static inline int svc_is_updated (svc_t *svc) { return svc && 1 == svc->dirty; }
|
||||||
|
|
||||||
static inline int svc_is_inetd (svc_t *svc) { return svc && SVC_TYPE_INETD == svc->type; }
|
static inline int svc_is_blocked (svc_t *svc) { return svc && svc->block != SVC_BLOCK_NONE; }
|
||||||
static inline int svc_is_inetd_conn(svc_t *svc) { return svc && SVC_TYPE_INETD_CONN == svc->type; }
|
static inline int svc_is_busy (svc_t *svc) { return svc && svc->block == SVC_BLOCK_BUSY; }
|
||||||
static inline int svc_is_daemon (svc_t *svc) { return svc && SVC_TYPE_SERVICE == svc->type; }
|
static inline void svc_unblock (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_NONE; }
|
||||||
static inline int svc_is_runtask (svc_t *svc) { return svc && (SVC_TYPE_RUNTASK & svc->type); }
|
|
||||||
|
|
||||||
static inline int svc_is_blocked (svc_t *svc) { return svc->block != SVC_BLOCK_NONE; }
|
|
||||||
static inline int svc_is_busy (svc_t *svc) { return svc->block == SVC_BLOCK_BUSY; }
|
|
||||||
static inline void svc_unblock (svc_t *svc) { svc->block = SVC_BLOCK_NONE; }
|
|
||||||
#define svc_start(svc) svc_unblock(svc)
|
#define svc_start(svc) svc_unblock(svc)
|
||||||
static inline void svc_stop (svc_t *svc) { svc->block = SVC_BLOCK_USER; }
|
static inline void svc_stop (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_USER; }
|
||||||
static inline void svc_busy (svc_t *svc) { svc->block = SVC_BLOCK_BUSY; }
|
static inline void svc_busy (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_BUSY; }
|
||||||
static inline void svc_missing (svc_t *svc) { svc->block = SVC_BLOCK_MISSING; }
|
static inline void svc_missing (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_MISSING; }
|
||||||
static inline void svc_restarting (svc_t *svc) { svc->block = SVC_BLOCK_RESTARTING; }
|
static inline void svc_restarting (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_RESTARTING; }
|
||||||
static inline void svc_crashing (svc_t *svc) { svc->block = SVC_BLOCK_CRASHING; }
|
static inline void svc_crashing (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_CRASHING; }
|
||||||
|
|
||||||
static inline char *svc_status(svc_t *svc)
|
static inline char *svc_status(svc_t *svc)
|
||||||
{
|
{
|
||||||
|
if (!svc)
|
||||||
|
return "Unknown";
|
||||||
|
|
||||||
switch (svc->state) {
|
switch (svc->state) {
|
||||||
case SVC_HALTED_STATE:
|
case SVC_HALTED_STATE:
|
||||||
switch (svc->block) {
|
switch (svc->block) {
|
||||||
@@ -207,6 +239,7 @@ static inline char *svc_status(svc_t *svc)
|
|||||||
case SVC_BLOCK_RESTARTING:
|
case SVC_BLOCK_RESTARTING:
|
||||||
return "restart";
|
return "restart";
|
||||||
}
|
}
|
||||||
|
return "unknown";
|
||||||
|
|
||||||
case SVC_DONE_STATE:
|
case SVC_DONE_STATE:
|
||||||
return "done";
|
return "done";
|
||||||
@@ -238,6 +271,9 @@ static inline char *svc_status(svc_t *svc)
|
|||||||
|
|
||||||
static inline const char *svc_dirtystr(svc_t *svc)
|
static inline const char *svc_dirtystr(svc_t *svc)
|
||||||
{
|
{
|
||||||
|
if (!svc)
|
||||||
|
return "Unknown";
|
||||||
|
|
||||||
if (svc_is_removed(svc))
|
if (svc_is_removed(svc))
|
||||||
return "removed";
|
return "removed";
|
||||||
if (svc_is_updated(svc))
|
if (svc_is_updated(svc))
|
||||||
|
|||||||
@@ -41,32 +41,16 @@
|
|||||||
#ifdef FALLBACK_SHELL
|
#ifdef FALLBACK_SHELL
|
||||||
static pid_t fallback = 0;
|
static pid_t fallback = 0;
|
||||||
#endif
|
#endif
|
||||||
static LIST_HEAD(, tty_node) tty_list = LIST_HEAD_INITIALIZER();
|
static LIST_HEAD(, tty) tty_list = LIST_HEAD_INITIALIZER();
|
||||||
|
|
||||||
static char *canonicalize(char *tty)
|
static char *canonicalize(char *tty)
|
||||||
{
|
{
|
||||||
char buf[42];
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
static char path[80];
|
static char path[80];
|
||||||
|
|
||||||
if (!tty)
|
if (!tty)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Auto-detect serial console, for embedded devices mostly */
|
|
||||||
if (!strcmp(tty, "@console")) {
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
fp = fopen("/sys/class/tty/console/active", "r");
|
|
||||||
if (!fp) {
|
|
||||||
_e("Cannot find system console, is sysfs not mounted?");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fgets(buf, sizeof(buf), fp))
|
|
||||||
tty = chomp(buf);
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
strlcpy(path, tty, sizeof(path));
|
strlcpy(path, tty, sizeof(path));
|
||||||
if (stat(path, &st)) {
|
if (stat(path, &st)) {
|
||||||
if (!strncmp(path, _PATH_DEV, strlen(_PATH_DEV))) {
|
if (!strncmp(path, _PATH_DEV, strlen(_PATH_DEV))) {
|
||||||
@@ -88,7 +72,7 @@ static char *canonicalize(char *tty)
|
|||||||
|
|
||||||
void tty_mark(void)
|
void tty_mark(void)
|
||||||
{
|
{
|
||||||
tty_node_t *tty;
|
struct tty *tty;
|
||||||
|
|
||||||
LIST_FOREACH(tty, &tty_list, link)
|
LIST_FOREACH(tty, &tty_list, link)
|
||||||
tty->dirty = -1;
|
tty->dirty = -1;
|
||||||
@@ -96,17 +80,17 @@ void tty_mark(void)
|
|||||||
|
|
||||||
void tty_sweep(void)
|
void tty_sweep(void)
|
||||||
{
|
{
|
||||||
tty_node_t *tty, *tmp;
|
struct tty *tty, *tmp;
|
||||||
|
|
||||||
LIST_FOREACH_SAFE(tty, &tty_list, link, tmp) {
|
LIST_FOREACH_SAFE(tty, &tty_list, link, tmp) {
|
||||||
if (!tty->dirty)
|
if (!tty->dirty)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_d("TTY %s dirty, stopping ...", tty->data.name);
|
_d("TTY %s dirty, stopping ...", tty->name);
|
||||||
tty_stop(&tty->data);
|
tty_stop(tty);
|
||||||
|
|
||||||
if (tty->dirty == -1) {
|
if (tty->dirty == -1) {
|
||||||
_d("TTY %s removed, cleaning up.", tty->data.name);
|
_d("TTY %s removed, cleaning up.", tty->name);
|
||||||
tty_unregister(tty);
|
tty_unregister(tty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,12 +120,12 @@ void tty_sweep(void)
|
|||||||
*/
|
*/
|
||||||
int tty_register(char *line, struct rlimit rlimit[], char *file)
|
int tty_register(char *line, struct rlimit rlimit[], char *file)
|
||||||
{
|
{
|
||||||
tty_node_t *entry;
|
struct tty *entry;
|
||||||
int insert = 0, noclear = 0, nowait = 0;
|
|
||||||
size_t i, num = 0;
|
size_t i, num = 0;
|
||||||
char *tok, *cmd = NULL, *args[TTY_MAX_ARGS];
|
char *tok, *cmd = NULL, *args[TTY_MAX_ARGS], buf[256];
|
||||||
char *dev = NULL, *baud = NULL;
|
char *dev = NULL, *baud = NULL;
|
||||||
char *runlevels = NULL, *term = NULL;
|
char *runlevels = NULL, *term = NULL;
|
||||||
|
int insert = 0, noclear = 0, nowait = 0, nologin = 0, atcon = 0;
|
||||||
|
|
||||||
if (!line) {
|
if (!line) {
|
||||||
_e("Missing argument");
|
_e("Missing argument");
|
||||||
@@ -159,6 +143,8 @@ int tty_register(char *line, struct rlimit rlimit[], char *file)
|
|||||||
noclear = 1;
|
noclear = 1;
|
||||||
else if (!strcmp(tok, "nowait"))
|
else if (!strcmp(tok, "nowait"))
|
||||||
nowait = 1;
|
nowait = 1;
|
||||||
|
else if (!strcmp(tok, "nologin"))
|
||||||
|
nologin = 1;
|
||||||
else
|
else
|
||||||
args[num++] = tok;
|
args[num++] = tok;
|
||||||
|
|
||||||
@@ -167,8 +153,12 @@ int tty_register(char *line, struct rlimit rlimit[], char *file)
|
|||||||
|
|
||||||
/* Iterate over all args */
|
/* Iterate over all args */
|
||||||
for (i = 0; i < num; i++) {
|
for (i = 0; i < num; i++) {
|
||||||
/* First, figure out if built-in or external */
|
/*
|
||||||
if (!dev && !cmd) {
|
* First, figure out if built-in or external getty
|
||||||
|
* tty [12345] /dev/ttyAMA0 115200 noclear vt220 # built-in
|
||||||
|
* tty [12345] /sbin/getty -L 115200 @console vt100 noclear # external
|
||||||
|
*/
|
||||||
|
if ((!cmd && !dev) || (cmd && !dev)) {
|
||||||
if (args[i][0] == '[')
|
if (args[i][0] == '[')
|
||||||
runlevels = line;
|
runlevels = line;
|
||||||
if (!strcmp(args[i], "@console"))
|
if (!strcmp(args[i], "@console"))
|
||||||
@@ -178,14 +168,14 @@ int tty_register(char *line, struct rlimit rlimit[], char *file)
|
|||||||
if (!strncmp(args[i], "tty", 3))
|
if (!strncmp(args[i], "tty", 3))
|
||||||
dev = args[i];
|
dev = args[i];
|
||||||
if (!access(args[i], X_OK))
|
if (!access(args[i], X_OK))
|
||||||
cmd = strdup(args[i]);
|
cmd = args[i];
|
||||||
|
|
||||||
/* The first arg must be one of the above */
|
/* The first arg must be one of the above */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Built-in getty args */
|
/* Built-in getty args */
|
||||||
if (dev) {
|
if (!cmd && dev) {
|
||||||
if (isdigit(args[i][0])) {
|
if (isdigit(args[i][0])) {
|
||||||
baud = args[i];
|
baud = args[i];
|
||||||
continue;
|
continue;
|
||||||
@@ -198,50 +188,63 @@ int tty_register(char *line, struct rlimit rlimit[], char *file)
|
|||||||
if (i + 1 == num)
|
if (i + 1 == num)
|
||||||
term = args[i];
|
term = args[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* External getty, figure out the device */
|
|
||||||
if (cmd) {
|
|
||||||
if (!strncmp(args[i], "/dev", 4))
|
|
||||||
dev = args[i];
|
|
||||||
|
|
||||||
if (!strncmp(args[i], "tty", 3))
|
|
||||||
dev = args[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
error:
|
error:
|
||||||
_e("Incomplete or non-existing TTY device given, cannot register.");
|
_e("Incomplete or non-existing TTY device given, cannot register.");
|
||||||
if (cmd)
|
|
||||||
free(cmd);
|
|
||||||
|
|
||||||
return errno = EINVAL;
|
return errno = EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Auto-detect serial console, for embedded devices mostly */
|
||||||
|
if (!strcmp(dev, "@console")) {
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopen("/sys/class/tty/console/active", "r");
|
||||||
|
if (!fp) {
|
||||||
|
_e("Cannot find system console, is sysfs not mounted?");
|
||||||
|
return errno = ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
atcon = 1;
|
||||||
|
if (fgets(buf, sizeof(buf), fp))
|
||||||
|
dev = strtok(chomp(buf), " \t");
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
again:
|
||||||
/* Ensure all getty (built-in + external) are registered with absolute path */
|
/* Ensure all getty (built-in + external) are registered with absolute path */
|
||||||
dev = canonicalize(dev);
|
dev = canonicalize(dev);
|
||||||
if (!dev)
|
if (!dev)
|
||||||
goto error;
|
goto error;
|
||||||
dev = strdup(dev);
|
|
||||||
|
|
||||||
entry = tty_find(dev);
|
entry = tty_find(dev);
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
insert = 1;
|
|
||||||
entry = calloc(1, sizeof(*entry));
|
entry = calloc(1, sizeof(*entry));
|
||||||
if (!entry) {
|
if (!entry)
|
||||||
free(dev);
|
|
||||||
if (cmd)
|
|
||||||
free(cmd);
|
|
||||||
return errno = ENOMEM;
|
return errno = ENOMEM;
|
||||||
|
insert = 1;
|
||||||
|
} else {
|
||||||
|
if (entry->cmd) {
|
||||||
|
free(entry->cmd);
|
||||||
|
entry->cmd = NULL;
|
||||||
|
for (i = 0; i < TTY_MAX_ARGS; i++) {
|
||||||
|
if (entry->args[i])
|
||||||
|
free(entry->args[i]);
|
||||||
|
entry->args[i] = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
insert = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry->data.name = dev;
|
strlcpy(entry->name, dev, sizeof(entry->name));
|
||||||
entry->data.baud = baud ? strdup(baud) : NULL;
|
strlcpy(entry->baud, baud ? baud : "", sizeof(entry->baud));
|
||||||
entry->data.term = term ? strdup(term) : NULL;
|
strlcpy(entry->term, term ? term : "", sizeof(entry->term));
|
||||||
entry->data.noclear = noclear;
|
entry->noclear = noclear;
|
||||||
entry->data.nowait = nowait;
|
entry->nowait = nowait;
|
||||||
entry->data.runlevels = conf_parse_runlevels(runlevels);
|
entry->nologin = nologin;
|
||||||
|
entry->runlevels = conf_parse_runlevels(runlevels);
|
||||||
|
|
||||||
/* External getty */
|
/* External getty */
|
||||||
if (cmd) {
|
if (cmd) {
|
||||||
@@ -252,12 +255,19 @@ int tty_register(char *line, struct rlimit rlimit[], char *file)
|
|||||||
tok = cmd;
|
tok = cmd;
|
||||||
else
|
else
|
||||||
tok++;
|
tok++;
|
||||||
entry->data.cmd = cmd;
|
entry->cmd = strdup(cmd);
|
||||||
args[1] = strdup(tok);
|
args[1] = strdup(tok);
|
||||||
|
|
||||||
for (i = 1; i < num; i++)
|
for (i = 1; i < num; i++) {
|
||||||
entry->data.args[j++] = strdup(args[i]);
|
char *arg = args[i];
|
||||||
entry->data.args[++j] = NULL;
|
|
||||||
|
/* Replace @console with actual device */
|
||||||
|
if (arg && !strcmp(arg, "@console"))
|
||||||
|
arg = dev;
|
||||||
|
if (arg)
|
||||||
|
entry->args[j++] = strdup(arg);
|
||||||
|
}
|
||||||
|
entry->args[++j] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("Registering %s getty on TTY %s at %s baud with term %s on runlevels %s",
|
_d("Registering %s getty on TTY %s at %s baud with term %s on runlevels %s",
|
||||||
@@ -267,7 +277,7 @@ int tty_register(char *line, struct rlimit rlimit[], char *file)
|
|||||||
LIST_INSERT_HEAD(&tty_list, entry, link);
|
LIST_INSERT_HEAD(&tty_list, entry, link);
|
||||||
|
|
||||||
/* Register configured limits */
|
/* Register configured limits */
|
||||||
memcpy(entry->data.rlimit, rlimit, sizeof(entry->data.rlimit));
|
memcpy(entry->rlimit, rlimit, sizeof(entry->rlimit));
|
||||||
|
|
||||||
if (file && conf_changed(file))
|
if (file && conf_changed(file))
|
||||||
entry->dirty = 1; /* Modified, restart */
|
entry->dirty = 1; /* Modified, restart */
|
||||||
@@ -275,10 +285,18 @@ int tty_register(char *line, struct rlimit rlimit[], char *file)
|
|||||||
entry->dirty = 0; /* Not modified */
|
entry->dirty = 0; /* Not modified */
|
||||||
_d("TTY %s is %sdirty", dev, entry->dirty ? "" : "NOT ");
|
_d("TTY %s is %sdirty", dev, entry->dirty ? "" : "NOT ");
|
||||||
|
|
||||||
|
if (atcon) {
|
||||||
|
dev = strtok(NULL, " \t");
|
||||||
|
if (dev) {
|
||||||
|
_d("Found another @console: %s", dev);
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tty_unregister(tty_node_t *tty)
|
int tty_unregister(struct tty *tty)
|
||||||
{
|
{
|
||||||
if (!tty) {
|
if (!tty) {
|
||||||
_e("Missing argument");
|
_e("Missing argument");
|
||||||
@@ -287,20 +305,14 @@ int tty_unregister(tty_node_t *tty)
|
|||||||
|
|
||||||
LIST_REMOVE(tty, link);
|
LIST_REMOVE(tty, link);
|
||||||
|
|
||||||
if (tty->data.name)
|
if (tty->cmd) {
|
||||||
free(tty->data.name);
|
|
||||||
if (tty->data.baud)
|
|
||||||
free(tty->data.baud);
|
|
||||||
if (tty->data.term)
|
|
||||||
free(tty->data.term);
|
|
||||||
if (tty->data.cmd) {
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
free(tty->data.cmd);
|
free(tty->cmd);
|
||||||
for (i = 0; i < TTY_MAX_ARGS; i++) {
|
for (i = 0; i < TTY_MAX_ARGS; i++) {
|
||||||
if (tty->data.args[i])
|
if (tty->args[i])
|
||||||
free(tty->data.args[i]);
|
free(tty->args[i]);
|
||||||
tty->data.args[i] = NULL;
|
tty->args[i] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(tty);
|
free(tty);
|
||||||
@@ -308,12 +320,12 @@ int tty_unregister(tty_node_t *tty)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
tty_node_t *tty_find(char *dev)
|
struct tty *tty_find(char *dev)
|
||||||
{
|
{
|
||||||
tty_node_t *entry;
|
struct tty *entry;
|
||||||
|
|
||||||
LIST_FOREACH(entry, &tty_list, link) {
|
LIST_FOREACH(entry, &tty_list, link) {
|
||||||
if (!strcmp(dev, entry->data.name))
|
if (!strcmp(dev, entry->name))
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,7 +335,7 @@ tty_node_t *tty_find(char *dev)
|
|||||||
size_t tty_num(void)
|
size_t tty_num(void)
|
||||||
{
|
{
|
||||||
size_t num = 0;
|
size_t num = 0;
|
||||||
tty_node_t *entry;
|
struct tty *entry;
|
||||||
|
|
||||||
LIST_FOREACH(entry, &tty_list, link)
|
LIST_FOREACH(entry, &tty_list, link)
|
||||||
num++;
|
num++;
|
||||||
@@ -334,22 +346,22 @@ size_t tty_num(void)
|
|||||||
size_t tty_num_active(void)
|
size_t tty_num_active(void)
|
||||||
{
|
{
|
||||||
size_t num = 0;
|
size_t num = 0;
|
||||||
tty_node_t *entry;
|
struct tty *entry;
|
||||||
|
|
||||||
LIST_FOREACH(entry, &tty_list, link) {
|
LIST_FOREACH(entry, &tty_list, link) {
|
||||||
if (entry->data.pid)
|
if (entry->pid)
|
||||||
num++;
|
num++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
tty_node_t *tty_find_by_pid(pid_t pid)
|
struct tty *tty_find_by_pid(pid_t pid)
|
||||||
{
|
{
|
||||||
tty_node_t *entry;
|
struct tty *entry;
|
||||||
|
|
||||||
LIST_FOREACH(entry, &tty_list, link) {
|
LIST_FOREACH(entry, &tty_list, link) {
|
||||||
if (entry->data.pid == pid)
|
if (entry->pid == pid)
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,7 +384,7 @@ static int tty_exist(char *dev)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tty_start(finit_tty_t *tty)
|
void tty_start(struct tty *tty)
|
||||||
{
|
{
|
||||||
char *dev;
|
char *dev;
|
||||||
|
|
||||||
@@ -392,13 +404,20 @@ void tty_start(finit_tty_t *tty)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tty->nologin) {
|
||||||
|
_d("%s: Starting /bin/sh ...", dev);
|
||||||
|
tty->pid = run_sh(dev, tty->noclear, tty->nowait, tty->rlimit);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_d("%s: Starting %sgetty ...", dev, !tty->cmd ? "built-in " : "");
|
||||||
if (!tty->cmd)
|
if (!tty->cmd)
|
||||||
tty->pid = run_getty(dev, tty->baud, tty->term, tty->noclear, tty->nowait, tty->rlimit);
|
tty->pid = run_getty(dev, tty->baud, tty->term, tty->noclear, tty->nowait, tty->rlimit);
|
||||||
else
|
else
|
||||||
tty->pid = run_getty2(dev, tty->cmd, tty->args, tty->noclear, tty->nowait, tty->rlimit);
|
tty->pid = run_getty2(dev, tty->cmd, tty->args, tty->noclear, tty->nowait, tty->rlimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tty_stop(finit_tty_t *tty)
|
void tty_stop(struct tty *tty)
|
||||||
{
|
{
|
||||||
if (!tty->pid)
|
if (!tty->pid)
|
||||||
return;
|
return;
|
||||||
@@ -415,7 +434,7 @@ void tty_stop(finit_tty_t *tty)
|
|||||||
tty->pid = 0;
|
tty->pid = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tty_enabled(finit_tty_t *tty)
|
int tty_enabled(struct tty *tty)
|
||||||
{
|
{
|
||||||
if (!tty)
|
if (!tty)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -463,12 +482,12 @@ int tty_fallback(pid_t lost)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tty_action(tty_node_t *tty)
|
static void tty_action(struct tty *tty)
|
||||||
{
|
{
|
||||||
if (!tty_enabled(&tty->data))
|
if (!tty_enabled(tty))
|
||||||
tty_stop(&tty->data);
|
tty_stop(tty);
|
||||||
else
|
else
|
||||||
tty_start(&tty->data);
|
tty_start(tty);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -476,7 +495,7 @@ static void tty_action(tty_node_t *tty)
|
|||||||
*/
|
*/
|
||||||
int tty_respawn(pid_t pid)
|
int tty_respawn(pid_t pid)
|
||||||
{
|
{
|
||||||
tty_node_t *tty = tty_find_by_pid(pid);
|
struct tty *tty = tty_find_by_pid(pid);
|
||||||
|
|
||||||
if (!tty)
|
if (!tty)
|
||||||
return tty_fallback(pid);
|
return tty_fallback(pid);
|
||||||
@@ -485,7 +504,7 @@ int tty_respawn(pid_t pid)
|
|||||||
utmp_set_dead(pid);
|
utmp_set_dead(pid);
|
||||||
|
|
||||||
/* Clear PID to be able to respawn it. */
|
/* Clear PID to be able to respawn it. */
|
||||||
tty->data.pid = 0;
|
tty->pid = 0;
|
||||||
tty_action(tty);
|
tty_action(tty);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -496,7 +515,7 @@ int tty_respawn(pid_t pid)
|
|||||||
*/
|
*/
|
||||||
void tty_reload(char *dev)
|
void tty_reload(char *dev)
|
||||||
{
|
{
|
||||||
tty_node_t *tty;
|
struct tty *tty;
|
||||||
|
|
||||||
if (dev) {
|
if (dev) {
|
||||||
tty = tty_find(dev);
|
tty = tty_find(dev);
|
||||||
@@ -521,7 +540,7 @@ void tty_reload(char *dev)
|
|||||||
/* Start all TTYs that exist in the system and are allowed at this runlevel */
|
/* Start all TTYs that exist in the system and are allowed at this runlevel */
|
||||||
void tty_runlevel(void)
|
void tty_runlevel(void)
|
||||||
{
|
{
|
||||||
tty_node_t *tty;
|
struct tty *tty;
|
||||||
|
|
||||||
LIST_FOREACH(tty, &tty_list, link)
|
LIST_FOREACH(tty, &tty_list, link)
|
||||||
tty_action(tty);
|
tty_action(tty);
|
||||||
|
|||||||
Loaded 100 of 104 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user