mirror of
https://github.com/troglobit/finit.git
synced 2026-10-12 10:12:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4d3ec1a9f | ||
|
|
51befb492c | ||
|
|
7850378e15 | ||
|
|
438d6b4e63 | ||
|
|
712f68f9da | ||
|
|
8a32ec5c92 | ||
|
|
081622a085 | ||
|
|
2526431d8e | ||
|
|
47d8a83668 | ||
|
|
f72f3febf9 | ||
|
|
138546d008 | ||
|
|
cee244d151 | ||
|
|
7af4ad5c24 | ||
|
|
c0d3705ed5 | ||
|
|
5cf2b9a283 | ||
|
|
0e898da6e5 | ||
|
|
d9f13a1e50 | ||
|
|
4fbcd1bbad | ||
|
|
b6c5498f43 | ||
|
|
9a6c68c952 | ||
|
|
e8170e1216 | ||
|
|
059a4c8a86 | ||
|
|
0de9db68a3 | ||
|
|
aeff68b598 | ||
|
|
700c32fd73 | ||
|
|
334d4a708a | ||
|
|
4d472273e1 | ||
|
|
13f1359b3a | ||
|
|
2e5b97c8b2 | ||
|
|
9a962c86c8 | ||
|
|
f954a4cb92 | ||
|
|
feb97bc77c | ||
|
|
e00fda5dc3 | ||
|
|
80191f2fd5 | ||
|
|
42ef3d3cf7 | ||
|
|
1f4acb322a | ||
|
|
c3ba15045b | ||
|
|
8f1d1717f8 | ||
|
|
7703d00e82 | ||
|
|
3bb826b22b | ||
|
|
9ee2be121f | ||
|
|
36c6aa73aa | ||
|
|
13dddb6912 | ||
|
|
bdaf3370d4 | ||
|
|
a24077c4af | ||
|
|
414a49d733 | ||
|
|
be9d54561d | ||
|
|
3ce5a2a965 | ||
|
|
1d03e9aa8b | ||
|
|
5340e47e81 | ||
|
|
98bbf4a1e5 | ||
|
|
d70e2f1ed0 | ||
|
|
ecb5949679 | ||
|
|
e55fd19091 | ||
|
|
19c64e323c | ||
|
|
9354221bdd | ||
|
|
1d7048d3ae | ||
|
|
8251d713e0 | ||
|
|
44d0d87ad3 | ||
|
|
571250a9b9 | ||
|
|
91540fd793 | ||
|
|
2566e00ef0 | ||
|
|
1e5ce38928 | ||
|
|
c679b0a93d | ||
|
|
c4dcf568c8 | ||
|
|
b65773d508 | ||
|
|
e75c1792aa | ||
|
|
0be4838e01 | ||
|
|
b71605c819 | ||
|
|
3bb2eb2a8d | ||
|
|
8ce35771c3 | ||
|
|
67e80ea989 | ||
|
|
f4d8ecfb5b | ||
|
|
2eb3ebb404 | ||
|
|
1e1b3564dd | ||
|
|
7af257cccf | ||
|
|
84ddac65e5 | ||
|
|
62d6b56fd3 | ||
|
|
fa71f97dcf | ||
|
|
ed383eaaa6 | ||
|
|
9cb6a54493 | ||
|
|
f796d59f77 | ||
|
|
97ca450966 | ||
|
|
e0c1c08e68 | ||
|
|
c81b722691 | ||
|
|
11da93b759 | ||
|
|
28a90a793d | ||
|
|
56a89db889 | ||
|
|
a613ee908f | ||
|
|
d3f58b5df0 | ||
|
|
af88b10322 | ||
|
|
966ae9fb0d | ||
|
|
a69cef0a11 | ||
|
|
b396a018c5 | ||
|
|
a4af9ba248 | ||
|
|
6942e38413 | ||
|
|
e03bd093b5 | ||
|
|
d6070a0d10 | ||
|
|
bd4efb59ca | ||
|
|
a90cfd4a75 | ||
|
|
ab5a983bf7 | ||
|
|
f7bacf8b1b | ||
|
|
d363501e21 | ||
|
|
4150fdfe59 | ||
|
|
4d2b97e4cc | ||
|
|
21eda9dd1c | ||
|
|
4f7e726a3e | ||
|
|
74fc16b832 | ||
|
|
7393072120 | ||
|
|
96bb3f5c6c | ||
|
|
c23a867485 | ||
|
|
4f8a5a6531 | ||
|
|
48e1a0b17f | ||
|
|
9c727ed08d | ||
|
|
49cd3a441d | ||
|
|
8b9258aa73 | ||
|
|
82c6e4680f | ||
|
|
a67b2ba9a7 | ||
|
|
a96edf0291 | ||
|
|
c26dded49c | ||
|
|
3bd15a53d6 | ||
|
|
f0a888c0d1 | ||
|
|
b6769356b2 | ||
|
|
5a9cafc2fc | ||
|
|
2e36590bbd | ||
|
|
33e504b928 | ||
|
|
6a4f197cc0 | ||
|
|
4894580e8b | ||
|
|
70997fb4c5 | ||
|
|
e9515971ea | ||
|
|
82dfa002ff | ||
|
|
a664fd7192 | ||
|
|
b62ee0ef6d | ||
|
|
0cfd867816 | ||
|
|
934a4db7d5 | ||
|
|
c9fe9afa61 | ||
|
|
320e91653b | ||
|
|
859d215ca4 | ||
|
|
0a94f3f303 | ||
|
|
e83a26b256 | ||
|
|
2508495b8c | ||
|
|
3ef52d9324 | ||
|
|
05b72281e6 | ||
|
|
a47abfdc16 | ||
|
|
2c9265f8c8 | ||
|
|
56cb6f8613 | ||
|
|
3dd56ed8af | ||
|
|
fddeeb683c | ||
|
|
25835b0edf | ||
|
|
27fcfada66 | ||
|
|
2dd5fb0f77 | ||
|
|
63044a4b81 | ||
|
|
4e74f9783a | ||
|
|
c3c662fe64 | ||
|
|
7c2764790c | ||
|
|
732d500cf5 | ||
|
|
4e1ac726ac | ||
|
|
fba58085c6 | ||
|
|
d1ebb255c6 | ||
|
|
a39ee0b44d | ||
|
|
947d91acd5 | ||
|
|
8c206d52e5 | ||
|
|
0f445dc9f4 | ||
|
|
c71b35e61a | ||
|
|
d20308b7d7 | ||
|
|
e4e54a88d9 | ||
|
|
308b7c5197 | ||
|
|
89772bf6c0 | ||
|
|
077002e647 | ||
|
|
988cdf9878 | ||
|
|
97db2078f5 | ||
|
|
02a110e6c2 | ||
|
|
681ef8de6f | ||
|
|
0147e0e64f | ||
|
|
311c6be9aa | ||
|
|
c22d123ab0 | ||
|
|
96b5991355 | ||
|
|
06bd352863 | ||
|
|
a918f7497a | ||
|
|
8bbae3d414 | ||
|
|
bfd1f36fdd | ||
|
|
6fc702a560 | ||
|
|
40dcc5541b | ||
|
|
5b41c6e327 | ||
|
|
4bd81b4d4c | ||
|
|
c29589c2ca | ||
|
|
73b89430e4 | ||
|
|
2a62fa3d85 | ||
|
|
4542fdb5bb | ||
|
|
525aaf1f66 | ||
|
|
910dac5f3a | ||
|
|
2a5c319084 | ||
|
|
612f4fe288 | ||
|
|
c058c05651 | ||
|
|
0de4578e50 | ||
|
|
b9e94e4695 | ||
|
|
9887003b25 | ||
|
|
f6bfbc86e9 | ||
|
|
4c90b51d80 | ||
|
|
48cfbfe5ed | ||
|
|
f98be8540f | ||
|
|
17c69fef3d | ||
|
|
c586204fc1 | ||
|
|
ff5e3219be | ||
|
|
07c52f1566 | ||
|
|
0e04ffd68f | ||
|
|
8b5435908c | ||
|
|
3a74310aa6 | ||
|
|
180859a429 | ||
|
|
1d92819d92 | ||
|
|
cfa871c548 | ||
|
|
685e0a80a4 | ||
|
|
19847d2997 | ||
|
|
7108b0e789 | ||
|
|
7eac0b0341 | ||
|
|
33ec4e7d19 | ||
|
|
1b78f2b364 | ||
|
|
119363ff75 | ||
|
|
f89b508c01 | ||
|
|
dda8c7c3ac | ||
|
|
e2d9aab70d | ||
|
|
3df154b798 | ||
|
|
3d9cbaf040 | ||
|
|
70c2939596 | ||
|
|
d4ee44e27f | ||
|
|
0498326962 | ||
|
|
c84ababbd4 | ||
|
|
67ea42c87b | ||
|
|
a2ab45cad7 | ||
|
|
f3fcca6150 | ||
|
|
2b65d8f1e9 | ||
|
|
7c2abf69c4 | ||
|
|
457c0a246f | ||
|
|
1a439baf68 | ||
|
|
68ce78b3fe | ||
|
|
72e27e99e5 | ||
|
|
a436382886 | ||
|
|
6bbfc7b1f1 | ||
|
|
006dd12b09 | ||
|
|
d3a0631390 | ||
|
|
9046b6fe2b | ||
|
|
f217794773 | ||
|
|
11e02fabb3 | ||
|
|
8b9bb1c7ce | ||
|
|
2a7abf1db0 | ||
|
|
34b8c5a3ba | ||
|
|
8e056422fc | ||
|
|
94e8b185b4 | ||
|
|
996d3960e1 | ||
|
|
3b19734f63 | ||
|
|
64e7c0cd9e | ||
|
|
4d0c88bd7a | ||
|
|
9e8c601507 | ||
|
|
b26104466a | ||
|
|
bd25bf65ce | ||
|
|
edd3b41adf | ||
|
|
28ca3fcc5c | ||
|
|
3b601d0115 | ||
|
|
1ef9a9f128 | ||
|
|
d612a86c3b | ||
|
|
5d3cd05202 | ||
|
|
726f7ba229 | ||
|
|
61dab8bd75 | ||
|
|
a7e81f45c6 | ||
|
|
be4062f019 | ||
|
|
035f06e137 | ||
|
|
2f91ab5eac | ||
|
|
f6b5b0260b | ||
|
|
bb9bd7e0b0 | ||
|
|
287abd5c7c | ||
|
|
d27f114742 | ||
|
|
505c370898 | ||
|
|
f26009ec3e | ||
|
|
8425bc313b | ||
|
|
f4d3cf2835 | ||
|
|
bd5cf7c9eb | ||
|
|
4709394ae6 | ||
|
|
729002ef82 | ||
|
|
58b075dbf2 | ||
|
|
d679840fa3 | ||
|
|
0e70bdbf6a | ||
|
|
d810ac00bc | ||
|
|
5f74adad06 | ||
|
|
585ac51f45 | ||
|
|
ce36797506 | ||
|
|
a61c2ceb79 | ||
|
|
383339dc4a | ||
|
|
36b46ba134 | ||
|
|
a2d0859bf1 | ||
|
|
d5f542dcca | ||
|
|
fb86042cb3 | ||
|
|
359fb8530e | ||
|
|
5dd1a676ac | ||
|
|
278994781b | ||
|
|
c9f1bff419 | ||
|
|
1f9621cf4b | ||
|
|
9458e4e66b | ||
|
|
ff08038bdc | ||
|
|
ce330e8bf1 | ||
|
|
47d837bf6a | ||
|
|
912a281ee2 | ||
|
|
6e863a7872 | ||
|
|
488e6c2adf | ||
|
|
e177b866a9 | ||
|
|
15dcebd0f1 | ||
|
|
af60d8d3ec | ||
|
|
5a32fdb309 | ||
|
|
19f5cb1d01 | ||
|
|
c5bca5f80a | ||
|
|
d22dea74e3 | ||
|
|
dc547317c9 | ||
|
|
6bf5d98569 | ||
|
|
29dea38f50 | ||
|
|
34567dd244 | ||
|
|
a3584c6ca3 | ||
|
|
165d0633f6 | ||
|
|
9f7ba1ba79 | ||
|
|
03c08d3970 | ||
|
|
37e3be9a0d | ||
|
|
10437887fc | ||
|
|
faf1c6233d | ||
|
|
c36960350c | ||
|
|
51ade57723 | ||
|
|
9d79673cea | ||
|
|
762bf5f031 | ||
|
|
abcb3ceb67 | ||
|
|
0ae5071f94 | ||
|
|
e589c5b269 | ||
|
|
12e341fe73 | ||
|
|
9be3c4cb9a | ||
|
|
433f3ce17e | ||
|
|
2c29ede0da | ||
|
|
7cfbca6d74 | ||
|
|
b30621bb3b | ||
|
|
d6f35903d6 | ||
|
|
a61a8015d7 | ||
|
|
e2f070649d | ||
|
|
f08d375c36 | ||
|
|
1c4bad5b73 | ||
|
|
6c874895dc | ||
|
|
ef1a05425d | ||
|
|
fc3bad2160 | ||
|
|
31ac933d64 | ||
|
|
caa398816d | ||
|
|
0d57a507f3 | ||
|
|
96257cc5c7 | ||
|
|
fbcd7d2384 | ||
|
|
d9dbfa23c7 | ||
|
|
91f077bd08 | ||
|
|
5fb4a6ae8f | ||
|
|
e84333662e | ||
|
|
ddb42fda70 | ||
|
|
621eb21b42 | ||
|
|
6cc44a87c9 | ||
|
|
5f908cae49 | ||
|
|
6de67ed107 | ||
|
|
c129f06195 | ||
|
|
d11dc63bc2 | ||
|
|
d904ec1602 | ||
|
|
2a98b2f055 | ||
|
|
6286ede985 | ||
|
|
4a8ca787d3 | ||
|
|
561c88a868 | ||
|
|
f8dfcdf024 | ||
|
|
f50b5a4ac6 | ||
|
|
59525b80e3 | ||
|
|
0ce028add1 | ||
|
|
75c5c85f07 | ||
|
|
ccb84ced2e | ||
|
|
5ef669fb6c | ||
|
|
96ff9c115c | ||
|
|
83aa6abb1c | ||
|
|
9304024841 | ||
|
|
0de5981948 | ||
|
|
c39106906d | ||
|
|
929a6e7aac | ||
|
|
ceb4d04d23 | ||
|
|
f483a8aeaa | ||
|
|
e3e220ce8e | ||
|
|
fc653e4293 | ||
|
|
94d55cb7dd | ||
|
|
0e84ecf143 | ||
|
|
0e93dfd640 | ||
|
|
4dff8237f1 | ||
|
|
35400f2a8b | ||
|
|
9a76f0862c | ||
|
|
fb8a7caa99 | ||
|
|
f8bed5c7af | ||
|
|
da6fa482e7 | ||
|
|
fdf8e48c99 | ||
|
|
195155a7f5 | ||
|
|
6934ba4dbc | ||
|
|
fdbd25c1b5 | ||
|
|
467f1cca81 | ||
|
|
d6fdf4a806 | ||
|
|
4be9d97e61 | ||
|
|
021d011493 | ||
|
|
e988d38f71 | ||
|
|
8690fc732b | ||
|
|
ceb2945da9 | ||
|
|
1b8a0951f5 | ||
|
|
a27b8462d1 | ||
|
|
edc2d53923 | ||
|
|
4aae3403f5 | ||
|
|
73423699fd | ||
|
|
0cce69892a | ||
|
|
3ca6256f87 | ||
|
|
eca3098c0e | ||
|
|
7af3461e3c | ||
|
|
b62c975dc4 | ||
|
|
b368bd1420 | ||
|
|
060e97d64e | ||
|
|
9b17ce0b7c | ||
|
|
50f2cbf600 | ||
|
|
837bca3947 | ||
|
|
16180675db | ||
|
|
d3c6351ed8 | ||
|
|
7e37ac348e | ||
|
|
30e68658ae | ||
|
|
a179308819 | ||
|
|
4cdd5f8ccc | ||
|
|
7f19474d8d | ||
|
|
a5941165a0 | ||
|
|
181d9556a1 | ||
|
|
bf72e6b9c8 | ||
|
|
8db521d379 | ||
|
|
f46ac20fb0 | ||
|
|
d70d86e9fe | ||
|
|
38db52aa4e | ||
|
|
bf62bee440 | ||
|
|
e50fe3b060 | ||
|
|
d6c55282ef | ||
|
|
1015124530 | ||
|
|
38885aaa67 | ||
|
|
a685b698c2 | ||
|
|
9bce8f9584 | ||
|
|
d04b04d73a | ||
|
|
72125430e6 | ||
|
|
561387ce57 | ||
|
|
e2d1930e6c | ||
|
|
6f2a124240 | ||
|
|
10392e9639 | ||
|
|
605c489937 | ||
|
|
26409bc860 | ||
|
|
b01f9f38f2 | ||
|
|
2ddbb805ca | ||
|
|
ed999d9a80 | ||
|
|
82cc10be88 | ||
|
|
30fb9780d7 | ||
|
|
09f46f62b4 | ||
|
|
bc4e7a8d8d | ||
|
|
e2753d75f8 | ||
|
|
addb8c4019 | ||
|
|
0c4a9b62c2 | ||
|
|
57c97d8190 | ||
|
|
b0d0ca76cf | ||
|
|
5240c0cf19 | ||
|
|
a02f369a89 | ||
|
|
fa2a113cbf | ||
|
|
4c5ac38e2c | ||
|
|
f89ebb91a8 | ||
|
|
477bc064d5 | ||
|
|
96376126b3 | ||
|
|
1c150928cb | ||
|
|
7a8d4e2c6b | ||
|
|
fb956fd2f5 | ||
|
|
e6e4d814f3 | ||
|
|
544d44886a | ||
|
|
cec2d5a4db | ||
|
|
539d215d0e | ||
|
|
10ef0e7de6 | ||
|
|
05e6b3e752 | ||
|
|
3e4be9a122 | ||
|
|
5593372ffb | ||
|
|
05be281301 | ||
|
|
108bbf56dd | ||
|
|
a61aa73419 | ||
|
|
f39626f132 | ||
|
|
c0b6f3af08 | ||
|
|
5d8fcfdf13 | ||
|
|
e4830c5614 | ||
|
|
f33261af6b | ||
|
|
e7516f2b63 | ||
|
|
d18167fe1d | ||
|
|
7d3f95c0a9 | ||
|
|
86c5bbb03d | ||
|
|
7530bb74f6 | ||
|
|
54dd726d16 | ||
|
|
bd9bb92ca0 | ||
|
|
01cb088e51 | ||
|
|
3d91112e0d | ||
|
|
16aef80682 | ||
|
|
fd34914936 | ||
|
|
21a890a04e | ||
|
|
7f5f7e8ef6 | ||
|
|
ff937576ea | ||
|
|
7d831170ae | ||
|
|
6a21ac55ad | ||
|
|
a0820c7f20 | ||
|
|
6d58c9ed0b | ||
|
|
bc2ffbc767 | ||
|
|
4c1fc2410e | ||
|
|
70e1aa889a | ||
|
|
c8c5e4e88a | ||
|
|
86c1398778 | ||
|
|
b37fa2b417 | ||
|
|
a91e197553 | ||
|
|
5adb92ca1b | ||
|
|
cfc99c4e8b | ||
|
|
3e51ed1c55 | ||
|
|
b5df0a6274 | ||
|
|
cbe8d56042 | ||
|
|
a3ec792b44 | ||
|
|
c24855d4d5 | ||
|
|
014e457fda | ||
|
|
21d89c7e24 | ||
|
|
639fb76f5a | ||
|
|
30c189b116 | ||
|
|
e2a8803f7a | ||
|
|
209e140ddd | ||
|
|
2e3fa72924 | ||
|
|
1502838a0d | ||
|
|
377c8bce8c | ||
|
|
a39d958d25 | ||
|
|
7f8a96a73e | ||
|
|
5c2577214d | ||
|
|
f03206a694 | ||
|
|
f0e328edc9 | ||
|
|
13342f2bd9 | ||
|
|
c926160853 | ||
|
|
462d5b22b4 | ||
|
|
b1bfab08f3 | ||
|
|
aeb48ef04b | ||
|
|
b8b200ad75 | ||
|
|
c148d8d783 | ||
|
|
27ba3b27f5 | ||
|
|
b4af86255d | ||
|
|
01a007b388 | ||
|
|
0e28741dcb | ||
|
|
c993feeb44 | ||
|
|
ec17f0aa23 | ||
|
|
6baf2990e8 | ||
|
|
6416e2a1a4 | ||
|
|
7c42986800 | ||
|
|
6f802a7ff1 | ||
|
|
879721839e | ||
|
|
20290a4166 | ||
|
|
ba77e4f217 | ||
|
|
e7b18feca5 | ||
|
|
4a90a3e8ef | ||
|
|
6d14ff84d3 | ||
|
|
89cc6017df | ||
|
|
f6fafdbd23 | ||
|
|
3480e42687 | ||
|
|
053c1643a7 | ||
|
|
2018cac050 | ||
|
|
f9090f535d | ||
|
|
10577f3e48 | ||
|
|
07f7caef0d | ||
|
|
093b3ba467 | ||
|
|
c63279630b | ||
|
|
4755e5206b | ||
|
|
2002157032 | ||
|
|
094e00d405 | ||
|
|
e01836c506 | ||
|
|
685f332c6e | ||
|
|
ae09272bcc | ||
|
|
d16f7e0c88 | ||
|
|
063d645d95 | ||
|
|
f87e9d8880 | ||
|
|
e8099f1bfa | ||
|
|
7dc7f9a968 | ||
|
|
996ab8c6c6 | ||
|
|
16c2198304 | ||
|
|
ecca01dea0 | ||
|
|
bda3cdd3ad | ||
|
|
4811f76294 | ||
|
|
0aba704312 | ||
|
|
57329832d0 | ||
|
|
078a1d0c95 | ||
|
|
0e695aa0c7 | ||
|
|
f7a1514131 | ||
|
|
11bc87ecc3 | ||
|
|
e1c59a2515 | ||
|
|
2faefd44a2 | ||
|
|
6fa3aa41df | ||
|
|
ef9e9ec786 | ||
|
|
d77e3a6113 | ||
|
|
0b1258b44c | ||
|
|
62dad82ba8 | ||
|
|
5423b5b0a2 | ||
|
|
6b10174bcb | ||
|
|
ec94f4d321 | ||
|
|
69800537f2 | ||
|
|
61faedb0b5 | ||
|
|
61014431aa | ||
|
|
49bd63994c | ||
|
|
85b29d9407 | ||
|
|
b83fdea49b | ||
|
|
beec0ee590 | ||
|
|
4121113688 | ||
|
|
62da379472 | ||
|
|
3c9053b055 | ||
|
|
71b07ce2bd | ||
|
|
ebea3d273e | ||
|
|
f3a76b8a63 | ||
|
|
ba93791077 | ||
|
|
b994858907 | ||
|
|
74ad34a0c5 | ||
|
|
1b5b37c06b | ||
|
|
c8e1bd0e9a | ||
|
|
e9c8d3d740 | ||
|
|
f567b866a0 | ||
|
|
3471d3ee2d | ||
|
|
6e197f5751 | ||
|
|
b568c18346 | ||
|
|
1b29876ba8 | ||
|
|
4c6f3d2d69 | ||
|
|
8d3f7eded2 | ||
|
|
0222feeda1 | ||
|
|
f10cf1a9a0 | ||
|
|
85b2089fd3 | ||
|
|
885808c64c | ||
|
|
78069b42e7 | ||
|
|
3e0063e874 | ||
|
|
6ec1ab3d4f | ||
|
|
33b4540ad9 | ||
|
|
a434b51653 | ||
|
|
222d8d3575 | ||
|
|
8e2d006048 | ||
|
|
fd9f204b6d | ||
|
|
f0f358a138 | ||
|
|
cfffcd4513 | ||
|
|
e51587c66e | ||
|
|
f930953e6a | ||
|
|
ebdc10d1c5 | ||
|
|
d12370568f | ||
|
|
176125deca | ||
|
|
cb934ca39f | ||
|
|
4fd95fdcbe | ||
|
|
cb62349054 | ||
|
|
1b72119673 | ||
|
|
add474e825 | ||
|
|
f32e4d4b30 | ||
|
|
eff87b3dc5 | ||
|
|
ea4821fd18 | ||
|
|
6285668dcd | ||
|
|
449bc7d12b | ||
|
|
ee867e7f3b | ||
|
|
b4c7ae9c8c | ||
|
|
95995a45cf | ||
|
|
823bb82b8c | ||
|
|
9a5bb46f78 | ||
|
|
950ca953f5 | ||
|
|
495c8c9eac | ||
|
|
2887795586 | ||
|
|
6a893f50ae | ||
|
|
5d08353284 | ||
|
|
a37037ded4 | ||
|
|
d331b72dfd | ||
|
|
3b21d35f23 | ||
|
|
62a694b8b7 | ||
|
|
eeba2960f9 | ||
|
|
91550c926b | ||
|
|
184525687c | ||
|
|
cdede817fd | ||
|
|
df42c2f6fe | ||
|
|
b53f2f4a60 | ||
|
|
5ff27c4fe2 | ||
|
|
e5fff5117d | ||
|
|
615cd5aac3 | ||
|
|
621d95a89e | ||
|
|
cd383167f9 | ||
|
|
cb2969002c | ||
|
|
1cf204e23d | ||
|
|
393834b253 | ||
|
|
4ca8256e18 | ||
|
|
280d91b9bf | ||
|
|
980152fd53 | ||
|
|
d994420d4d | ||
|
|
38f3ecf01f | ||
|
|
5cd0d05b31 | ||
|
|
62519c3638 | ||
|
|
27bb2deb1a | ||
|
|
a2c8e71f14 | ||
|
|
d1f56e7c2e | ||
|
|
a9fd0cbf02 | ||
|
|
be8c89ec00 | ||
|
|
4f53752693 | ||
|
|
393673222d | ||
|
|
a88f4524d5 | ||
|
|
3a02066a66 | ||
|
|
7e3981d1a3 | ||
|
|
ec2900e4dd | ||
|
|
d718a27abf | ||
|
|
db8027911c | ||
|
|
aef3b4117d | ||
|
|
6728b77aca | ||
|
|
a7c0b42965 | ||
|
|
667b6ecbbd | ||
|
|
b852878a4a | ||
|
|
940f1f7486 | ||
|
|
49c705b5ad | ||
|
|
5163e8a433 | ||
|
|
71e9603e4e | ||
|
|
c71102f44e | ||
|
|
9b9158a765 | ||
|
|
595e2b4e81 | ||
|
|
ae8e205343 | ||
|
|
00b33fbd42 | ||
|
|
841b06df37 | ||
|
|
522a06f864 | ||
|
|
fa14ed1649 | ||
|
|
64e41e066b | ||
|
|
2a71f35005 | ||
|
|
961a337a5e | ||
|
|
f0622a692e | ||
|
|
ef7042dd9d | ||
|
|
046ecfa329 | ||
|
|
47fbe49861 | ||
|
|
2f34315634 | ||
|
|
c8d6ad6546 | ||
|
|
3dfae3074e | ||
|
|
97bebe52c9 | ||
|
|
8e1845f57b | ||
|
|
6cd6769997 | ||
|
|
03884d3566 | ||
|
|
899925e249 | ||
|
|
efefa398ce | ||
|
|
1ee24c69bc | ||
|
|
b16a36980c | ||
|
|
c1b52bbc04 | ||
|
|
9461ad4d4d | ||
|
|
e2ef6e9c34 | ||
|
|
cdc8873f5b | ||
|
|
b82b205d92 | ||
|
|
39d879f240 | ||
|
|
9c1db9cab3 | ||
|
|
2f5c00f2bd | ||
|
|
dc36b313ff | ||
|
|
093fa0107a | ||
|
|
e8f5ec2579 | ||
|
|
62241668df | ||
|
|
ee67c08b64 | ||
|
|
41a14391a2 | ||
|
|
6eccca31b9 | ||
|
|
d497942a9f | ||
|
|
68c7352108 | ||
|
|
0d40e43c4b | ||
|
|
9867fd82df | ||
|
|
1c941fdfbb | ||
|
|
0ba67a72f8 | ||
|
|
09b9e26b2d | ||
|
|
d25c1d5564 | ||
|
|
d4358ed3f7 | ||
|
|
cc6ffa35fc | ||
|
|
55e9cb2f58 | ||
|
|
2641256254 | ||
|
|
473116f603 | ||
|
|
e18d63df4a | ||
|
|
4b1b3f6913 | ||
|
|
f6da5e4136 | ||
|
|
d1d5d39144 | ||
|
|
754358113f | ||
|
|
c24207516d | ||
|
|
2a23bce78d | ||
|
|
a19b82ea5f | ||
|
|
ed9590aef1 | ||
|
|
25683221cc | ||
|
|
9cc9e3ddbb | ||
|
|
654f8aeb19 | ||
|
|
e349abb897 | ||
|
|
3027a6755f | ||
|
|
5404aa6037 | ||
|
|
a319e32438 | ||
|
|
2eaf57fc67 | ||
|
|
88ec4a55cb | ||
|
|
0acbc60ec1 | ||
|
|
4362971c6a | ||
|
|
94c0d1b833 | ||
|
|
1e795d4e16 | ||
|
|
93a027ca23 | ||
|
|
5f3958fab4 | ||
|
|
1351b708fe | ||
|
|
e867e039bb | ||
|
|
1d1087a3b3 | ||
|
|
e91f1ea1b2 | ||
|
|
55d16edadc | ||
|
|
b79245ddb3 | ||
|
|
e706300b6d | ||
|
|
d08cbd77aa | ||
|
|
b070ae73a4 | ||
|
|
2c30eef9a1 | ||
|
|
31cdc113fc | ||
|
|
f6f813498b | ||
|
|
4c8baaf7c0 | ||
|
|
57ca937f27 | ||
|
|
d13e39e345 | ||
|
|
f52c141062 | ||
|
|
40042da8ff | ||
|
|
c251304146 | ||
|
|
c047e37a79 | ||
|
|
d2c57447f0 | ||
|
|
79e9dabc11 | ||
|
|
b04dc4d457 | ||
|
|
f86e7810be | ||
|
|
2018c82ea1 | ||
|
|
c27f3603e6 | ||
|
|
6f82b806ad | ||
|
|
cbb8935660 | ||
|
|
21ebbb942f | ||
|
|
988ecd95e3 | ||
|
|
3f3e70c686 | ||
|
|
073b040981 | ||
|
|
b1a058ccdd | ||
|
|
cbc7b8c3c7 | ||
|
|
13340e4200 | ||
|
|
0076c1f218 | ||
|
|
6fc71b7528 | ||
|
|
b42f1e99e2 | ||
|
|
afd6ad06a6 | ||
|
|
ea0bfaa2f3 | ||
|
|
5c3ec176c2 | ||
|
|
40425ee9ec | ||
|
|
424db825a3 | ||
|
|
b9cc4cd629 | ||
|
|
243b8f025b | ||
|
|
6c60b67588 | ||
|
|
910bb13711 | ||
|
|
add55cfc2a | ||
|
|
565820325b | ||
|
|
6bb4d67d92 | ||
|
|
534d50c03a | ||
|
|
9a42883a96 | ||
|
|
7c77e2c2b6 | ||
|
|
ea8c46cd30 | ||
|
|
fead3b0671 | ||
|
|
081990b49e | ||
|
|
6b89f8c6db | ||
|
|
373097040a | ||
|
|
a4ab75172c | ||
|
|
5cf9958957 | ||
|
|
b137e08e84 | ||
|
|
a1af8e8687 | ||
|
|
53c7ddcb22 | ||
|
|
3872077ff1 | ||
|
|
9e85c4f3d1 | ||
|
|
2531102623 | ||
|
|
33deada6f0 | ||
|
|
9d1506bb7e | ||
|
|
c3f115c9ec | ||
|
|
430d402b14 | ||
|
|
e011dac98b | ||
|
|
42b84d1ccb | ||
|
|
288105eac7 | ||
|
|
842b522e68 | ||
|
|
e6f36974c8 | ||
|
|
679b4df881 | ||
|
|
666cae6f49 | ||
|
|
be2ac1d1b1 | ||
|
|
266e5b30eb | ||
|
|
4e5d06b580 | ||
|
|
fe334135ce | ||
|
|
aef10fb5e7 | ||
|
|
86707c1f0b | ||
|
|
a28d5b3c09 | ||
|
|
550ae9c784 | ||
|
|
cd5b91680a | ||
|
|
221ab20898 | ||
|
|
96534789db | ||
|
|
26128dd788 | ||
|
|
799e992542 | ||
|
|
fa524eec60 | ||
|
|
6dced29b49 | ||
|
|
2ea613a42b | ||
|
|
985df20519 | ||
|
|
f6161b9be9 | ||
|
|
25c5014d3c | ||
|
|
b8b7b53d96 | ||
|
|
7707c4b8e6 | ||
|
|
437f95f00f | ||
|
|
099672fabb | ||
|
|
860515a716 | ||
|
|
c85551a42e | ||
|
|
79dc6e7472 | ||
|
|
06e456384c | ||
|
|
38f7d24a80 | ||
|
|
145c78ef3e | ||
|
|
dd437bf0a5 | ||
|
|
d82d119729 | ||
|
|
7f76202865 | ||
|
|
aee92751ac | ||
|
|
2ea7236d45 | ||
|
|
cedc04e1e3 | ||
|
|
edc6eb1747 | ||
|
|
be5ec94fdf | ||
|
|
23a13fe1b6 | ||
|
|
0168b765c1 | ||
|
|
01358a5a45 | ||
|
|
106516d12d | ||
|
|
ba858743e5 | ||
|
|
9fd860ef3c | ||
|
|
46ccdc3820 | ||
|
|
242fe54afd | ||
|
|
df5d296cd9 | ||
|
|
dc4630f214 | ||
|
|
ac07d3bac7 | ||
|
|
f641eef8f7 | ||
|
|
f17b5b3cd3 | ||
|
|
d945f4960b | ||
|
|
6a5a6ac62f | ||
|
|
a9ba4300ec | ||
|
|
7bb649f11a | ||
|
|
85ada0ac99 | ||
|
|
be343a3b34 | ||
|
|
0ac0e5c7d3 | ||
|
|
7f272768e4 | ||
|
|
7b74c9900f | ||
|
|
36f1a39b31 | ||
|
|
6d380082eb | ||
|
|
8d3917e9fa | ||
|
|
c3cd1a5bfa | ||
|
|
eaeddc36c2 | ||
|
|
4f40b65f0c | ||
|
|
f958aa504e | ||
|
|
3d1b95aa7a | ||
|
|
4bb67bc06f | ||
|
|
0929c93caf | ||
|
|
c0368d2b16 | ||
|
|
85a212ef93 | ||
|
|
12c3cb3dc0 | ||
|
|
16710e7ab5 | ||
|
|
b652aaf0cb | ||
|
|
30020263ba | ||
|
|
3cf5d36972 | ||
|
|
c9ae96bcf7 | ||
|
|
5955110e67 | ||
|
|
4191e15c77 | ||
|
|
d60baa2b80 | ||
|
|
a50bc331db | ||
|
|
eff4453de9 | ||
|
|
4cfc8fec0e | ||
|
|
c9e1c2f80f | ||
|
|
93039e40cc | ||
|
|
015a52a20d | ||
|
|
d53cc8bfe7 | ||
|
|
3c4eca60b7 | ||
|
|
c85e28b971 | ||
|
|
d373068619 | ||
|
|
997f3d7862 | ||
|
|
f12f53692e | ||
|
|
b921b8cf0f | ||
|
|
61781c72fe | ||
|
|
3b5cfc5ecf | ||
|
|
a42a789d29 | ||
|
|
d77c014723 | ||
|
|
23fca9c067 | ||
|
|
37eb1901f9 | ||
|
|
98c4e7764f | ||
|
|
d3e4463612 | ||
|
|
b812045d82 | ||
|
|
b1bcdc88e0 | ||
|
|
62c5a9d06d | ||
|
|
dcdc842336 | ||
|
|
12eaa3073a | ||
|
|
34875f57a5 | ||
|
|
f0bf1343b0 | ||
|
|
4e6b9514d5 | ||
|
|
3b495d7518 | ||
|
|
badf8701bf | ||
|
|
85fa0d4926 | ||
|
|
3de9643893 | ||
|
|
73629944c0 | ||
|
|
c97c83bfb6 | ||
|
|
19b18afac9 | ||
|
|
e3c424e129 | ||
|
|
c0716d7f63 | ||
|
|
d43af8c9c1 | ||
|
|
2825100f77 | ||
|
|
b1bee31d61 | ||
|
|
522276b80d | ||
|
|
7bc1470a1e | ||
|
|
ca32cb0dfc | ||
|
|
d59f55b90c | ||
|
|
02936de993 | ||
|
|
8ed223343d | ||
|
|
90f7ff1c23 | ||
|
|
a56220f158 | ||
|
|
d40b426c1b | ||
|
|
5342881bf4 | ||
|
|
c84c17ea8c | ||
|
|
f976b8261f | ||
|
|
10f4c7fa18 | ||
|
|
665d212bd6 | ||
|
|
9e6e653c57 | ||
|
|
bda4da71a6 | ||
|
|
a24fc941a6 | ||
|
|
f307ad060b | ||
|
|
1845b7be54 | ||
|
|
a260e157eb | ||
|
|
0641b1a73e | ||
|
|
9ba57f0c9d | ||
|
|
9c2f0b2dc8 | ||
|
|
d4bbebeb93 | ||
|
|
1a22b4f0aa | ||
|
|
9c4d5341ae | ||
|
|
b9d498e01c | ||
|
|
a1e38a3e40 | ||
|
|
c0ae7763a6 | ||
|
|
9f98b1d3d1 | ||
|
|
a7e2224f05 | ||
|
|
3bb1e41394 | ||
|
|
e437379939 | ||
|
|
3ad4f6ef4b | ||
|
|
4170a61d0b | ||
|
|
b3c5ab41e7 | ||
|
|
b3fad1077e | ||
|
|
522e1f57d7 | ||
|
|
ff86f29f41 | ||
|
|
3107027132 | ||
|
|
728db73b09 | ||
|
|
fcb8ec9967 | ||
|
|
5b8fe12502 | ||
|
|
6e24f2ff13 | ||
|
|
74d715243c | ||
|
|
d9993860cb | ||
|
|
6a6f3a8291 |
@@ -9,9 +9,9 @@ For email questions/requests/alerts there is always the risk of memory
|
|||||||
exhaustion on the part of the maintainer(s).
|
exhaustion on the part of the maintainer(s).
|
||||||
|
|
||||||
If you are unsure of what to do, or how to implement an idea or bugfix,
|
If you are unsure of what to do, or how to implement an idea or bugfix,
|
||||||
open an issue with `"[RFC: Unsure if this is a bug ... ?"`, or similar,
|
open an issue with `"[RFC: Unsure if this is a bug ... ?"`, or use the
|
||||||
so we can discuss it. Talking about the code first is the best way to
|
GitHub discussions forum, so we can discuss it. Talking about the code
|
||||||
get started before submitting a pull request.
|
first is the best way to get started before submitting a pull request.
|
||||||
|
|
||||||
Either way, when sending an email, patch, or pull request, start by
|
Either way, when sending an email, patch, or pull request, start by
|
||||||
stating the version the change is made against, what it does, and why.
|
stating the version the change is made against, what it does, and why.
|
||||||
@@ -73,7 +73,6 @@ It is expected of everyone engaging in the project to, in the words of
|
|||||||
Bill & Ted; [be excellent to each other][conduct].
|
Bill & Ted; [be excellent to each other][conduct].
|
||||||
|
|
||||||
|
|
||||||
[github]: https://github.com/troglobit/finit/
|
|
||||||
[KNF]: https://en.wikipedia.org/wiki/Kernel_Normal_Form
|
[KNF]: https://en.wikipedia.org/wiki/Kernel_Normal_Form
|
||||||
[gitbook]: https://git-scm.com/book/ch5-2.html
|
[gitbook]: https://git-scm.com/book/ch5-2.html
|
||||||
[conduct]: CODE-OF-CONDUCT.md
|
[conduct]: CODE-OF-CONDUCT.md
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
name: Bob the Builder
|
||||||
|
|
||||||
|
# Run on all branches, including all pull requests, except the 'dev'
|
||||||
|
# branch since that's where we run Coverity Scan (limited tokens/day)
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- '**'
|
||||||
|
- '!dev'
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- '**'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
# Verify we can build on latest Ubuntu with both gcc and clang
|
||||||
|
name: ${{ matrix.compiler }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
compiler: [gcc, clang]
|
||||||
|
fail-fast: false
|
||||||
|
env:
|
||||||
|
MAKEFLAGS: -j3
|
||||||
|
CC: ${{ matrix.compiler }}
|
||||||
|
steps:
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get -y update
|
||||||
|
sudo apt-get -y install pkg-config tree jq libuev-dev libite-dev
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Static Finit
|
||||||
|
run: |
|
||||||
|
./autogen.sh
|
||||||
|
./configure --prefix= --enable-static
|
||||||
|
make V=1
|
||||||
|
- name: Regular Finit
|
||||||
|
run: |
|
||||||
|
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
|
||||||
|
--enable-x11-common-plugin --enable-testserv-plugin --with-watchdog \
|
||||||
|
--with-keventd
|
||||||
|
make clean
|
||||||
|
make V=1
|
||||||
|
- name: Install to /tmp
|
||||||
|
run: |
|
||||||
|
DESTDIR=/tmp make install-strip
|
||||||
|
tree /tmp || true
|
||||||
|
- name: Check dependencies
|
||||||
|
run: |
|
||||||
|
ldd /tmp/sbin/finit
|
||||||
|
size /tmp/sbin/finit
|
||||||
|
ldd /tmp/sbin/initctl
|
||||||
|
size /tmp/sbin/initctl
|
||||||
|
ldd /tmp/sbin/reboot
|
||||||
|
size /tmp/sbin/reboot
|
||||||
|
- name: Verify starting and showing usage text
|
||||||
|
run: |
|
||||||
|
sudo /tmp/sbin/finit -h
|
||||||
|
sudo /tmp/sbin/initctl -h
|
||||||
|
- name: Run Unit Tests
|
||||||
|
run: |
|
||||||
|
make check || (cat test/test-suite.log; false)
|
||||||
|
- name: Upload Test Results
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: finit-test-${{ matrix.compiler }}
|
||||||
|
path: test/*.log
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
name: Coverity Scan
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'dev'
|
||||||
|
|
||||||
|
env:
|
||||||
|
PROJECT_NAME: finit
|
||||||
|
CONTACT_EMAIL: troglobit@gmail.com
|
||||||
|
COVERITY_NAME: troglobit-finit
|
||||||
|
COVERITY_PROJ: troglobit%2Ffinit
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
coverity:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
id: coverity-toolchain-cache
|
||||||
|
with:
|
||||||
|
path: cov-analysis-linux64
|
||||||
|
key: ${{ runner.os }}-coverity
|
||||||
|
- name: Download Coverity Scan
|
||||||
|
if: steps.coverity-toolchain-cache.outputs.cache-hit != 'true'
|
||||||
|
env:
|
||||||
|
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
|
||||||
|
run: |
|
||||||
|
wget -q https://scan.coverity.com/download/cxx/linux64 \
|
||||||
|
--post-data "token=$TOKEN&project=${COVERITY_PROJ}" \
|
||||||
|
-O cov-analysis-linux64.tar.gz
|
||||||
|
mkdir cov-analysis-linux64
|
||||||
|
tar xzf cov-analysis-linux64.tar.gz --strip 1 -C cov-analysis-linux64
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get -y update
|
||||||
|
sudo apt-get -y install pkg-config
|
||||||
|
wget https://github.com/troglobit/libuev/releases/download/v2.4.0/libuev-2.4.0.tar.xz
|
||||||
|
wget https://github.com/troglobit/libite/releases/download/v2.5.2/libite-2.5.2.tar.gz
|
||||||
|
tar xf libuev-2.4.0.tar.xz
|
||||||
|
tar xf libite-2.5.2.tar.gz
|
||||||
|
(cd libuev-2.4.0 && ./configure --prefix=/usr && make && sudo make install-strip)
|
||||||
|
(cd libite-2.5.2 && ./configure --prefix=/usr && make && sudo make install-strip)
|
||||||
|
sudo ldconfig
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
./autogen.sh
|
||||||
|
./configure --prefix= --enable-x11-common-plugin --with-watchdog --with-keventd
|
||||||
|
export PATH=`pwd`/cov-analysis-linux64/bin:$PATH
|
||||||
|
cov-build --dir cov-int make
|
||||||
|
- name: Submit result to Coverity Scan
|
||||||
|
env:
|
||||||
|
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
|
||||||
|
run: |
|
||||||
|
tar czvf ${PROJECT_NAME}.tgz cov-int
|
||||||
|
curl \
|
||||||
|
--form project=${COVERITY_NAME} \
|
||||||
|
--form token=$TOKEN \
|
||||||
|
--form email=${CONTACT_EMAIL} \
|
||||||
|
--form file=@${PROJECT_NAME}.tgz \
|
||||||
|
--form version=trunk \
|
||||||
|
--form description="${PROJECT_NAME} $(git rev-parse HEAD)" \
|
||||||
|
https://scan.coverity.com/builds?project=${COVERITY_PROJ}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
name: Release General
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- '[0-9]+.[0-9]+*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
name: Build and upload release tarball
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Installing dependencies ...
|
||||||
|
run: |
|
||||||
|
sudo apt-get -y update
|
||||||
|
sudo apt-get -y install pkg-config jq libuev-dev libite-dev
|
||||||
|
- name: Creating Makefiles ...
|
||||||
|
run: |
|
||||||
|
./autogen.sh
|
||||||
|
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
|
||||||
|
--enable-x11-common-plugin --enable-testserv-plugin --with-watchdog \
|
||||||
|
--with-keventd
|
||||||
|
- name: Build release ...
|
||||||
|
run: |
|
||||||
|
make release || (cat test/test-suite.log; false)
|
||||||
|
ls -lF ../
|
||||||
|
mkdir -p artifacts/
|
||||||
|
mv ../*.tar.* artifacts/
|
||||||
|
- name: Extract ChangeLog entry ...
|
||||||
|
run: |
|
||||||
|
awk '/-----*/{if (x == 1) exit; x=1;next}x' ChangeLog.md \
|
||||||
|
|head -n -1 > release.md
|
||||||
|
cat release.md
|
||||||
|
- uses: ncipollo/release-action@v1
|
||||||
|
with:
|
||||||
|
name: Finit v${{ github.ref_name }}
|
||||||
|
bodyFile: "release.md"
|
||||||
|
artifacts: "artifacts/*"
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
name: Weekly Distcheck
|
||||||
|
|
||||||
|
# Verify that `make distcheck` works as intended: all tests pass, and
|
||||||
|
# any new files are distributed in the tarballs
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * 0'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
schedule:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
run: ${{ steps.check.outputs.run }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Check for any commits since last week
|
||||||
|
run: |
|
||||||
|
commits="$(git log --format=%H --since='1 week ago')"
|
||||||
|
if [ -n "$commits" ]; then
|
||||||
|
echo "run=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "run=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
distcheck:
|
||||||
|
needs: schedule
|
||||||
|
if: ${{ needs.schedule.outputs.run == 'true' }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get -y update
|
||||||
|
sudo apt-get -y install pkg-config jq libuev-dev libite-dev
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Base run
|
||||||
|
run: |
|
||||||
|
./autogen.sh
|
||||||
|
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var
|
||||||
|
make -j9 V=1
|
||||||
|
- name: Install to /tmp
|
||||||
|
run: |
|
||||||
|
DESTDIR=/tmp make install-strip
|
||||||
|
- name: Check dist tarball
|
||||||
|
run: |
|
||||||
|
ver=$(/tmp/sbin/initctl -V | awk '/Finit.*/ {print $2;}')
|
||||||
|
dir=finit-$ver/_build/sub
|
||||||
|
make -j1 distcheck || (cat $dir/test/test-suite.log; false)
|
||||||
@@ -45,3 +45,6 @@ GTAGS
|
|||||||
/.autoconf
|
/.autoconf
|
||||||
/.automake
|
/.automake
|
||||||
/.built
|
/.built
|
||||||
|
|
||||||
|
# VS Code user settings
|
||||||
|
.vscode
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# GNU Global .conf file, see /etc/gtags/gtags.conf for details.
|
||||||
|
default:\
|
||||||
|
:tc=default@/etc/gtags/gtags.conf:\
|
||||||
|
:tc=common:
|
||||||
|
|
||||||
|
common:\
|
||||||
|
:skip=tags,TAGS,ID,y.tab.c,y.tab.h,gtags.files,cscope.files,cscope.out,cscope.po.out,cscope.in.out,,{arch}/,autom4te.cache/,*.orig,*.rej,*.bak,*~,#*#,*.swp,*.tmp,*_flymake.*,*_flymake,*.o,*.a,*.so,*.lo,*.zip,*.gz,*.bz2,*.xz,*.lzh,*.Z,*.tgz,*.min.js,*min.css,sysroot/:
|
||||||
-62
@@ -1,62 +0,0 @@
|
|||||||
# Travis CI integration -- https://travis-ci.org/troglobit/finit
|
|
||||||
# Defaults to GNU GCC and autotools: ./configure && make && make test
|
|
||||||
language: c
|
|
||||||
|
|
||||||
# Use docker for quicker builds, it now allows https://docs.travis-ci.com/user/apt/
|
|
||||||
sudo: false
|
|
||||||
|
|
||||||
# Test build with both GCC and Clang (LLVM)
|
|
||||||
compiler:
|
|
||||||
- gcc
|
|
||||||
- clang
|
|
||||||
|
|
||||||
# The secure: declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
|
||||||
# via the "travis encrypt" command using the project repo's public key
|
|
||||||
env:
|
|
||||||
global:
|
|
||||||
- PKG_CONFIG_PATH=/tmp/lib/pkgconfig
|
|
||||||
- CFLAGS="-W -Wall -Wextra"
|
|
||||||
- secure: "eOiuHs02lG2Uv146K9dMqucGTWUJFEhpz1oAtwe+kPrRXsXWc20hYMO+DSpMgD05vSvNeQA6p7h7LdRFQ+/g/Obj27TsOE+RKkUvRAtdwzxnKVyii9C/nmML8cFw7rIA0VS8O9mAkVYeyDxNDupBp3e9DPCibhKPvqCvioTnyy4="
|
|
||||||
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
packages:
|
|
||||||
- tree
|
|
||||||
coverity_scan:
|
|
||||||
project:
|
|
||||||
name: "troglobit/finit"
|
|
||||||
description: "finit | Fast & Extensible init for Linux"
|
|
||||||
notification_email: troglobit@gmail.com
|
|
||||||
build_command_prepend: "./autogen.sh && ./configure --prefix=/tmp --disable-doc --disable-contrib --enable-watchdog --enable-fallback-shell"
|
|
||||||
build_command: "make"
|
|
||||||
branch_pattern: dev
|
|
||||||
|
|
||||||
install:
|
|
||||||
- wget https://github.com/troglobit/libuev/releases/download/v2.3.2/libuev-2.3.2.tar.xz
|
|
||||||
- wget https://github.com/troglobit/libite/releases/download/v2.3.1/libite-2.3.1.tar.gz
|
|
||||||
- tar xf libuev-2.3.2.tar.xz
|
|
||||||
- tar xf libite-2.3.1.tar.gz
|
|
||||||
- (cd libuev-2.3.2 && ./configure --prefix=/tmp && make && make install-strip)
|
|
||||||
- (cd libite-2.3.1 && ./configure --prefix=/tmp && make && make install-strip)
|
|
||||||
|
|
||||||
# Custom build script for the time being, no "make test" yet
|
|
||||||
script:
|
|
||||||
- ./autogen.sh
|
|
||||||
- ./configure --prefix=/tmp --enable-static
|
|
||||||
- make clean
|
|
||||||
- make V=1 -j5
|
|
||||||
- ./configure --prefix=/tmp --enable-x11-common-plugin --enable-fallback-shell --enable-watchdog
|
|
||||||
- cat config.log
|
|
||||||
- make clean
|
|
||||||
- make V=1 -j5
|
|
||||||
- make install-strip
|
|
||||||
- tree /tmp
|
|
||||||
- ldd /tmp/sbin/finit
|
|
||||||
- size /tmp/sbin/finit
|
|
||||||
- size /tmp/sbin/initctl
|
|
||||||
- size /tmp/sbin/reboot
|
|
||||||
- LD_LIBRARY_PATH=/tmp/lib /tmp/sbin/initctl -h
|
|
||||||
- unshare -V
|
|
||||||
- nsenter -V
|
|
||||||
- chroot --version
|
|
||||||
- 'LD_LIBRARY_PATH=/tmp/lib make distcheck || (cat finit-4.0-beta1/_build/sub/test/test-suite.log; exit 1)'
|
|
||||||
+690
-29
@@ -4,12 +4,647 @@ Change Log
|
|||||||
All relevant changes are documented in this file.
|
All relevant changes are documented in this file.
|
||||||
|
|
||||||
|
|
||||||
[4.0][UNRELEASED] - 2021-03-xx
|
[4.4][] - 2023-05-15
|
||||||
------------------------------
|
--------------------
|
||||||
|
|
||||||
|
> **Note 1:** this release contains changes to the `.conf` parser. If you
|
||||||
|
> have .conf file statements with comment character (`#`) in the command
|
||||||
|
> options or description, you must now escape them (`\#`). Issue #186
|
||||||
|
>
|
||||||
|
> **Note 2:** prior to this release, runlevel `S` and `0` were after
|
||||||
|
> boot treated as the same runlevel. This caused `task [06] ...` to
|
||||||
|
> also run at bootstrap instead of just at shutdown and reboot. The
|
||||||
|
> changes made to Finit to separate `S` from `0` require you to update
|
||||||
|
> the allowed runlevels for services that are allowed to continue
|
||||||
|
> running at shutdown. I.e., change `[S123456789]` to `[S0123456789]`
|
||||||
|
> for, e.g., `sysklogd`. Issue #352
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
* Add limited tmpfiles.d(5) support
|
||||||
|
|
||||||
|
This change adds very basic `tmpfiles.d/` support to Finit. Most of
|
||||||
|
the basic types are supported, but not all, so for now, please check
|
||||||
|
the code and examples for details on what is working.
|
||||||
|
|
||||||
|
* If a run/task/service command does not exist, skip registering it
|
||||||
|
|
||||||
|
This changes the semantics of Finit a bit by checking for the command
|
||||||
|
to run when registering it, skipping commands that cannot be found in
|
||||||
|
the absolute path provided in the command, or in `$PATH`
|
||||||
|
|
||||||
|
This change includes a new `nowarn` flag that can be used to prevent
|
||||||
|
Finit from warning for missing commands. See below for an example.
|
||||||
|
|
||||||
|
* Add run/task/service support for `conflict:foo` handling
|
||||||
|
* Add run/task/service support for `if:[!]ident` and `if:<[!]cond>`
|
||||||
|
|
||||||
|
Conditional loading of stanza depending on ident is already loaded (or
|
||||||
|
not), or condition satisfied (or not). E.g., do not run `mdev` if we
|
||||||
|
found and registered `udevd`, or load service only if `<boot/testing>`
|
||||||
|
condition is set.
|
||||||
|
|
||||||
|
The optional leading `!` negates the comparison, if NOT foo then ...
|
||||||
|
|
||||||
|
* Add support for static services in `/lib/finit/system/*.conf`
|
||||||
|
|
||||||
|
Slowly migrating away from hard-coded services in plugins. This way
|
||||||
|
it's possible for the user to both inspect and override as needed.
|
||||||
|
|
||||||
|
* Migrate hotplug plugin to a conditional `/lib/finit/system/hotplug.conf`
|
||||||
|
|
||||||
|
This is the first example of the just minted advanced stanza syntax with
|
||||||
|
`if:`-statements, `conflict:` handling, and `nowarn` flags.
|
||||||
|
|
||||||
|
* Initial support for template services, `foo@.conf`, similar to systemd
|
||||||
|
|
||||||
|
$ initctl show avahi-autoipd@
|
||||||
|
service :%i avahi-autoipd --syslog %i -- ZeroConf for %i
|
||||||
|
|
||||||
|
To enable ZeroConf for, e.g., `eth0`, use
|
||||||
|
|
||||||
|
$ initctl enable avahi-autoipd@eth0.conf
|
||||||
|
|
||||||
|
The enabled symlink will be set up to `avahi-autoipd@.conf` and every
|
||||||
|
instance of `%i` will in the instantiated directive be replaced with
|
||||||
|
`eth0`. Inspect the result with:
|
||||||
|
|
||||||
|
$ initctl status avahi-autoipd:eth0
|
||||||
|
|
||||||
|
* Add `devmon`, a `<dev/foo>` condition provider, issue #185
|
||||||
|
* Support for line continuation character `\` in .conf files, issue #186
|
||||||
|
|
||||||
|
service name:sysklogd [S123456789] \
|
||||||
|
env:-/etc/default/sysklogd \
|
||||||
|
syslogd -F $SYSLOGD_ARGS \
|
||||||
|
-- System log daemon
|
||||||
|
|
||||||
|
* `HOOK_BASEFS_UP` has been moved! External plugins that need to call
|
||||||
|
`service_register()`, please use `HOOK_SVC_PLUGIN` from now on.
|
||||||
|
Apologies for any inconveniences this might cause!
|
||||||
|
* getty: add support for `/etc/os-release` to replace `uname` output
|
||||||
|
This change, which has a fallback to `/usr/lib/os-release`, overrides
|
||||||
|
traditional modifiers with the os-release variant. These values were
|
||||||
|
taken from `uname`, which on Linux systems are pretty useless since
|
||||||
|
they always return the kernel name and version instead of the
|
||||||
|
distro/OS values.
|
||||||
|
|
||||||
|
E.g., \s becomes `PRETTY_NAME` instead of 'Linux' and \v becomes the
|
||||||
|
pretty `VERSION`, while \r becomes `VERSION_ID`.
|
||||||
|
* Support for overriding `/etc/finit.conf` and `/etc/finit.d` issue #235
|
||||||
|
New (kernel) command line option `finit.config=PATH` which can be used
|
||||||
|
to redirect Finit to start up with, e.g., `/etc/factory.conf` instead of
|
||||||
|
`/etc/finit.conf`.
|
||||||
|
|
||||||
|
For the complete experience a new top-level configuration file directive
|
||||||
|
`rcsd PATH` has aslo been added. It in turn can be used by `factory.conf`
|
||||||
|
as follows to override `/etc/finit.d`:
|
||||||
|
|
||||||
|
rcsd /etc/factory.d
|
||||||
|
|
||||||
|
* Support for overriding `/etc/finit.d` from the alternate `finit.conf`
|
||||||
|
with a new `rcsd /path/to/dot.d/` .conf file directive
|
||||||
|
* Support for `fsck_mode=[auto,skip,force]` + `fsck_repair=[preen,no,yes]`
|
||||||
|
* Add `set` keyword for environment variables set in `/etc/finit.conf`
|
||||||
|
* Support `finit.cond=foo` cmdline `<boot/foo>` conditions, issue #250
|
||||||
|
* `initctl` JSON output support for status and conditions, issue #273
|
||||||
|
Example:
|
||||||
|
|
||||||
|
root@infix:~$ initctl status -j resolvconf
|
||||||
|
{
|
||||||
|
"identity": "resolvconf",
|
||||||
|
"description": "Update DNS configuration",
|
||||||
|
"type": "task",
|
||||||
|
"forking": false,
|
||||||
|
"status": "done",
|
||||||
|
"exit": { "code": 0 },
|
||||||
|
"origin": "/etc/finit.d/enabled/sysrepo.conf",
|
||||||
|
"command": "resolvconf -u",
|
||||||
|
"restarts": 0,
|
||||||
|
"pidfile": "none",
|
||||||
|
"pid": 0,
|
||||||
|
"user": "root",
|
||||||
|
"group": "root",
|
||||||
|
"uptime": 0,
|
||||||
|
"runlevels": [ 1, 2, 3, 4, 5, 7, 8, 9 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
The excellent tool `jq` can be used to extract parts of the output for
|
||||||
|
further scripting. E.g. `initctl status -j foo | jq .exit.status`
|
||||||
|
|
||||||
|
* Add JSON support to `initctl ls` command
|
||||||
|
|
||||||
|
This allows for easy access to the *disabled* services:
|
||||||
|
|
||||||
|
root@anarchy:~# initctl ls --json |jq '.available - .enabled'
|
||||||
|
[
|
||||||
|
"chronyd.conf",
|
||||||
|
"dnsmasq.conf",
|
||||||
|
"gdbserver.conf",
|
||||||
|
"inadyn.conf",
|
||||||
|
"inetd.conf",
|
||||||
|
"isisd.conf",
|
||||||
|
"lldpd.conf",
|
||||||
|
"mstpd.conf",
|
||||||
|
"ntpd.conf",
|
||||||
|
"ospf6d.conf",
|
||||||
|
"ospfd.conf",
|
||||||
|
"querierd.conf",
|
||||||
|
"ripd.conf",
|
||||||
|
"ripng.conf",
|
||||||
|
"sshd.conf",
|
||||||
|
"syslogd.conf",
|
||||||
|
"telnetd.conf",
|
||||||
|
"uftpd.conf",
|
||||||
|
"wpa_supplicant.conf",
|
||||||
|
"zebra.conf"
|
||||||
|
]
|
||||||
|
|
||||||
|
* Allow `manual:yes` on sysv/service/run/task stanzas, issue #274
|
||||||
|
* Add support for `oncrash:script` to call the `post:script` action, if
|
||||||
|
defined, for a crashing service. The `EXIT_CODE` variable sent to the
|
||||||
|
script is set to `crashed`. Issue #282
|
||||||
|
* Search for plugins in `/usr` and `/usr/local` as well, issue #284
|
||||||
|
* tty: add support for `passenv` flag to `/bin/login`, issue #286
|
||||||
|
* Add reboot/shutdown/poweroff timeout `-t SEC` to initctl, issue #295
|
||||||
|
* Add support for s6 and systemd readiness notification, issue #299.
|
||||||
|
Service readiness notification to support daemons employing systemd
|
||||||
|
and s6 notification. Complementing the native Finit readiness support
|
||||||
|
using PID files that exist already.
|
||||||
|
|
||||||
|
The two have slightly different ways of implementing readiness:
|
||||||
|
|
||||||
|
- https://www.freedesktop.org/software/systemd/man/sd_notify.html
|
||||||
|
- https://skarnet.org/software/s6/notifywhenup.html
|
||||||
|
|
||||||
|
Finit now provides both a `NOTIFY_SOCKET` environment variable, for
|
||||||
|
systemd, and a way to start s6 daemons with a descriptor argument.
|
||||||
|
|
||||||
|
For details on the syntax, see the `service` documentation.
|
||||||
|
|
||||||
|
This change also renames internal states for run/task/services to
|
||||||
|
avoid any confusion with the introduction of `ready:scripts`:
|
||||||
|
|
||||||
|
- `WAITING -> PAUSED`
|
||||||
|
- `READY -> WAITING`
|
||||||
|
|
||||||
|
A service condition that used, e.g., `<service/foo/ready>` should now
|
||||||
|
instead use `<service/foo/waiting>`
|
||||||
|
|
||||||
|
* Add `ready:script` for services, called when daemon is ready, issue #300
|
||||||
|
* Add support for running scripts at shutdown at two new hook points
|
||||||
|
during the shutdown process, issue #302. See doc/plugins.md for details:
|
||||||
|
|
||||||
|
- `HOOK_SVC_DN`: after all services and non-reserved processes have been
|
||||||
|
killed (and collected)
|
||||||
|
- `HOOK_SYS_DN`: after all file systems have been unmounted, *just prior*
|
||||||
|
to Finit calling `reboot()` to shut down or reboot the system
|
||||||
|
|
||||||
|
* The `modules-load` plugin now default to runlevel `[S]`, in previous
|
||||||
|
releases it was `[2345]`. This breaking change is to align it more
|
||||||
|
with what users mostly want (modules loaded before services start) and
|
||||||
|
can be changed back to the old behavior with a per-file setting:
|
||||||
|
|
||||||
|
set runlevel 2345
|
||||||
|
|
||||||
|
* The `modules-load` plugin now adds silent tasks for modprobe. This to
|
||||||
|
prevent confusing `[ OK ]` boot messages when in fact modprobe failed.
|
||||||
|
* The `modules-load` plugin now support `set modprobe /path/to/modprobe`
|
||||||
|
* The header files `finit/conf.h` and `finit/service.h` are now exported
|
||||||
|
for external plugins
|
||||||
|
* Add support for multiple args to `initctl cond set/clr`, issue #329
|
||||||
|
* Silence confusing `[ OK ]` progress from modules-load plugin, issue #332
|
||||||
|
|
||||||
|
This change drops the confusing status progress output, which was always
|
||||||
|
OK since the actual modprobe operation runs in the background. No need
|
||||||
|
to show status of the "added a task to finit, found modprobe" command.
|
||||||
|
|
||||||
|
* dbus plugin: adapt to other operating systems
|
||||||
|
|
||||||
|
Not all Linux systems are based on Debian, and even if they are inspired
|
||||||
|
by Debian (Buildroot), they do not necessarily use the same defaults.
|
||||||
|
Probes the system at runtime for:
|
||||||
|
|
||||||
|
- dbus user and group
|
||||||
|
- dbus PID file
|
||||||
|
|
||||||
|
If the user/group cannot be found we fall back to `root`, if the PID
|
||||||
|
file cannot be determined we ignore PID file readiness.
|
||||||
|
|
||||||
|
* Improve documentation for runparts and hook scripts. Issue #315, #320
|
||||||
|
* Add `HOOK_NETWORK_DN`, called after change to runlevel 6 or 0, issue #319
|
||||||
|
* Use sysklogd `logger` tool instead of legacy `logit` tool, issue #344
|
||||||
|
|
||||||
|
For log redirection Finit has the legacy `logit` tool. This change
|
||||||
|
allows Finit to use the `sysklogd` project's extended `logger` tool
|
||||||
|
instead, when available. Allowing logging with the process' PID.
|
||||||
|
|
||||||
|
* Add `initctl` aliases: `cat -> show`, `kill -> signal`
|
||||||
|
* Add `initctl -n,--noerr` to return OK(0) if services do not exist, for
|
||||||
|
integration with openresolv and scripts with similar requirements
|
||||||
|
* Add `initctl plugins`, list installed plugins
|
||||||
|
* Add timestamp to log messages in fallback and logging to `stderr`.
|
||||||
|
When there is no log daemon, and we are running in a container, or we
|
||||||
|
cannot log to the kernel ring buffer, then we log to `stderr`. This
|
||||||
|
change improves log output by prefixing each message with a timestamp.
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Fix #254: document limitations in `rc.local` and `runparts` scripts
|
||||||
|
* Fix #269: add compulsory kernel symlinks in `/dev`
|
||||||
|
* Fix #275: `initctl status foo` should list all instances, regression
|
||||||
|
introduced in v4.3
|
||||||
|
* Fix #278: enforce conditions also for running `pre:` scripts
|
||||||
|
* Fix #279: allow `restart:always`, of crashing services. Similar to
|
||||||
|
`respawn` but honors `restart_sec`
|
||||||
|
* Fix #280: allow calling `initctl restart foo` from within foo
|
||||||
|
* Fix #283: too quick timeout at bootstrap of lingering tasks
|
||||||
|
* Fix #285: `initctl restart` should start crashed service
|
||||||
|
* Fix #288: enable built-in `sulogin` in Alpine and Void Linux builds
|
||||||
|
* Fix #293: modprobe plugin: support for coldplugging more devices. It
|
||||||
|
turns out, not all buses in Linux add `modalias` attributes to their
|
||||||
|
devices in sysfs. One notable exception are MDIO buses. The plugin's
|
||||||
|
scan routine would thus not pick them up.
|
||||||
|
* Fix #294: `shutdown --help` mistakenly shuts down system
|
||||||
|
* Fix #310: Always use configured restart delay for crashing services.
|
||||||
|
If no delay is configured, default to an initial 2000 msec for forking
|
||||||
|
daemons and start-stop scripts, and 1 msec for non-forking daemons
|
||||||
|
* Fix #311: document how to combine device tree with conditions
|
||||||
|
* Fix #312: restart services with respawn set, e.g. ttys, immediately
|
||||||
|
* Fix #313: Cancel pending restart timer on stop/start/restart/reload
|
||||||
|
* Fix #314: skip run/task/service restart if conditions are lost
|
||||||
|
* Fix #315: add environment variables to hook scripts
|
||||||
|
|
||||||
|
All hook scripts are called with at least one environment variable
|
||||||
|
set, `FINIT_HOOK_NAME`, useful when reusing the same hook script for
|
||||||
|
multiple hook points. It is set to the string name, also used by the
|
||||||
|
path, e.g., `hook/net/up`
|
||||||
|
|
||||||
|
For all hook points from hook/sys/shutdown and later, `FINIT_SHUTDOWN`
|
||||||
|
is also set, to one of: `halt`, `poweroff`, `reboot`
|
||||||
|
|
||||||
|
* Fix #317: make sure hook scripts don't run twice, also fixes #316
|
||||||
|
* Fix #318: only show `[ OK ] Calling foo` progress for `runparts ...`
|
||||||
|
* Fix #320: the API/IPC socket is closed immediately at shutdown/reboot
|
||||||
|
to protect hook scripts or services calling initctl. There is no way
|
||||||
|
to service these requests safely at that time
|
||||||
|
* Fix #333: consider a service dirty if command line args have changed
|
||||||
|
|
||||||
|
This fixes `initctl reload` correctly restarting all daemons that have
|
||||||
|
new command line arguments.
|
||||||
|
|
||||||
|
Previously command line arguments changes were only acted upon if the
|
||||||
|
service was explicitly reloaded `initctl reload myservice`.
|
||||||
|
|
||||||
|
Found and fixed by Jack Newman
|
||||||
|
|
||||||
|
* Fix #338: ensure shutdown hooks are called properly; `hook/sys/down`
|
||||||
|
and `hook/svc/down` hook scripts, found and fixed by Jack Newman
|
||||||
|
* Fix #339: use absolute path in `/etc/finit.d/enabled/` symlinks, for
|
||||||
|
use-cases when `/etc` is read-only and `/etc/finit.d/enabled ->
|
||||||
|
/mnt/finit.d/enabled`, reported by Jack Newman
|
||||||
|
* Fix #340: Finit ignores deleted/moved `.conf` file sin `/etc/finit.d`
|
||||||
|
* Fix #342: in runlevel S (bootstrap), not all `initctl` commands can be
|
||||||
|
supported, block the following: runlevel, reload, start/stop, restart,
|
||||||
|
reload, halt, poweroff, suspend. Also, prevent `SIGHUP` and `SIGUSR1`
|
||||||
|
signals when in shutdown or reboot
|
||||||
|
* Fix #352: separate runlevel S from runlevel 0
|
||||||
|
* Fix #355: regression in v3.2 stopping a process and its group
|
||||||
|
|
||||||
|
In Finit v3.2 a regression was introduced that affects the way Finit
|
||||||
|
stops a supervised process and its process group.
|
||||||
|
|
||||||
|
Instead of sending SIGTERM to the process, and thus delegating the
|
||||||
|
responsibility to that process to inform any children it may have, as
|
||||||
|
of commit 91a9c83 Finit sends SIGTERM to the entire process group.
|
||||||
|
For SIGKILL this is fine, SIGKILL only runs as cleanup and as a last
|
||||||
|
ditch effort if the process doesn't respond to SIGTERM.
|
||||||
|
|
||||||
|
This regression, introduced in v3.2, directly affects services like
|
||||||
|
`avahi-autoipd` that have forked off children that it needs to tell to
|
||||||
|
exit cleanly before it returns. With the patch in question these
|
||||||
|
children are never allowed to complete, which in turn causes lingering
|
||||||
|
169.254 link-local addresses on interfaces.
|
||||||
|
|
||||||
|
* Fix bootmisc plugin: octal permission on `/run/lock` and `/var/lock`
|
||||||
|
|
||||||
|
* Ensure `initctl cond get` support the flux state (exit code 255)
|
||||||
|
* Fix potential socket leak at bootstrap and shutdown
|
||||||
|
* Fix potential NULL pointer deref in kernel command line parser
|
||||||
|
* Fix lingering condition in service after reload of service with new
|
||||||
|
config that has no condition
|
||||||
|
* Fix wrong path to command in service after reload, may have changed
|
||||||
|
* `logit`: fall back to package name if `$LOGNAME` and `$USER` are
|
||||||
|
unset. **Note:** you should probably not use `logit` in your own
|
||||||
|
scripts, it is only meant for internal use by Finit. We recommend
|
||||||
|
using `logger` from the `bsdutils` or `sysklogd` packages instead
|
||||||
|
* Fix issue where `env:`/`pre:`/`post:`/etc. is removed from a service
|
||||||
|
|
||||||
|
The trick is when reloading a service like this:
|
||||||
|
|
||||||
|
service env:/etc/env serv -np -e foo:bar
|
||||||
|
|
||||||
|
into this:
|
||||||
|
|
||||||
|
service pre:/bin/pre.sh serv -np
|
||||||
|
|
||||||
|
In the second the `env:` has been removed and `pre:` added. Prior to
|
||||||
|
this patch, `env:` was kept leading to unintended behavior.
|
||||||
|
* Fix parse/diff of command line args, e.g., `nginx -g 'daemon off;'`
|
||||||
|
|
||||||
|
Starting a service like this works fine:
|
||||||
|
|
||||||
|
service [2345789] env:-/etc/default/nginx nginx -g 'daemon off;'
|
||||||
|
|
||||||
|
However, on `initctl reload` (and no change to .conf files) the arg
|
||||||
|
list was lost while parsing the .conf files. Leading to a false
|
||||||
|
positive 'diff' in args causing nginx to be unnecessarily restarted.
|
||||||
|
* Fix issue with disabled "linewrap" on the console TTY after login.
|
||||||
|
The root cause is `qemu-system-x86_64 -nographics` disabling it when
|
||||||
|
starting up. The correct `\e[?7h` escape code is now used.
|
||||||
|
|
||||||
|
|
||||||
|
[4.3][] - 2022-05-15
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
Critical bug fix release. If you run a 32-bit target with GLIBC 2.34
|
||||||
|
you *need* to upgrade!
|
||||||
|
|
||||||
|
> **Note:** system verbosity on console at start and shutdown has been
|
||||||
|
> increased. Now the output of all commands is logged to the
|
||||||
|
> system logger, for early services `/dev/kmsg` is used.
|
||||||
|
>
|
||||||
|
> **Also:** please notice the updated support for enabling and disabling
|
||||||
|
> kernel and Finit debug messages on the system console. Very
|
||||||
|
> useful when debugging either of them, e.g., a kernel module.
|
||||||
|
> For details, see [cmdline.md](doc/cmdline.md).
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
* Support for overriding default runlevel from kernel command line. Any
|
||||||
|
runlevel `[1-9]` may be selected, except 6 (reboot). Issue #261
|
||||||
|
* New command line option: `finit.fstab=/etc/fstab.custom`, with full
|
||||||
|
support for mounting, mount helpers, fsck, and swapon/off, issue #224
|
||||||
|
* Support for special device `/dev/root`, which may not exist in `/dev`.
|
||||||
|
Finit now looks up the matching block device for `/` in `/sys/block/`
|
||||||
|
* Loading `module`s no longer shows arguments in progress output
|
||||||
|
* Warning messages in progress output now in yellow, not red, issue #214
|
||||||
|
* `initctl`, new command line option `-V,--version` for ease of use
|
||||||
|
* New condition `done` for run task, issue #207 by Ming Liu, Atlas Copco
|
||||||
|
* Refactor parts of shutdown and reboot sequence for PREEMPT-RT kernels,
|
||||||
|
by Robert Andersson, Mathias Thore, and Ming Liu, Atlas Copco
|
||||||
|
* Conditions for run/task/sysv status, e.g. `run/foo/success` and
|
||||||
|
`task/bar/failure`. Issue #232, by Ming Liu, Atlas Copco
|
||||||
|
* Conditions for services, can be used to synchronize other stanzas:
|
||||||
|
- `service/foo/running`
|
||||||
|
- `service/foo/halted`
|
||||||
|
- `service/foo/missing`
|
||||||
|
- `service/foo/crashed`
|
||||||
|
- `service/foo/stopped`
|
||||||
|
- `service/foo/busy`
|
||||||
|
- `service/foo/restart`
|
||||||
|
* `initctl signal` support, by Jörgen Sigvardsson, issue #225
|
||||||
|
* `initctl cond get` support to match `cond [set | clear]`, issue #255
|
||||||
|
* `[WARN]` messages on console now printed in yellow, issue #214
|
||||||
|
* Network services now also stopped when going to runlevel 6 (reboot),
|
||||||
|
not just runlevel 0 (shutdown) or 1 (single-user)
|
||||||
|
* When `ifup` is missing on the system, bring at least `lo` up at boot
|
||||||
|
* Log output from `ifup -a` (and `ifdown -a`), to syslog
|
||||||
|
* Avoid blocking PID 1 when starting SysV init scripts
|
||||||
|
* Allow custom `pid:` for SysV init scripts
|
||||||
|
* Document supported types of forking/non-forking services
|
||||||
|
* Auto-detect running in some common forms of containers
|
||||||
|
* Simplify shutdown/reboot when running in a container
|
||||||
|
* Log to `stderr` when running in a container w/o syslog daemon
|
||||||
|
* Add support for `type:forking` to services, already supported but
|
||||||
|
with a very difficult `pid:` syntax, issue #223. Docs updated
|
||||||
|
* Support for setting global environment variables in `finit.conf`,
|
||||||
|
please note: this also affects Finit itself, be careful!
|
||||||
|
* Extended environment variables for pre/post scripts, issue #189
|
||||||
|
* Document secret service option `respawn`, which bypasses the crash
|
||||||
|
semantics, allowing endless restarts
|
||||||
|
* Document secret `HOOK_BANNER`, the first hook point before the banner
|
||||||
|
* Document slightly confusing `initctl reload foo` command. It does
|
||||||
|
*not* reload the service's `.conf` file! Issue #263
|
||||||
|
* Log changes; all instances where previously the `basename cmd` of a
|
||||||
|
service was used to identify the service, now the proper `name:id` is
|
||||||
|
used instead. Meaning, a service without a custom `:ID` or `name:`
|
||||||
|
will display the same as before, but with any of those customizations
|
||||||
|
the name and name:id will now be shown. **Note:** this may affect any
|
||||||
|
log scrapers out there!
|
||||||
|
* New plugin: `hook-scripts`, allows [run-parts(8)][] style scripts to
|
||||||
|
run on any hook point. Contributed by Tobias Waldekranz
|
||||||
|
* `initctl` (`reboot`) falls back to `-f` when it detects it is in
|
||||||
|
`sulogin` recovery mode, issue #247
|
||||||
|
* The bundled `sulogin` is no longer enabled by default, in favor of
|
||||||
|
distribution versions. Enable with `./configure --with-sulogin`
|
||||||
|
* Support args to sysv-like scripts, e.g. `bridge-stp br0 start`
|
||||||
|
* The `modules-load` plugin now skips all lines starting with `#` and
|
||||||
|
`;`. Furthermore, files in `/etc/modules-load.d/*.conf` are now read
|
||||||
|
in lexicographic order and UNIX backup files (`foo.conf~`) are skipped
|
||||||
|
* The `name:id` tuple is now more consistently used in all log and debug
|
||||||
|
messages instead of the basename of the command
|
||||||
|
* Simplify error output of `initctl start/stop/restart/signal`, no more
|
||||||
|
extra usage help, just a plain error message
|
||||||
|
* Exit codes of `initctl` have changed to use LSB script standard and BSD
|
||||||
|
sysexits.h exit codes. As before, a non-zero exit is error or missing
|
||||||
|
* Add support for `initctl -q` to more commands: stop, start, restart,
|
||||||
|
reload, signal, etc.
|
||||||
|
|
||||||
|
[run-parts(8)]: https://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Fix nasty 32/64-bit alignment issue between finit and its plugins,
|
||||||
|
applicable to 32-bit targets with GLIBC 2.34 and later. External
|
||||||
|
plugins must make sure to use, at least: `-D_TIME_BITS=64`
|
||||||
|
* Fix #215: disable cgroup support at runtime if kernel lacks support
|
||||||
|
or does not have the required controllers (cpu)
|
||||||
|
* Fix #217: iwatcher initialization issue, by Ming Liu, Atlas Copco
|
||||||
|
* Fix #218: initctl matches too many services, by Ming Liu, Atlas Copco
|
||||||
|
* Fix #219: not all filesystems unmounted at shutdown, by Ming Liu,
|
||||||
|
Mathias Thore, and Robert Andersson, Atlas Copco
|
||||||
|
* Fix #226: initctl shows wrong PID for crashing services
|
||||||
|
* Fix #227: reboot stalls if process stopped with `[WARN]`
|
||||||
|
* Fix #233: initctl shows wrong status for run/task, by Sergio Morlans
|
||||||
|
and Ming Liu, Atlas Copco
|
||||||
|
* Fix #248: source `env:file` also in `pre:` and `post` scripts
|
||||||
|
* Fix #260: drop limit on device name in `Checking filesystem...` output
|
||||||
|
* Fix start/stop and monitoring (restart) of SysV init scripts and
|
||||||
|
forking services, see the updated documentation for details
|
||||||
|
* Fix call to `swapoff` at shutdown, does not support `-e` flag
|
||||||
|
* Fix suspend to RAM issue. Previously `reboot(RB_SW_SUSPEND)` was
|
||||||
|
used, now the modern `/sys/power/state` API is used instead.
|
||||||
|
* Fix nasty run/task/service matcher bug, triggered by stanzas using the
|
||||||
|
same basename of a command but different `:ID`. Caused Finit to match
|
||||||
|
with already registered but different run/task/service
|
||||||
|
|
||||||
|
|
||||||
|
[4.2][] - 2022-01-16
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
* Support for non-root users to use `initctl`, e.g. group wheel
|
||||||
|
* Support for new libite (-lite) header namespace
|
||||||
|
* RTC plugin now reset an invalid RTC time to the kernel default
|
||||||
|
time, 2000-01-01 00:00, prevents errors and is less crazy than
|
||||||
|
some systems coming with with <= Jan 1, 1970
|
||||||
|
* urandom plugin now use RNDADDENTROPY ioctl to seed kernel rng,
|
||||||
|
incrementing entropy count. Also, 32 kiB instead of 512 bytes are
|
||||||
|
now saved (and restored) on reboot. This should greatly improve
|
||||||
|
reliability of systems with none or poor HWRNG
|
||||||
|
* Kernel logging to console (loglevel >= 7, debug, when quiet mode is
|
||||||
|
not used) is now honored by Finit, regardless of the finit.debug
|
||||||
|
command line option
|
||||||
|
* Reduced default log level from `LOG_NOTICE` to `LOG_INFO`
|
||||||
|
* Wrapped all calls to mount(2) to add logging in case of failure
|
||||||
|
* New configure options to control fastboot (no fsck) and fsck fix
|
||||||
|
options, by Ming Liu, Atlas Copco
|
||||||
|
* Support for overriding default `/etc/nologin` file with an external
|
||||||
|
`#define`, by Ming Liu, Atlas Copco
|
||||||
|
* Support for overriding default `/var/run/dbus/pid` file with an
|
||||||
|
external `#define`, by Ming Liu, Atlas Copco
|
||||||
|
* Support for more service options to control respawn behavior of
|
||||||
|
crashing services, by Robert Andersson and Ming Liu, Atlas Copco
|
||||||
|
* Support for `initctl ident [NAME]` which lists all instances of
|
||||||
|
`NAME`, or all enabled system run/tasks and services
|
||||||
|
* Show number of total restarts and current respawn count for a
|
||||||
|
service in `initctl status foo`
|
||||||
|
* Crashing services no longer have the crash/restart counter reset as
|
||||||
|
soon as they have stabilized. Instead, a background timer will
|
||||||
|
slowly (every 300 sec) age (decrement) the counter. This will still
|
||||||
|
catch services that "rage quit", but also those that crash after a
|
||||||
|
longer period of activity
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Fix #180: user managed (`manual:yes`) services accidentally started
|
||||||
|
by `initctl reload`, regression introduced in Finit v4.0
|
||||||
|
* Fix #181: lots of typos all over the tree, by David Yang, Debian
|
||||||
|
* Fix #187: fix typos, incl. small cleanup, in doc/bootstrap.md
|
||||||
|
* Fix #188: support running on kernels that do not have cgroups v2.
|
||||||
|
When this is detect, all functions related to cgroups support in
|
||||||
|
Finit are disabled, *except* the .conf file parser. Hence, you
|
||||||
|
may get parse error if you have invalid cgroup configuration in
|
||||||
|
your Finit .conf files
|
||||||
|
* Fix #197: `initctl status foo` now shows a focused overview of all
|
||||||
|
matching instances; foo:1, foo:2 -- if only one instance matches the
|
||||||
|
command line argument, or if onle one instance exists, the detailed
|
||||||
|
view is shown, as before
|
||||||
|
* Fix #198: a few typos found by Tim Gates
|
||||||
|
* Fix #199: avoid using C++ reserved keywords
|
||||||
|
* Fix #201: memory leak in usr condition plugin, by Ming Liu, Atlas Copco
|
||||||
|
* Fix #203: ensure all filesystems listed in /proc/mounts are properly
|
||||||
|
unumounted on shutdown/reboot, by Robert Andersson, Atlas Copco
|
||||||
|
* Fix #210: resizing terminal (smaller) after boot causes empty lines
|
||||||
|
to be inserted between boot progress
|
||||||
|
* Fix #211: drop hard-coded 32 character limit in getty, now reads
|
||||||
|
`_SC_LOGIN_NAME_MAX` from `sysconf(3)`
|
||||||
|
* Fix #212: service PID file lost after inictl reload, visible from
|
||||||
|
the output from `initctl status foo`
|
||||||
|
|
||||||
|
|
||||||
|
[4.1][] - 2021-06-06
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
Bug fix release. Also disables handlers for `SIGINT` and `SIGPWR`, a
|
||||||
|
new set of `sys` conditions are instead generated which can be used to
|
||||||
|
trigger external programs.
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
* Change behavior on SIGUSR1 to be compatible with sysvinit and systemd.
|
||||||
|
Previously SIGUSR1 caused Finit to halt, like BusyBox init. This had
|
||||||
|
"interesting" side effects on Debian systems when coexisting with
|
||||||
|
sysvinit (upgrading/reinstalling causes scripts to `kill -USR1 1`)
|
||||||
|
* Change how `contrib/debian/install.sh` sets up a Grub boot entry for
|
||||||
|
finit. We now modify the $SUPPORTED_INITS variable in `10_linux`
|
||||||
|
* Disable default kernel ctrl-alt-delete handler and let Finit instead
|
||||||
|
catch `SIGINT` from kernel to be able to perform a proper reboot.
|
||||||
|
There is no default command for this, you need to set up a task that
|
||||||
|
triggers on `<sys/key/ctrlaltdel>` to issue `initctl reboot`
|
||||||
|
* Added keventd to provide `<sys/pwr/ac>` condition to Finit. keventd
|
||||||
|
is currently only responsible for monitoring `/sys/class/power_supply`
|
||||||
|
for changes to active AC mains power online status. Enable keventd
|
||||||
|
with `configure --with-keventd`
|
||||||
|
* For handling power fail events (from UPS and similar) a process may
|
||||||
|
send `SIGPWR` to PID 1. Finit no longer redirects this to `SIGUSR1`
|
||||||
|
(poweroff). There is no default command for this, you need to set up
|
||||||
|
a task that triggers on `<sys/pwr/fail>` to issue `initctl poweroff`
|
||||||
|
* Built-in Finit getty is now a standalone program
|
||||||
|
* Default termios for TTYs now enable `IUTF8` on input
|
||||||
|
* If `/bin/login` is not found, Finit now tries `sulogin` before it
|
||||||
|
falls back to an unauthenticated `/bin/sh`
|
||||||
|
* Dropped (broken) support for multiple consoles. Finit now follows
|
||||||
|
the default console selected by the kernel, `/dev/console`
|
||||||
|
* Dropped signal handlers for SIGSTOP/TSTP and SIGCONT
|
||||||
|
* Added support for `\n`, in addition to `\r`, in "Please press Enter"
|
||||||
|
prompt before starting getty
|
||||||
|
* Finit no longer parses `/proc/cmdline` for its options. Instead all
|
||||||
|
options are by default now read from `argv[]`, like a normal program,
|
||||||
|
this is also what the kernel does by default. Please note, this may
|
||||||
|
not work if your systems boots with an initramfs (ymmv), for such
|
||||||
|
cases, see `configure --enable-kernel-cmdline`
|
||||||
|
* The following plugins are now possible to disable (for containers):
|
||||||
|
`rtc.so`, `urandom.so`, you may also want to disable `hotplug.so`.
|
||||||
|
They are all enabled by default, as in Finit 4.0, but may be moved
|
||||||
|
to external tools or entries in `finit.conf` in Finit 5.0
|
||||||
|
* Added support for reading `PRETTY_NAME` from `/etc/os-release` to use
|
||||||
|
as heading in progress output, unless `--with-heading=GREET` is used.
|
||||||
|
* Added manual pages for finit(8), initctl(8), and finit.conf(5)
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Stricter interface name validation in netlink plugin, modeled after
|
||||||
|
the kernel. Suggested by Coverity Scan
|
||||||
|
* Fix problem of re-registering a service as a task. Previously, if a
|
||||||
|
fundamental change, like type, was made to an active service/run/task
|
||||||
|
it did not take. Only possible workaround was to remove from config
|
||||||
|
* initctl: drop warning when removing a non-existing usr condition
|
||||||
|
* initctl: drop confusing `errno 0` when timing out waiting for reply
|
||||||
|
* Ensure services in plugins and from Finit main belong to a cgroup
|
||||||
|
* Ensure init top-level cgroup remains a leaf group
|
||||||
|
* Fix tty parse error for detecting use of external getty
|
||||||
|
* Fix default `name:` and `:ID` for tty's, e.g. `ttyS0` now gives
|
||||||
|
`tty:S0` as expected. This was default for built-in getty already
|
||||||
|
* Fix max username (32 chars) in bundled Finit getty
|
||||||
|
* The `contrib/*/install.sh` scripts failed to run from tarball
|
||||||
|
* Finit no longer forcibly mounts; `/dev`, `/proc`, or `/sys`, instead
|
||||||
|
it checks first if they are already mounted (devtmpfs or container)
|
||||||
|
* Fix `/etc/fstab` parser to properly check for 'ro' to not remount the
|
||||||
|
root filesystem at boot. The wrong field was read, so a root mounted
|
||||||
|
by an initramfs, or by lxc for a container, had their root remounted
|
||||||
|
* Fix SIGCHLD handler, `waitpd()` may be interrupted by a signal
|
||||||
|
* Reset `starting` flag of services being stopped. When a service
|
||||||
|
is started and then stopped before it has created its pid file,
|
||||||
|
it could be left forever in the stopping state, unless we reset
|
||||||
|
the starting flag.
|
||||||
|
* Fix #170: detect loss of default route when interfaces go down. This
|
||||||
|
emulates the missing kernel netlink message to remove the condition
|
||||||
|
net/default/route to allow stopping dependent services
|
||||||
|
* Fix #171: restore automatic mount of `/dev/shm`, `/dev/pts`, `/run`
|
||||||
|
and `/tmp`, unless mounted already by `/etc/fstab`. This is what most
|
||||||
|
desktop systems expect PID 1 to do. Here we also make sure to mount
|
||||||
|
`/run/lock` as a tmpfs as well, with write perms for regular users,
|
||||||
|
this prevents regular users from filling up `/run` and causing DoS.
|
||||||
|
* Fix #173: netlink plugin runs out of socket buffer space;
|
||||||
|
|
||||||
|
finit[1]: nl_callback():recv(): No buffer space available
|
||||||
|
|
||||||
|
Fixed by adding support for resync with kernel on `ENOBUFS`. See
|
||||||
|
netlink(7) for details. As a spin-off the plugin now supports any
|
||||||
|
number of interfaces and routes on a system. On resync, the following
|
||||||
|
message is now logged, as a warning:
|
||||||
|
|
||||||
|
finit[1]: nl_callback():busy system, resynchronizing with kernel.
|
||||||
|
|
||||||
|
* Fix #174: loss of log messages using combo of prio and facility, e.g.,
|
||||||
|
`logit(LOG_CONSOLE | LOG_NOTICE, ...)`, by Jacques de Laval, Westermo
|
||||||
|
* Fix #175: ensure Finit does not acquire a controlling TTY when checking
|
||||||
|
if a device is a TTY before starting a getty. This fixes an old bug
|
||||||
|
where Ctrl-C after logout from a shell could cause PID 1 to get SIGINT,
|
||||||
|
which in turn could lead to a system reboot
|
||||||
|
|
||||||
|
|
||||||
|
[4.0][] - 2021-04-26
|
||||||
|
--------------------
|
||||||
|
|
||||||
This release became v4.0, and not v3.2, because of incompatible changes
|
This release became v4.0, and not v3.2, because of incompatible changes
|
||||||
to service conditions. There are other significant changes as well, so
|
to service conditions. There are other significant changes as well, so
|
||||||
make sure to read the whole changelog when upgrading.
|
make sure to read the whole change log when upgrading.
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
* The stand-alone `reboot` tool has been replaced with a symlink to
|
* The stand-alone `reboot` tool has been replaced with a symlink to
|
||||||
@@ -24,28 +659,47 @@ make sure to read the whole changelog when upgrading.
|
|||||||
* Removed built-in inetd super server. If you need this functionality,
|
* Removed built-in inetd super server. If you need this functionality,
|
||||||
use an external inetd, like xinetd, instead. A pull request for a
|
use an external inetd, like xinetd, instead. A pull request for a
|
||||||
stand-alone inetd, like watchdogd and getty, is most welcome!
|
stand-alone inetd, like watchdogd and getty, is most welcome!
|
||||||
* Incompatible `configure` script changes, i.e., you must give proper
|
* Incompatible `configure` script changes, i.e., no guessing `--prefix`
|
||||||
path arguments to the script, no more guessing just GNU defaults.
|
and other paths. Also, many options have been changed, renamed, or
|
||||||
There are examples in the documentation and the `contrib/` section
|
flipped defaults, or even dropped altogether. There are examples in
|
||||||
* Change service conditions from the non-obvious `<svc/path/to/foo>` to
|
the documentation and the `contrib/` section
|
||||||
`<pid/foo:id>`. This to hopefully make it clear that one service's
|
* Service conditions change from the non-obvious `<svc/path/to/foo>` to
|
||||||
'pid:!foo' pidfile is another service's `<pid/foo>` condition
|
`<pid/foo:id>`. Not only does this give simpler internal semantics,
|
||||||
* Initial support for cgroups, every service now runs in its own cgroup
|
it hopefully also makes it clear that one service's `pid:!foo` pidfile
|
||||||
https://twitter.com/b0rk/status/1214341831049252870?s=20
|
is another service's `<pid/foo>` condition, issue #143
|
||||||
|
* Initial support for cgroups v2:
|
||||||
|
- services runs in a cgroup named after their respective *.conf file
|
||||||
|
- top-level groups are; init, user, and system
|
||||||
|
- all top-level groups can be configured from finit *.conf files
|
||||||
|
- each service can tweak the cgroup settings
|
||||||
|
- Use `initctl [top|ps|cgroup]` commands to inspect runtime state
|
||||||
|
- https://twitter.com/b0rk/status/1214341831049252870?s=20
|
||||||
* Major refactor of Finit's `main()` function to be able to start the
|
* Major refactor of Finit's `main()` function to be able to start the
|
||||||
event loop earlier. This also facilitated factoring out functionality
|
event loop earlier. This also facilitated factoring out functionality
|
||||||
previously hard-coded in Finit, e.g., starting the bundled watchdogd,
|
previously hard-coded in Finit, e.g., starting the bundled watchdogd,
|
||||||
various distro packed udevd and other hotplugging tools
|
various distro packed udevd and other hotplugging tools
|
||||||
|
* A proper rescue mode has been added. It is started extremely early
|
||||||
|
and is protected with a bundled `suslogin`. Exiting rescue mode now
|
||||||
|
brings up the system as a normal boot, as one expects
|
||||||
* Support for `sysv` start/stop scripts as well as monitoring forking
|
* Support for `sysv` start/stop scripts as well as monitoring forking
|
||||||
services, stared using `sysv` or `service` stanza
|
services, stared using `sysv` or `service` stanza
|
||||||
* Support for custom `kill:DELAY`, default 3 sec.
|
* Support for custom `kill:DELAY`, default 3 sec.
|
||||||
* Support for custom `halt:SIGNAL`, default SIGTERM
|
* Support for custom `halt:SIGNAL`, default SIGTERM
|
||||||
|
* Support for `pre:script` and `post:script`, allows for setup and
|
||||||
|
teardown/cleanup before and after a service runs, issue #129
|
||||||
|
* Support for `env:file` in `/etc/default/foo` or `/etc/conf.d/foo`, see
|
||||||
|
the contrib section for examples that utilize this feature. Variables
|
||||||
|
expanded from env files, and the env files themselves, are tracked for
|
||||||
|
changes to see if a service .conf file is "dirty" and needs restart on
|
||||||
|
`initctl reload`
|
||||||
* Support for tracking custom PID files, using `pid:!/path/to/foo.pid`,
|
* Support for tracking custom PID files, using `pid:!/path/to/foo.pid`,
|
||||||
useful with new `sysv` or `service` which fork to background
|
useful with new `sysv` or `service` which fork to background
|
||||||
* Support starting run/task/services without absolute path, trust `$PATH`
|
* Support starting run/task/services without absolute path, trust `$PATH`
|
||||||
* Add support for `--disable-doc` and `--disable-contrib` to speed up
|
* Add support for `--disable-doc` and `--disable-contrib` to speed up
|
||||||
builds and work around issue with massively parallel builds
|
builds and work around issue with massively parallel builds
|
||||||
* Add support for `@console` also for external getty
|
* Support for `@console` also for external getty
|
||||||
|
* Support for `notty` option to built-in getty, for board bring-up
|
||||||
|
* Support for `rescue` option to built-in getty, for rescue shells
|
||||||
* Add `-b`, batch mode, for non-interactive use to `initctl`
|
* Add `-b`, batch mode, for non-interactive use to `initctl`
|
||||||
* Prefer udev to handle `/dev/` if mdev is also available
|
* Prefer udev to handle `/dev/` if mdev is also available
|
||||||
* Redirect dbus daemon output to syslog
|
* Redirect dbus daemon output to syslog
|
||||||
@@ -65,7 +719,7 @@ make sure to read the whole changelog when upgrading.
|
|||||||
- As long as a stepped service changes state we queue another step all
|
- As long as a stepped service changes state we queue another step all
|
||||||
event, because services may depend on each other
|
event, because services may depend on each other
|
||||||
* Require new libuEv API: `uev_init1()` to reduce event cache so that
|
* Require new libuEv API: `uev_init1()` to reduce event cache so that
|
||||||
the kernel can invalidate deleted events before enqueing to userspace
|
the kernel can invalidate deleted events before enqueuing to userspace
|
||||||
* Rename `hwclock.so` plugin to `rtc.so` since it now is stand-alone
|
* Rename `hwclock.so` plugin to `rtc.so` since it now is stand-alone
|
||||||
from the `hwclock` tool. Note: the kernel can also be set to load
|
from the `hwclock` tool. Note: the kernel can also be set to load
|
||||||
and store RTC to/from system clock at boot/halt as well, issue #110
|
and store RTC to/from system clock at boot/halt as well, issue #110
|
||||||
@@ -95,6 +749,8 @@ make sure to read the whole changelog when upgrading.
|
|||||||
* Always append `:ID` qualifier to conditions if set for a service
|
* Always append `:ID` qualifier to conditions if set for a service
|
||||||
* The IPC socket has moved from `/run/finit.sock` to `/run/finit/socket`
|
* The IPC socket has moved from `/run/finit.sock` to `/run/finit/socket`
|
||||||
officially only supported for use by the `initctl` tool
|
officially only supported for use by the `initctl` tool
|
||||||
|
* The IPC socket now uses `SOCK_SEQPACKET` instead of `SOCK_STREAM`.
|
||||||
|
Recommend using watchdogd v3.4, or later, which support this
|
||||||
* Improved support for modern `/etc/network/interfaces`, which has
|
* Improved support for modern `/etc/network/interfaces`, which has
|
||||||
include statements. No more native `ifup` of individual interfaces,
|
include statements. No more native `ifup` of individual interfaces,
|
||||||
Finit now calls `ifup -a`, or `ifdown -a`, delegating all details to
|
Finit now calls `ifup -a`, or `ifdown -a`, delegating all details to
|
||||||
@@ -112,16 +768,21 @@ make sure to read the whole changelog when upgrading.
|
|||||||
that do not have a watchdog
|
that do not have a watchdog
|
||||||
* Fix #100: Early condition handling may not work if `/var/run` does
|
* Fix #100: Early condition handling may not work if `/var/run` does
|
||||||
not yet exist (symlink to `/run`). Added compat layer for access
|
not yet exist (symlink to `/run`). Added compat layer for access
|
||||||
|
* Fix #101: Built-in inetd removed
|
||||||
|
* Fix #102: Start built-in watchdogd as a regular service
|
||||||
* Fix #103: Register multiple getty if `@console` resolves to >1 TTY,
|
* Fix #103: Register multiple getty if `@console` resolves to >1 TTY,
|
||||||
* Fix #105: Only remove /etc/nologin when moving from runlevel 0, 1, 6
|
* Fix #105: Only remove /etc/nologin when moving from runlevel 0, 1, 6
|
||||||
Fixed by Jonas Johansson, Westermo
|
Fixed by Jonas Johansson, Westermo
|
||||||
* Fix #109: Support for PID files in sub-directories to `/var/run`
|
* Fix #109: Support for PID files in sub-directories to `/var/run`
|
||||||
* Handle rename of PID files, by Robert Andersson, Atlas Copco
|
* Handle rename of PID files, by Robert Andersson, Atlas Copco
|
||||||
|
* Fix #110: automatic modprobe of RTC devices, built-in hwclock
|
||||||
* Fix #120: Redirect `stdin` to `/dev/null` for services by default
|
* Fix #120: Redirect `stdin` to `/dev/null` for services by default
|
||||||
* Fix #122: Switch to `nanosleep()` to achieve "signal safe" sleep,
|
* Fix #122: Switch to `nanosleep()` to achieve "signal safe" sleep,
|
||||||
fixed by Jacques de Laval, Westermo
|
fixed by Jacques de Laval, Westermo
|
||||||
* Fix #124: Lingering processes in process group when session leader
|
* Fix #124: Lingering processes in process group when session leader
|
||||||
exits. E.g., lingering `logit` processes when parent dies
|
exits. E.g., lingering `logit` processes when parent dies
|
||||||
|
* Fix #127: Show all runparts scripts as they start, like rc.local, fixed
|
||||||
|
by Jacques de Laval, Westermo
|
||||||
* Fix service name matching, e.g. for condition handling, may match with
|
* Fix service name matching, e.g. for condition handling, may match with
|
||||||
wrong service, by Jonas Holmberg, Westermo
|
wrong service, by Jonas Holmberg, Westermo
|
||||||
* Run all run-parts scripts using `/bin/sh -c foo` just like the standard
|
* Run all run-parts scripts using `/bin/sh -c foo` just like the standard
|
||||||
@@ -140,6 +801,8 @@ make sure to read the whole changelog when upgrading.
|
|||||||
* Provide service description for built-in watchdog daemon
|
* Provide service description for built-in watchdog daemon
|
||||||
* Fix #138: Handle `SIGPWR` like `SIGSUR2`, i.e., power off the system
|
* Fix #138: Handle `SIGPWR` like `SIGSUR2`, i.e., power off the system
|
||||||
* Drop the '%m' GNUism, for compat with older musl libc
|
* Drop the '%m' GNUism, for compat with older musl libc
|
||||||
|
* Fix #139: call `tzset()` on `initctl reload` to activate system
|
||||||
|
timezone changes (for logging)
|
||||||
|
|
||||||
|
|
||||||
[3.1][] - 2018-01-23
|
[3.1][] - 2018-01-23
|
||||||
@@ -378,7 +1041,7 @@ Bug fix release.
|
|||||||
|
|
||||||
* Add support for status/show service by `name:id`
|
* Add support for status/show service by `name:id`
|
||||||
* Enforce terse mode after boot, if verbose mode is disabled
|
* Enforce terse mode after boot, if verbose mode is disabled
|
||||||
* Reenable verbose mode at reboot, if disabled at boot
|
* Re-enable verbose mode at reboot, if disabled at boot
|
||||||
* Update section mentioning BusyBox getty
|
* Update section mentioning BusyBox getty
|
||||||
* Update debugging documentation
|
* Update debugging documentation
|
||||||
* Allow debug to override terse mode
|
* Allow debug to override terse mode
|
||||||
@@ -433,7 +1096,7 @@ handling and reconfiguration at runtime.
|
|||||||
* Clarify how to select different plugins with the configure script
|
* Clarify how to select different plugins with the configure script
|
||||||
* Improve urandom plugin for embedded systems w/o random seed
|
* Improve urandom plugin for embedded systems w/o random seed
|
||||||
* Add `--debug` flag to `initctl`
|
* Add `--debug` flag to `initctl`
|
||||||
* The runlevels listed for services in `initctl show` now hightlight the
|
* The runlevels listed for services in `initctl show` now highlight the
|
||||||
active runlevel.
|
active runlevel.
|
||||||
* Clarify in the README and in `initctl help` that the GW event to
|
* Clarify in the README and in `initctl help` that the GW event to
|
||||||
listen for in service declarations is `GW:UP`
|
listen for in service declarations is `GW:UP`
|
||||||
@@ -465,7 +1128,7 @@ handling and reconfiguration at runtime.
|
|||||||
* Do not use `-Os` use `-O2` as default optimization level. Many cross
|
* Do not use `-Os` use `-O2` as default optimization level. Many cross
|
||||||
compiler toolchains are known to have problems with `-Os`
|
compiler toolchains are known to have problems with `-Os`
|
||||||
* Do not allow build VERSION to be overloaded by an environment variable
|
* Do not allow build VERSION to be overloaded by an environment variable
|
||||||
* Fix too small MAX arguments and too few argments in `svc_t` for
|
* Fix too small MAX arguments and too few arguments in `svc_t` for
|
||||||
reading currently running services with `initctl show`
|
reading currently running services with `initctl show`
|
||||||
* Unblock blocked signals after forking off a child
|
* Unblock blocked signals after forking off a child
|
||||||
|
|
||||||
@@ -565,7 +1228,7 @@ The inetd release.
|
|||||||
### Changes
|
### Changes
|
||||||
* Add support for built-in inetd super server -- launch services on
|
* Add support for built-in inetd super server -- launch services on
|
||||||
demand. Supports filtering per interface and custom Inet ports.
|
demand. Supports filtering per interface and custom Inet ports.
|
||||||
* Upgrade to [libuEv] v1.1.0 to better handle error conditions.
|
* Upgrade to [libuEv][] v1.1.0 to better handle error conditions.
|
||||||
* Allow mixed case config directives in `finit.conf`
|
* Allow mixed case config directives in `finit.conf`
|
||||||
* Add support for RFC 868 (rdate) time plugin, start as inetd service.
|
* Add support for RFC 868 (rdate) time plugin, start as inetd service.
|
||||||
* Load plugins before parsing `finit.conf`, this makes it possible to
|
* Load plugins before parsing `finit.conf`, this makes it possible to
|
||||||
@@ -583,7 +1246,7 @@ The inetd release.
|
|||||||
turned out to not work so well after all. For instance, launching
|
turned out to not work so well after all. For instance, launching
|
||||||
TTYs in a background process completely blocked inetd services from
|
TTYs in a background process completely blocked inetd services from
|
||||||
even starting up listening sockets ... proper fork seems to work fine
|
even starting up listening sockets ... proper fork seems to work fine
|
||||||
though. This is the casue for *yanking* the [1.11] release, below.
|
though. This is the cause for *yanking* the [1.11] release, below.
|
||||||
* Trap segfaults caused by external plugins/callbacks in a sub-process.
|
* Trap segfaults caused by external plugins/callbacks in a sub-process.
|
||||||
This prevents a single programming mistake in by a 3rd party developer
|
This prevents a single programming mistake in by a 3rd party developer
|
||||||
from taking down the entire system.
|
from taking down the entire system.
|
||||||
@@ -596,7 +1259,7 @@ The inetd release.
|
|||||||
[1.11][] - 2015-01-24 [YANKED]
|
[1.11][] - 2015-01-24 [YANKED]
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
The [libuEv] release.
|
The [libuEv][] release.
|
||||||
|
|
||||||
**Note:** This release has been *yanked* from distribution due to a
|
**Note:** This release has been *yanked* from distribution due to a
|
||||||
regression in launching background processes and TTY's. Fixed in
|
regression in launching background processes and TTY's. Fixed in
|
||||||
@@ -679,7 +1342,7 @@ Major bug fix release.
|
|||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
* Show `__FILE__` in `_d()` debug messages, useful for plugins with
|
* Show `__FILE__` in `_d()` debug messages, useful for plugins with
|
||||||
similarily named callbacks. Also, only in debug mode anyway
|
similarly named callbacks. Also, only in debug mode anyway
|
||||||
* Make sure to cleanup recorded PID when a service is lost. Required by
|
* Make sure to cleanup recorded PID when a service is lost. Required by
|
||||||
service plugins for their callbacks to work.
|
service plugins for their callbacks to work.
|
||||||
* Only clear screen when in verbose mode. Maybe this should be removed
|
* Only clear screen when in verbose mode. Maybe this should be removed
|
||||||
@@ -748,14 +1411,14 @@ Major bug fix release.
|
|||||||
* Makefile fixes for installation, paths encoded wrong
|
* Makefile fixes for installation, paths encoded wrong
|
||||||
* Strip binaries + .so files, support for `$(CROSS)` toolchain strip
|
* Strip binaries + .so files, support for `$(CROSS)` toolchain strip
|
||||||
* Default install is now to `/sbin/finit` and `/usr/`
|
* Default install is now to `/sbin/finit` and `/usr/`
|
||||||
* Note change in `$PLUGIN_DIR` environemnt variable to `$plugindir`
|
* Note change in `$PLUGIN_DIR` environment variable to `$plugindir`
|
||||||
|
|
||||||
|
|
||||||
[1.2][] - 2012-09-27
|
[1.2][] - 2012-09-27
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
* Update README with section on building and enviroment variables
|
* Update README with section on building and environment variables
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
* Fix installation paths encoded in finit binary
|
* Fix installation paths encoded in finit binary
|
||||||
@@ -847,7 +1510,11 @@ Major bug fix release.
|
|||||||
|
|
||||||
* Initial release
|
* Initial release
|
||||||
|
|
||||||
[UNRELEASED]: https://github.com/troglobit/finit/compare/3.1...HEAD
|
[UNRELEASED]: https://github.com/troglobit/finit/compare/4.3...HEAD
|
||||||
|
[4.4]: https://github.com/troglobit/finit/compare/4.3...4.4
|
||||||
|
[4.3]: https://github.com/troglobit/finit/compare/4.2...4.3
|
||||||
|
[4.2]: https://github.com/troglobit/finit/compare/4.1...4.2
|
||||||
|
[4.1]: https://github.com/troglobit/finit/compare/4.0...4.1
|
||||||
[4.0]: https://github.com/troglobit/finit/compare/3.1...4.0
|
[4.0]: https://github.com/troglobit/finit/compare/3.1...4.0
|
||||||
[3.1]: https://github.com/troglobit/finit/compare/3.0...3.1
|
[3.1]: https://github.com/troglobit/finit/compare/3.0...3.1
|
||||||
[3.0]: https://github.com/troglobit/finit/compare/2.4...3.0
|
[3.0]: https://github.com/troglobit/finit/compare/2.4...3.0
|
||||||
@@ -879,9 +1546,3 @@ Major bug fix release.
|
|||||||
[0.2]: https://github.com/troglobit/finit/compare/0.1...0.2
|
[0.2]: https://github.com/troglobit/finit/compare/0.1...0.2
|
||||||
[libuEv]: https://github.com/troglobit/libuev
|
[libuEv]: https://github.com/troglobit/libuev
|
||||||
[dea3ae8]: https://github.com/troglobit/finit/commit/dea3ae8
|
[dea3ae8]: https://github.com/troglobit/finit/commit/dea3ae8
|
||||||
|
|
||||||
<!--
|
|
||||||
-- Local Variables:
|
|
||||||
-- mode: markdown
|
|
||||||
-- End:
|
|
||||||
-->
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||||
Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
|
Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
+5
-1
@@ -1,5 +1,5 @@
|
|||||||
ACLOCAL_AMFLAGS = -I m4
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
SUBDIRS = plugins src test
|
SUBDIRS = man plugins src system test tmpfiles.d
|
||||||
doc_DATA = README.md LICENSE contrib/finit.conf
|
doc_DATA = README.md LICENSE contrib/finit.conf
|
||||||
EXTRA_DIST = README.md LICENSE ChangeLog.md contrib/finit.conf
|
EXTRA_DIST = README.md LICENSE ChangeLog.md contrib/finit.conf
|
||||||
|
|
||||||
@@ -29,3 +29,7 @@ release: distcheck
|
|||||||
printf "$$file.md5\t"; cat ../$$file.md5 | cut -f1 -d' '; \
|
printf "$$file.md5\t"; cat ../$$file.md5 | cut -f1 -d' '; \
|
||||||
printf "$$file.sha256\t"; cat ../$$file.sha256 | cut -f1 -d' '; \
|
printf "$$file.sha256\t"; cat ../$$file.sha256 | cut -f1 -d' '; \
|
||||||
done
|
done
|
||||||
|
|
||||||
|
DISTCHECK_CONFIGURE_FLAGS = --prefix=/usr --sysconfdir=/etc --localstatedir=/var \
|
||||||
|
--enable-testserv-plugin --enable-x11-common-plugin \
|
||||||
|
--with-watchdog --with-keventd --with-fstab=/etc/fstab
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
[![License Badge][]][License] [![Travis Status]][Travis] [![Coverity Status]][Coverity Scan]
|
[![License Badge][]][License] [![GitHub Status][]][GitHub] [![Coverity Status][]][Coverity Scan]
|
||||||
<img align="right" src="img/finit3.png" alt="Finit: Fast Init">
|
<img align="right" src="img/finit3.png" alt="Finit: Fast Init">
|
||||||
|
|
||||||
* [Introduction](#introduction)
|
* [Introduction](#introduction)
|
||||||
@@ -22,20 +22,51 @@
|
|||||||
Introduction
|
Introduction
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Finit is a simple alternative to [SysV init][4] and [systemd][6]. It
|
Fast init for Linux systems. Reverse engineered from the [EeePC
|
||||||
was reverse engineered from the [EeePC fastinit][] over ten years ago
|
fastinit][] over ten years ago by [Claudio Matsuoka][] — "gaps filled
|
||||||
by [Claudio Matsuoka][] — "gaps filled with frog DNA …"
|
with frog DNA …"
|
||||||
|
|
||||||

|

|
||||||
*Figure 1: Screenshot showing Finit booting [Alpine Linux](https://www.alpinelinux.org/).*
|
*Figure 1: Screenshot showing Finit booting [Alpine Linux](https://www.alpinelinux.org/).*
|
||||||
|
|
||||||
|
Features include:
|
||||||
|
|
||||||
|
* Runlevels, defined per service
|
||||||
|
* One-shot tasks, services (daemons), or [SysV init][4] start/stop scripts
|
||||||
|
* Runparts and `/etc/rc.local` support
|
||||||
|
* Process supervision similar to [systemd][]
|
||||||
|
* Sourcing environment files
|
||||||
|
* Conditions for network/process/custom dependencies
|
||||||
|
* Readiness notification; PID files (native) for synchronizing system
|
||||||
|
startup, support for systemd [sd_notify()][], or [s6 style][] too
|
||||||
|
* Limited support for [tmpfiles.d(5)][] (no aging, attributes, or subvolumes)
|
||||||
|
* Pre/Post script actions
|
||||||
|
* Rudimentary [templating support](doc/config.md#templating)
|
||||||
|
* Tooling to enable/disable services
|
||||||
|
* Built-in getty
|
||||||
|
* Built-in watchdog, with support for hand-over to [watchdogd](https://troglobit.com/watchdogd.html)
|
||||||
|
* Built-in support for Debian/BusyBox `/etc/network/interfaces`
|
||||||
|
* Cgroups v2, both configuration and monitoring in `initctl top`
|
||||||
|
* Plugin support for customization
|
||||||
|
* Proper rescue mode with bundled `sulogin` for protected maintenance shell
|
||||||
|
* Integration with [watchdogd][] for full system supervision
|
||||||
|
* Logging to kernel ring buffer before `syslogd` has started, see the
|
||||||
|
recommended [sysklogd][] project for complete logging integration
|
||||||
|
and how to log to the kernel ring buffer from scripts using `logger`
|
||||||
|
|
||||||
Focus is on small and embedded systems, although Finit is fully usable
|
Focus is on small and embedded systems, although Finit is fully usable
|
||||||
on server and desktop systems as well. For working examples, see the
|
on server and desktop systems as well. For working examples, see the
|
||||||
[contrib/](contrib/) section with tutorials for:
|
[contrib/](contrib/) section with tutorials for the following Linux
|
||||||
|
distributions:
|
||||||
|
|
||||||
* [Void Linux](contrib/void/),
|
* [Void Linux](contrib/void/),
|
||||||
* [Alpine Linux](contrib/alpine/), and
|
* [Alpine Linux](contrib/alpine/), and
|
||||||
* [Debian GNU/Linux](contrib/debian/)
|
* [Debian GNU/Linux](contrib/debian/), also works on Ubuntu/Linux Mint
|
||||||
|
|
||||||
|
> **Note:** support for various Linux distributions does not mean Finit
|
||||||
|
> installs easily on all architectures. The bundled install scripts are
|
||||||
|
> examples for standard installations, tested on amd64 (x86_64) systems.
|
||||||
|
> Custom setups, for embedded systems, can be found in [myLinux][].
|
||||||
|
|
||||||
|
|
||||||
Example
|
Example
|
||||||
@@ -44,24 +75,35 @@ Example
|
|||||||
This example `/etc/finit.conf` can also be split up in multiple `.conf`
|
This example `/etc/finit.conf` can also be split up in multiple `.conf`
|
||||||
files in `/etc/finit.d`. Available, but not yet enabled, services can
|
files in `/etc/finit.d`. Available, but not yet enabled, services can
|
||||||
be placed in `/etc/finit.d/available` and enabled by an operator using
|
be placed in `/etc/finit.d/available` and enabled by an operator using
|
||||||
the [initctl](#commands--status) tool.
|
the [initctl](#commands--status) tool. See the above mentioned Linux
|
||||||
|
distributions, or [myLinux][].
|
||||||
|
|
||||||
|
> **Note:** as of Finit v4.4, .conf lines can be broken up using the
|
||||||
|
> standard UNIX continuation character (`\`), also trailing comments are
|
||||||
|
> now supported. The latter means you need to escape any hashes used in
|
||||||
|
> directives and descriptions (`\#`). For more on this and examples,
|
||||||
|
> see the [finit.conf(5)][] manual or [doc/config.md](doc/config.md).
|
||||||
|
|
||||||
```ApacheConf
|
```ApacheConf
|
||||||
# Fallback if /etc/hostname is missing
|
# Fallback if /etc/hostname is missing
|
||||||
host default
|
host default
|
||||||
|
|
||||||
# Runlevel to start after bootstrap, 'S', default: 2
|
# Runlevel to start after bootstrap, 'S', default: 2
|
||||||
runlevel 2
|
#runlevel 2
|
||||||
|
|
||||||
|
# Support for setting global environment variables, using foo=bar syntax
|
||||||
|
# be careful though with variables like PATH, SHELL, LOGNAME, etc.
|
||||||
|
#PATH=/usr/bin:/bin:/usr/sbin:/sbin
|
||||||
|
|
||||||
# Max file size for each log file: 100 kiB, rotate max 4 copies:
|
# Max file size for each log file: 100 kiB, rotate max 4 copies:
|
||||||
# log => log.1 => log.2.gz => log.3.gz => log.4.gz
|
# log => log.1 => log.2.gz => log.3.gz => log.4.gz
|
||||||
log size=100k count=4
|
log size=100k count=4
|
||||||
|
|
||||||
# Services to be monitored and respawned as needed
|
# Services to be monitored and respawned as needed
|
||||||
service [S12345] watchdogd -L -f -- System watchdog daemon
|
service [S12345] env:-/etc/conf.d/watchdog watchdog $WATCHDOG_OPTS $WATCHDOG_DEV -- System watchdog daemon
|
||||||
service [S12345] syslogd -n -b 3 -D -- System log daemon
|
service [S12345] env:-/etc/conf.d/syslog syslogd -n $SYSLOGD_OPTS -- System log daemon
|
||||||
service [S12345] <pid/syslogd> klogd -n -- Kernel log daemon
|
service [S12345] <pid/syslogd> env:-/etc/conf.d/klogd klogd -n $KLOGD_OPTS -- Kernel log daemon
|
||||||
service [2345] lldpd -d -c -M1 -H0 -i -- LLDP daemon (IEEE 802.1ab)
|
service [2345] env:-/etc/conf.d/lldpd lldpd -d $LLDPD_OPTS -- LLDP daemon (IEEE 802.1ab)
|
||||||
|
|
||||||
# The BusyBox ntpd does not use syslog when running in the foreground
|
# The BusyBox ntpd does not use syslog when running in the foreground
|
||||||
# So we use this trick to redirect stdout/stderr to a log file. The
|
# So we use this trick to redirect stdout/stderr to a log file. The
|
||||||
@@ -76,24 +118,29 @@ service :80 [2345] merecat -n -p 80 /var/www -- Web server
|
|||||||
service :8080 [2345] merecat -n -p 8080 /var/www -- Old web server
|
service :8080 [2345] merecat -n -p 8080 /var/www -- Old web server
|
||||||
|
|
||||||
# Alternative method instead of below runparts, can also use /etc/rc.local
|
# Alternative method instead of below runparts, can also use /etc/rc.local
|
||||||
#task [S] /etc/init.d/keyboard-setup start -- Setting up preliminary keymap
|
#sysv [S] /etc/init.d/keyboard-setup -- Setting up preliminary keymap
|
||||||
#task [S] /etc/init.d/acpid start -- Starting ACPI Daemon
|
#sysv [S] /etc/init.d/acpid -- Starting ACPI Daemon
|
||||||
#task [S] /etc/init.d/kbd start -- Preparing console
|
#task [S] /etc/init.d/kbd -- Preparing console
|
||||||
|
|
||||||
|
# Hidden from boot progress, using empty `--` description
|
||||||
|
#sysv [S] /etc/init.d/keyboard-setup --
|
||||||
|
#sysv [S] /etc/init.d/acpid --
|
||||||
|
#task [S] /etc/init.d/kbd --
|
||||||
|
|
||||||
# Run start scripts from this directory
|
# Run start scripts from this directory
|
||||||
# runparts /etc/start.d
|
# runparts /etc/start.d
|
||||||
|
|
||||||
# Virtual consoles run BusyBox getty, keep kernel default speed
|
# Virtual consoles run BusyBox getty, keep kernel default speed
|
||||||
tty [12345] /sbin/getty -L 0 /dev/tty1 linux
|
tty [12345] /sbin/getty -L 0 /dev/tty1 linux nowait noclear
|
||||||
tty [12345] /sbin/getty -L 0 /dev/tty2 linux
|
tty [2345] /sbin/getty -L 0 /dev/tty2 linux nowait noclear
|
||||||
tty [12345] /sbin/getty -L 0 /dev/tty3 linux
|
tty [2345] /sbin/getty -L 0 /dev/tty3 linux nowait noclear
|
||||||
|
|
||||||
# Use built-in getty for serial port and USB serial
|
# Use built-in getty for serial port and USB serial
|
||||||
tty [12345] /dev/ttyAMA0 noclear nowait
|
#tty [12345] /dev/ttyAMA0 noclear nowait
|
||||||
tty [12345] /dev/ttyUSB0 noclear
|
#tty [12345] /dev/ttyUSB0 noclear
|
||||||
|
|
||||||
# Just give me a shell, I need to debug this embedded system!
|
# Just give me a shell, I need to debug this embedded system!
|
||||||
tty [12345] @console noclear nologin
|
#tty [12345] console noclear nologin
|
||||||
```
|
```
|
||||||
|
|
||||||
The `service` stanza, as well as `task`, `run` and others are described
|
The `service` stanza, as well as `task`, `run` and others are described
|
||||||
@@ -102,10 +149,10 @@ some of the most common components needed to start a UNIX daemon:
|
|||||||
|
|
||||||
```
|
```
|
||||||
service [LVLS] <COND> log env:[-]/etc/default/daemon daemon ARGS -- Daemon daemon
|
service [LVLS] <COND> log env:[-]/etc/default/daemon daemon ARGS -- Daemon daemon
|
||||||
^ ^ ^ ^ ^ ^ ^ ^
|
^ ^ ^ ^ ^ ^ ^ ^
|
||||||
| | | | | | | `-- Optional description
|
| | | | | | | `---------- Optional description
|
||||||
| | | | | | `----------- Daemon arguments
|
| | | | | | `------------------ Daemon arguments
|
||||||
| | | | | `-------------------------- Path to daemon
|
| | | | | `------------------------- Path to daemon
|
||||||
| | | | `---------------------------------------------------- Optional env. file
|
| | | | `---------------------------------------------------- Optional env. file
|
||||||
| | | `-------------------------------------------------------- Redirect output to log
|
| | | `-------------------------------------------------------- Redirect output to log
|
||||||
| | `--------------------------------------------------------------- Optional conditions
|
| | `--------------------------------------------------------------- Optional conditions
|
||||||
@@ -117,13 +164,13 @@ Some components are optional: runlevel(s), condition(s) and description,
|
|||||||
making it easy to create simple start scripts and still possible for more
|
making it easy to create simple start scripts and still possible for more
|
||||||
advanced uses as well:
|
advanced uses as well:
|
||||||
|
|
||||||
service sshd -D
|
service /usr/sbin/sshd -D
|
||||||
|
|
||||||
Dependencies are handled using [conditions](doc/conditions.md). One of
|
Dependencies are handled using [conditions](doc/conditions.md). One of
|
||||||
the most common conditions is to wait for basic networking to become
|
the most common conditions is to wait for basic networking to become
|
||||||
available:
|
available:
|
||||||
|
|
||||||
service <net/route/default> nginx -- High performace HTTP server
|
service <net/route/default> nginx -- High performance HTTP server
|
||||||
|
|
||||||
Here is another example where we instruct Finit to not start BusyBox
|
Here is another example where we instruct Finit to not start BusyBox
|
||||||
`ntpd` until `syslogd` has started properly. Finit waits for `syslogd`
|
`ntpd` until `syslogd` has started properly. Finit waits for `syslogd`
|
||||||
@@ -198,13 +245,50 @@ networking here. The configured `runlevel NUM` from `/etc/finit.conf`
|
|||||||
is what Finit changes to after bootstrap, unless 'single' (or 'S') is
|
is what Finit changes to after bootstrap, unless 'single' (or 'S') is
|
||||||
given on the kernel cmdline, in which case runlevel 1 is started.
|
given on the kernel cmdline, in which case runlevel 1 is started.
|
||||||
|
|
||||||
All services in runlevel S(0) are started first, followed by the desired
|
All services in runlevel S) are started first, followed by the desired
|
||||||
run-time runlevel. Run tasks in runlevel S can be started in sequence
|
run-time runlevel. Run tasks in runlevel S can be started in sequence
|
||||||
by using `run [S] cmd`. Changing runlevels at runtime is done like any
|
by using `run [S] cmd`. Changing runlevels at runtime is done like any
|
||||||
other init, e.g. <kbd>init 4</kbd>, but also using the more advanced
|
other init, e.g. <kbd>init 4</kbd>, but also using the more advanced
|
||||||
`intictl` tool.
|
`intictl` tool.
|
||||||
|
|
||||||
|
|
||||||
|
**Conditions**
|
||||||
|
|
||||||
|
As mentioned previously, Finit has an advanced dependency system to
|
||||||
|
handle synchronization, called [conditions](doc/conditions.md). It can
|
||||||
|
be used in many ways; depend on another service, network availability,
|
||||||
|
etc.
|
||||||
|
|
||||||
|
One *really cool* example useful for embedded systems is to run certain
|
||||||
|
scripts if a board has a certain feature encoded in its device tree. At
|
||||||
|
bootstrap we run the following `ident` script:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
#!/bin/sh
|
||||||
|
conddir=/var/run/finit/cond/hw/model
|
||||||
|
dtmodel=/sys/firmware/devicetree/base/model
|
||||||
|
|
||||||
|
if ! test -e $dtmodel; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
model=$(cat $dtmodel | tr "[A-Z] " "[a-z]-")
|
||||||
|
mkdir -p $conddir && ln -s ../../reconf $conddir/$model
|
||||||
|
```
|
||||||
|
|
||||||
|
Provided the device tree node exists, and is a string, we can then use
|
||||||
|
the condition `<hw/model/foo>` when starting other scripts. Here is an
|
||||||
|
example:
|
||||||
|
|
||||||
|
```
|
||||||
|
run [S] /path/to/ident --
|
||||||
|
task [2] <hw/model/foo> /path/to/foo-init -- Initializing Foo board
|
||||||
|
```
|
||||||
|
|
||||||
|
> Notice the trick with an empty description to hide the call to `ident`
|
||||||
|
> in the Finit progress output.
|
||||||
|
|
||||||
|
|
||||||
**Plugins**
|
**Plugins**
|
||||||
|
|
||||||
Plugins can *extend* the functionality of Finit and *hook into* the
|
Plugins can *extend* the functionality of Finit and *hook into* the
|
||||||
@@ -232,8 +316,11 @@ For more information, see [doc/plugins.md](doc/plugins.md).
|
|||||||
By default, Finit monitors `/etc/finit.d/` and `/etc/finit.d/enabled/`
|
By default, Finit monitors `/etc/finit.d/` and `/etc/finit.d/enabled/`
|
||||||
registering any changes to `.conf` files. To activate a change the user
|
registering any changes to `.conf` files. To activate a change the user
|
||||||
must call `initctl reload`, which reloads all modified files, stops any
|
must call `initctl reload`, which reloads all modified files, stops any
|
||||||
removed services, starts new ones, and restarts any modified ones, with
|
removed services, starts new ones, and restarts any modified ones. If the
|
||||||
SIGHUP if the process supports it.
|
command line arguments of a service have changed, the process will be
|
||||||
|
terminated and then started again with the updated arguments. If the arguments
|
||||||
|
have not been modified and the process supports SIGHUP, the process will
|
||||||
|
receive a SIGHUP rather than being terminated and started.
|
||||||
|
|
||||||
For some use-cases the extra step of calling `initctl reload` creates an
|
For some use-cases the extra step of calling `initctl reload` creates an
|
||||||
unnecessary overhead, which can be removed at build-time using:
|
unnecessary overhead, which can be removed at build-time using:
|
||||||
@@ -241,6 +328,50 @@ unnecessary overhead, which can be removed at build-time using:
|
|||||||
configure --enable-auto-reload
|
configure --enable-auto-reload
|
||||||
|
|
||||||
|
|
||||||
|
**Cgroups**
|
||||||
|
|
||||||
|
Finit supports cgroups v2 and comes with the following default groups in
|
||||||
|
which services and user sessions are placed in:
|
||||||
|
|
||||||
|
/sys/fs/cgroup
|
||||||
|
|-- init/ # cpu.weight:100
|
||||||
|
|-- system/ # cpu.weight:9800
|
||||||
|
`-- user/ # cpu.weight:100
|
||||||
|
|
||||||
|
Finit itself and its helper scripts and services are placed in the
|
||||||
|
top-level leaf-node group `init/`, which also is _reserved_.
|
||||||
|
|
||||||
|
All run/task/service/sysv processes are placed in their own sub-group
|
||||||
|
in `system/`. The name of each sub-group is taken from the respective
|
||||||
|
`.conf` file from `/etc/finit.d`.
|
||||||
|
|
||||||
|
All getty/tty processes are placed in their own sub-group in `user/`.
|
||||||
|
The name of each sub-group is taken from the username.
|
||||||
|
|
||||||
|
A fourth group also exists, the `root` group. It is also _reserved_ and
|
||||||
|
primarily intended for RT tasks. If you have RT tasks they need to be
|
||||||
|
declared as such in their service stanza like this:
|
||||||
|
|
||||||
|
service [...] <...> cgroup.root /path/to/foo args -- description
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
cgroup.root
|
||||||
|
service [...] <...> /path/to/foo args -- description
|
||||||
|
service [...] <...> /path/to/bar args -- description
|
||||||
|
|
||||||
|
See [doc/config.md](doc/config.md#cgroups) for more information, e.g.,
|
||||||
|
how to configure per-group limits.
|
||||||
|
|
||||||
|
The `initctl` tool has three commands to help debug and optimize the
|
||||||
|
setup and monitoring of cgroups. See the `ps`, `top`, and `cgroup`
|
||||||
|
commands for details.
|
||||||
|
|
||||||
|
> **Note:** systems that do not support cgroups, specifically version 2,
|
||||||
|
> are automatically detected. On such systems the above functionality
|
||||||
|
> is disabled early at boot.
|
||||||
|
|
||||||
|
|
||||||
Runparts & /etc/rc.local
|
Runparts & /etc/rc.local
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
@@ -264,6 +395,33 @@ in [doc/plugins.md](doc/plugins.md#hooks), and about the system bootstrap
|
|||||||
in [doc/bootstrap.md](doc/bootstrap.md).
|
in [doc/bootstrap.md](doc/bootstrap.md).
|
||||||
|
|
||||||
|
|
||||||
|
### Limitations
|
||||||
|
|
||||||
|
It is not possible to call Finit via signals or use `initctl` in any
|
||||||
|
runparts or `/etc/rc.local` script. This because Finit is single
|
||||||
|
threaded and is calling these scripts in a blocking fashion at the end
|
||||||
|
of runlevel S, at which point the event loop has not yet been started.
|
||||||
|
|
||||||
|
The event loop is the whole thing which Finit is built around, except
|
||||||
|
for runlevel S, which remains a slow procession through a lot of set up,
|
||||||
|
with a few hooks and blocking call outs to external scripts.
|
||||||
|
|
||||||
|
However, not all `initctl` commands are prohibited, supported commands:
|
||||||
|
are:
|
||||||
|
|
||||||
|
- `inictl cond`: only operate of files in `/run/finit/cond`
|
||||||
|
- `initctl enable/disable`: enabled run/task/service is activated on
|
||||||
|
the runlevel change from S to 2
|
||||||
|
- `initctl touch/show/create/delete/list`: `create`, provided the
|
||||||
|
non-interactive mode is used, again changes take effect in the
|
||||||
|
runlevel change directly after bootstrap
|
||||||
|
- `initctl -f reboot/poweroff/halt`: provided the `-f` flag is used to
|
||||||
|
force direct kernel commands
|
||||||
|
|
||||||
|
**Example:** you can set a `usr/` condition in `/etc/rc.local` and have
|
||||||
|
a service/task in runlevel 2 depend on it to execute.
|
||||||
|
|
||||||
|
|
||||||
Runlevels
|
Runlevels
|
||||||
---------
|
---------
|
||||||
|
|
||||||
@@ -349,22 +507,25 @@ services, called `initctl`. Unlike `telinit` the `initctl` tool does
|
|||||||
not return until the given command has fully completed.
|
not return until the given command has fully completed.
|
||||||
|
|
||||||
```
|
```
|
||||||
alpine:~# initctl help
|
|
||||||
Usage: initctl [OPTIONS] [COMMAND]
|
Usage: initctl [OPTIONS] [COMMAND]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
-b, --batch Batch mode, no screen size probing
|
-b, --batch Batch mode, no screen size probing
|
||||||
-c, --create Create missing paths (and files) as needed
|
-c, --create Create missing paths (and files) as needed
|
||||||
-f, --force Ignore missing files and arguments, never prompt
|
-f, --force Ignore missing files and arguments, never prompt
|
||||||
|
-h, --help This help text
|
||||||
|
-j, --json JSON output in 'status' and 'cond' commands
|
||||||
|
-1, --once Only one lap in commands like 'top'
|
||||||
-p, --plain Use plain table headings, no ctrl chars
|
-p, --plain Use plain table headings, no ctrl chars
|
||||||
|
-q, --quiet Silent, only return status of command
|
||||||
-t, --no-heading Skip table headings
|
-t, --no-heading Skip table headings
|
||||||
-v, --verbose Verbose output
|
-v, --verbose Verbose output
|
||||||
-h, --help This help text
|
-V, --version Show program version
|
||||||
|
|
||||||
Commands:
|
Commands:
|
||||||
debug Toggle Finit (daemon) debug
|
debug Toggle Finit (daemon) debug
|
||||||
help This help text
|
help This help text
|
||||||
version Show Finit version
|
version Show program version
|
||||||
|
|
||||||
ls | list List all .conf in /etc/finit.d
|
ls | list List all .conf in /etc/finit.d
|
||||||
create <CONF> Create .conf in /etc/finit.d/available
|
create <CONF> Create .conf in /etc/finit.d/available
|
||||||
@@ -376,25 +537,37 @@ Commands:
|
|||||||
disable <CONF> Disable .conf in /etc/finit.d/enabled
|
disable <CONF> Disable .conf in /etc/finit.d/enabled
|
||||||
reload Reload *.conf in /etc/finit.d (activate changes)
|
reload Reload *.conf in /etc/finit.d (activate changes)
|
||||||
|
|
||||||
cond set <COND> Set (assert) user-defined condition +usr/COND
|
cond set <COND> Set (assert) user-defined conditions +usr/COND
|
||||||
cond clear <COND> Clear (deassert) user-defined condition -usr/COND
|
cond get <COND> Get status of user-defined condition, see $? and -v
|
||||||
cond show Show condition status
|
cond clear <COND> Clear (deassert) user-defined conditions -usr/COND
|
||||||
cond dump Dump all conditions and their status
|
cond status Show condition status, default cond command
|
||||||
|
cond dump [TYPE] Dump all, or a type of, conditions and their status
|
||||||
|
|
||||||
log [NAME] Show ten last Finit, or NAME, messages from syslog
|
log [NAME] Show ten last Finit, or NAME, messages from syslog
|
||||||
start <NAME>[:ID] Start service by name, with optional ID
|
start <NAME>[:ID] Start service by name, with optional ID
|
||||||
stop <NAME>[:ID] Stop/Pause a running service by name
|
stop <NAME>[:ID] Stop/Pause a running service by name
|
||||||
|
reload <NAME>[:ID] Reload service as if .conf changed (SIGHUP or restart)
|
||||||
|
This allows restart of run/tasks that have already run
|
||||||
|
Note: Finit .conf file(s) are *not* reloaded!
|
||||||
restart <NAME>[:ID] Restart (stop/start) service by name
|
restart <NAME>[:ID] Restart (stop/start) service by name
|
||||||
|
signal <NAME>[:ID] <S> Send signal S to service by name, with optional ID
|
||||||
|
ident [NAME] Show matching identities for NAME, or all
|
||||||
status <NAME>[:ID] Show service status, by name
|
status <NAME>[:ID] Show service status, by name
|
||||||
status Show status of services, default command
|
status Show status of services, default command
|
||||||
|
|
||||||
|
cgroup List cgroup config overview
|
||||||
ps List processes based on cgroups
|
ps List processes based on cgroups
|
||||||
|
top Show top-like listing based on cgroups
|
||||||
|
|
||||||
|
plugins List installed plugins
|
||||||
|
|
||||||
runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot
|
runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot
|
||||||
reboot Reboot system
|
reboot Reboot system
|
||||||
halt Halt system
|
halt Halt system
|
||||||
poweroff Halt and power off system
|
poweroff Halt and power off system
|
||||||
suspend Suspend system
|
suspend Suspend system
|
||||||
|
|
||||||
|
utmp show Raw dump of UTMP/WTMP db
|
||||||
```
|
```
|
||||||
|
|
||||||
For services *not* supporting `SIGHUP` the `<!>` notation in the .conf
|
For services *not* supporting `SIGHUP` the `<!>` notation in the .conf
|
||||||
@@ -402,37 +575,75 @@ file must be used to tell Finit to stop and start it on `reload` and
|
|||||||
`runlevel` changes. If `<>` holds more [conditions](doc/conditions.md),
|
`runlevel` changes. If `<>` holds more [conditions](doc/conditions.md),
|
||||||
these will also affect how a service is maintained.
|
these will also affect how a service is maintained.
|
||||||
|
|
||||||
**Note:** even though it is possible to start services not belonging in
|
> **Note:** even though it is possible to start services not belonging in
|
||||||
the current runlevel these services will not be respawned automatically
|
> the current runlevel these services will not be respawned automatically
|
||||||
by Finit if they exit (crash). Hence, if the runlevel is 2, the below
|
> by Finit if they exit (crash). Hence, if the runlevel is 2, the below
|
||||||
Dropbear SSH service will not be restarted if it is killed or exits.
|
> Dropbear SSH service will not be restarted if it is killed or exits.
|
||||||
|
|
||||||
|
The `status` command is the default, it displays a quick overview of all
|
||||||
|
monitored run/task/services. Here we call `initctl -p`, suitable for
|
||||||
|
scripting and documentation:
|
||||||
|
|
||||||
```
|
```
|
||||||
alpine:~# initctl
|
alpine:~# initctl -p
|
||||||
PID IDENT STATUS RUNLEVELS DESCRIPTION
|
PID IDENT STATUS RUNLEVELS DESCRIPTION
|
||||||
======================================================================
|
======================================================================
|
||||||
1506 acpid running [--2345----] ACPI daemon
|
1506 acpid running [---2345----] ACPI daemon
|
||||||
1509 crond running [--2345----] Cron daemon
|
1509 crond running [---2345----] Cron daemon
|
||||||
1489 dropbear running [--2345----] Dropbear SSH daemon
|
1489 dropbear running [---2345----] Dropbear SSH daemon
|
||||||
1511 klogd running [S12345----] Kernel log daemon
|
1511 klogd running [S-12345----] Kernel log daemon
|
||||||
1512 ntpd running [--2345----] NTP daemon
|
1512 ntpd running [---2345----] NTP daemon
|
||||||
1473 syslogd running [S12345----] Syslog daemon
|
1473 syslogd running [S-12345----] Syslog daemon
|
||||||
|
|
||||||
alpine:~# initctl -v
|
alpine:~# initctl -pv
|
||||||
PID IDENT STATUS RUNLEVELS COMMAND
|
PID IDENT STATUS RUNLEVELS COMMAND
|
||||||
======================================================================
|
======================================================================
|
||||||
1506 acpid running [--2345----] acpid -f
|
1506 acpid running [---2345----] acpid -f
|
||||||
1509 crond running [--2345----] crond -f -S $CRON_OPTS
|
1509 crond running [---2345----] crond -f -S $CRON_OPTS
|
||||||
1489 dropbear running [--2345----] dropbear -R -F $DROPBEAR_OPTS
|
1489 dropbear running [---2345----] dropbear -R -F $DROPBEAR_OPTS
|
||||||
1511 klogd running [S12345----] klogd -n $KLOGD_OPTS
|
1511 klogd running [S-12345----] klogd -n $KLOGD_OPTS
|
||||||
1512 ntpd running [--2345----] ntpd -n $NTPD_OPTS
|
1512 ntpd running [---2345----] ntpd -n $NTPD_OPTS
|
||||||
1473 syslogd running [S12345----] syslogd -n
|
1473 syslogd running [S-12345----] syslogd -n
|
||||||
```
|
```
|
||||||
|
|
||||||
The environment variables to each of the services above are read from,
|
The environment variables to each of the services above are read from,
|
||||||
in the case of Alpine Linux, `/etc/conf.d/`. Other distributions may
|
in the case of Alpine Linux, `/etc/conf.d/`. Other distributions may
|
||||||
have other directories, e.g., Debian use `/etc/default/`.
|
have other directories, e.g., Debian use `/etc/default/`.
|
||||||
|
|
||||||
|
The `status` command takes an optional `NAME:ID` argument. Here we
|
||||||
|
check the status of `dropbear`, which only has one instance in this
|
||||||
|
system:
|
||||||
|
|
||||||
|
```
|
||||||
|
alpine:~# initctl -p status dropbear
|
||||||
|
Status : running
|
||||||
|
Identity : dropbear
|
||||||
|
Description : Dropbear SSH daemon
|
||||||
|
Origin : /etc/finit.d/enabled/dropbear.conf
|
||||||
|
Environment : -/etc/conf.d/dropbear
|
||||||
|
Condition(s):
|
||||||
|
Command : dropbear -R -F $DROPBEAR_OPTS
|
||||||
|
PID file : !/run/dropbear.pid
|
||||||
|
PID : 1485
|
||||||
|
User : root
|
||||||
|
Group : root
|
||||||
|
Uptime : 2 hour 46 min 56 sec
|
||||||
|
Runlevels : [---2345----]
|
||||||
|
Memory : 1.2M
|
||||||
|
CGroup : /system/dropbear cpu 0 [100, max] mem [--.--, max]
|
||||||
|
|- 1485 dropbear -R -F
|
||||||
|
|- 2634 dropbear -R -F
|
||||||
|
|- 2635 ash
|
||||||
|
`- 2652 initctl -p status dropbear
|
||||||
|
|
||||||
|
Apr 8 12:19:49 alpine authpriv.info dropbear[1485]: Not backgrounding
|
||||||
|
Apr 8 12:37:45 alpine authpriv.info dropbear[2300]: Child connection from 192.168.121.1:47834
|
||||||
|
Apr 8 12:37:46 alpine authpriv.notice dropbear[2300]: Password auth succeeded for 'root' from 192.168.121.1:47834
|
||||||
|
Apr 8 12:37:46 alpine authpriv.info dropbear[2300]: Exit (root) from <192.168.121.1:47834>: Disconnect received
|
||||||
|
Apr 8 15:02:11 alpine authpriv.info dropbear[2634]: Child connection from 192.168.121.1:48576
|
||||||
|
Apr 8 15:02:12 alpine authpriv.notice dropbear[2634]: Password auth succeeded for 'root' from 192.168.121.1:48576
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Requirements
|
Requirements
|
||||||
------------
|
------------
|
||||||
@@ -468,36 +679,41 @@ This project is based on the [original finit][] by [Claudio Matsuoka][]
|
|||||||
which was reverse engineered from syscalls of the [EeePC fastinit][] —
|
which was reverse engineered from syscalls of the [EeePC fastinit][] —
|
||||||
"gaps filled with frog DNA …"
|
"gaps filled with frog DNA …"
|
||||||
|
|
||||||
Finit is developed and maintained by [Joachim Wiberg][] at [GitHub][].
|
Finit is developed and maintained by [Joachim Wiberg][] at [GitHub][6].
|
||||||
Please file bug reports, clone it, or send pull requests for bug fixes
|
Please file bug reports, clone it, or send pull requests for bug fixes
|
||||||
and proposed extensions.
|
and proposed extensions.
|
||||||
|
|
||||||
|
|
||||||
[1]: https://en.wikipedia.org/wiki/Process_supervision
|
[1]: https://en.wikipedia.org/wiki/Process_supervision
|
||||||
[2]: http://cr.yp.to/daemontools.html
|
[2]: https://cr.yp.to/daemontools.html
|
||||||
[3]: http://smarden.org/runit/
|
[3]: https://smarden.org/runit/
|
||||||
[4]: http://en.wikipedia.org/wiki/Init
|
[4]: https://en.wikipedia.org/wiki/Init
|
||||||
[5]: http://en.wikipedia.org/wiki/Runlevel
|
[5]: https://en.wikipedia.org/wiki/Runlevel
|
||||||
[6]: https://www.freedesktop.org/wiki/Software/systemd/
|
[6]: https://github.com/troglobit/finit
|
||||||
[9]: https://github.com/troglobit/troglos
|
|
||||||
[RFC862]: https://tools.ietf.org/html/rfc862
|
[RFC862]: https://tools.ietf.org/html/rfc862
|
||||||
[RFC863]: https://tools.ietf.org/html/rfc863
|
[RFC863]: https://tools.ietf.org/html/rfc863
|
||||||
[RFC864]: https://tools.ietf.org/html/rfc864
|
[RFC864]: https://tools.ietf.org/html/rfc864
|
||||||
[RFC867]: https://tools.ietf.org/html/rfc867
|
[RFC867]: https://tools.ietf.org/html/rfc867
|
||||||
[RFC868]: https://tools.ietf.org/html/rfc868
|
[RFC868]: https://tools.ietf.org/html/rfc868
|
||||||
[init]: http://en.wikipedia.org/wiki/Init
|
[init]: https://en.wikipedia.org/wiki/Init
|
||||||
[upstart]: http://upstart.ubuntu.com/
|
[upstart]: https://upstart.ubuntu.com/
|
||||||
[systemd]: http://www.freedesktop.org/wiki/Software/systemd/
|
[systemd]: https://www.freedesktop.org/wiki/Software/systemd/
|
||||||
[openrc]: http://www.gentoo.org/proj/en/base/openrc/
|
[openrc]: https://www.gentoo.org/proj/en/base/openrc/
|
||||||
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
[sd_notify()]: https://www.freedesktop.org/software/systemd/man/sd_notify.html
|
||||||
|
[s6 style]: https://skarnet.org/software/s6/notifywhenup.html
|
||||||
|
[run-parts(8)]: https://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
||||||
|
[tmpfiles.d(5)]: https://www.freedesktop.org/software/systemd/man/tmpfiles.d.html
|
||||||
[original finit]: http://helllabs.org/finit/
|
[original finit]: http://helllabs.org/finit/
|
||||||
[EeePC fastinit]: https://web.archive.org/web/20071208212450/http://wiki.eeeuser.com/boot_process:the_boot_process
|
[EeePC fastinit]: https://web.archive.org/web/20071208212450/http://wiki.eeeuser.com/boot_process:the_boot_process
|
||||||
[Claudio Matsuoka]: https://github.com/cmatsuoka
|
[Claudio Matsuoka]: https://github.com/cmatsuoka
|
||||||
[Joachim Wiberg]: http://troglobit.com
|
[Joachim Wiberg]: https://troglobit.com
|
||||||
[GitHub]: https://github.com/troglobit/finit
|
[finit.conf(5)]: https://man.troglobit.com/man5/finit.conf.5.html
|
||||||
[License]: https://en.wikipedia.org/wiki/MIT_License
|
[License]: https://en.wikipedia.org/wiki/MIT_License
|
||||||
[License Badge]: https://img.shields.io/badge/License-MIT-teal.svg
|
[License Badge]: https://img.shields.io/badge/License-MIT-teal.svg
|
||||||
[Travis]: https://travis-ci.org/troglobit/finit
|
[myLinux]: https://github.com/troglobit/myLinux/
|
||||||
[Travis Status]: https://travis-ci.org/troglobit/finit.svg?branch=master
|
[watchdogd]: https://github.com/troglobit/watchdogd/
|
||||||
|
[sysklogd]: https://github.com/troglobit/sysklogd/
|
||||||
|
[GitHub]: https://github.com/troglobit/finit/actions/workflows/build.yml/
|
||||||
|
[GitHub Status]: https://github.com/troglobit/finit/actions/workflows/build.yml/badge.svg
|
||||||
[Coverity Scan]: https://scan.coverity.com/projects/3545
|
[Coverity Scan]: https://scan.coverity.com/projects/3545
|
||||||
[Coverity Status]: https://scan.coverity.com/projects/3545/badge.svg
|
[Coverity Status]: https://scan.coverity.com/projects/3545/badge.svg
|
||||||
|
|||||||
+147
-54
@@ -1,20 +1,23 @@
|
|||||||
AC_INIT(Finit, 4.0-rc3, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/finit.html)
|
AC_INIT([Finit],[4.4],[https://github.com/troglobit/finit/issues],[finit],[https://troglobit.com/projects/finit/])
|
||||||
AC_CONFIG_AUX_DIR(aux)
|
AC_CONFIG_AUX_DIR(aux)
|
||||||
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
|
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
|
||||||
AM_SILENT_RULES([yes])
|
AM_SILENT_RULES([yes])
|
||||||
|
|
||||||
AC_CONFIG_SRCDIR([src/finit.c])
|
AC_CONFIG_SRCDIR([src/finit.c])
|
||||||
AC_CONFIG_HEADER([config.h])
|
AC_CONFIG_HEADERS([config.h])
|
||||||
AC_CONFIG_FILES([Makefile
|
AC_CONFIG_FILES([Makefile
|
||||||
contrib/Makefile
|
contrib/Makefile
|
||||||
contrib/alpine/Makefile contrib/alpine/finit.d/Makefile contrib/alpine/finit.d/available/Makefile
|
contrib/alpine/Makefile contrib/alpine/finit.d/Makefile contrib/alpine/finit.d/available/Makefile
|
||||||
contrib/debian/Makefile contrib/debian/finit.d/Makefile contrib/debian/finit.d/available/Makefile contrib/debian/grub.d/Makefile
|
contrib/debian/Makefile contrib/debian/finit.d/Makefile contrib/debian/finit.d/available/Makefile
|
||||||
contrib/void/Makefile contrib/void/finit.d/Makefile contrib/void/finit.d/available/Makefile
|
contrib/void/Makefile contrib/void/finit.d/Makefile contrib/void/finit.d/available/Makefile
|
||||||
doc/Makefile
|
doc/Makefile
|
||||||
|
man/Makefile
|
||||||
plugins/Makefile
|
plugins/Makefile
|
||||||
src/Makefile
|
src/Makefile
|
||||||
test/test.env
|
system/Makefile
|
||||||
test/Makefile])
|
tmpfiles.d/Makefile
|
||||||
|
test/test.env test/Makefile
|
||||||
|
test/lib/Makefile test/src/Makefile])
|
||||||
|
|
||||||
# Older versions of autoconf (<2.58) do not have AC_CONFIG_MACRO_DIR()
|
# Older versions of autoconf (<2.58) do not have AC_CONFIG_MACRO_DIR()
|
||||||
#m4_include([m4/plugin.m4])
|
#m4_include([m4/plugin.m4])
|
||||||
@@ -31,9 +34,8 @@ AC_PROG_INSTALL
|
|||||||
AC_PROG_MKDIR_P
|
AC_PROG_MKDIR_P
|
||||||
|
|
||||||
# Configuration.
|
# Configuration.
|
||||||
AC_HEADER_STDC
|
AC_CHECK_HEADERS([termios.h sys/ioctl.h mntent.h sys/sysmacros.h])
|
||||||
AC_CHECK_HEADERS([fstaby.h termios.h sys/ioctl.h])
|
AC_CHECK_FUNCS([strstr getopt getmntent getmntent_r])
|
||||||
AC_CHECK_FUNCS([strstr getopt getfsenty])
|
|
||||||
|
|
||||||
# Check for uint[8,16,32]_t
|
# Check for uint[8,16,32]_t
|
||||||
AC_TYPE_UINT8_T
|
AC_TYPE_UINT8_T
|
||||||
@@ -48,30 +50,25 @@ PKG_CHECK_MODULES([uev], [libuev >= 2.2.0])
|
|||||||
PKG_CHECK_MODULES([lite], [libite >= 2.2.0])
|
PKG_CHECK_MODULES([lite], [libite >= 2.2.0])
|
||||||
|
|
||||||
# Check for configured Finit features
|
# Check for configured Finit features
|
||||||
AC_ARG_ENABLE(emergency_shell,
|
|
||||||
AS_HELP_STRING([--enable-emergency-shell], [Experimental emergency fallback at boot.
|
|
||||||
Use only for debugging very early boot problems with Finit]),,[
|
|
||||||
enable_emergency_shell=no])
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(fallback_shell,
|
|
||||||
AS_HELP_STRING([--enable-fallback-shell], [Start a shell if no TTYs can start]),,[
|
|
||||||
enable_fallback_shell=no])
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(auto_reload,
|
AC_ARG_ENABLE(auto_reload,
|
||||||
AS_HELP_STRING([--enable-auto-reload], [Automatic reload on any .conf change]),,[
|
AS_HELP_STRING([--enable-auto-reload], [Automatic reload on any .conf change]),,[
|
||||||
enable_auto_reload=no])
|
enable_auto_reload=no])
|
||||||
|
|
||||||
AC_ARG_ENABLE(watchdog,
|
AC_ARG_ENABLE(kernel_cmdline,
|
||||||
AS_HELP_STRING([--enable-watchdog], [Enable built-in watchdog, uses /dev/watchdog]),,[
|
AS_HELP_STRING([--enable-kernel-cmdline], [Parse init args from /proc/cmdline (don't use!)]),,[
|
||||||
enable_watchdog=no])
|
enable_kernel_cmdline=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(fastboot,
|
||||||
|
AS_HELP_STRING([--enable-fastboot], [Skip fsck check on filesystems listed in /etc/fstab]),,[
|
||||||
|
enable_fastboot=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(fsckfix,
|
||||||
|
AS_HELP_STRING([--enable-fsckfix], [Run fsck fix mode (options: -yf) on filesystems listed in /etc/fstab]),,[
|
||||||
|
enable_fsckfix=no])
|
||||||
|
|
||||||
AC_ARG_ENABLE(redirect,
|
AC_ARG_ENABLE(redirect,
|
||||||
AS_HELP_STRING([--enable-redirect], [Redirect service output to /dev/null, default: no]),,[
|
AS_HELP_STRING([--disable-redirect], [Disable redirection of service output to /dev/null]),,[
|
||||||
enable_redirect_output=no])
|
enable_redirect=yes])
|
||||||
|
|
||||||
AC_ARG_ENABLE(logit,
|
|
||||||
AS_HELP_STRING([--disable-logit], [Disable logit, used for log redirection, default: enable]),,[
|
|
||||||
enable_logit=yes])
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(logrotate,
|
AC_ARG_ENABLE(logrotate,
|
||||||
AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp, default enabled]),,[
|
AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp, default enabled]),,[
|
||||||
@@ -86,18 +83,30 @@ AC_ARG_ENABLE(contrib,
|
|||||||
enable_contrib=yes])
|
enable_contrib=yes])
|
||||||
|
|
||||||
# Check for extra plugins to enable
|
# Check for extra plugins to enable
|
||||||
enable_all_plugins=auto
|
AC_ARG_ENABLE(all_plugins,
|
||||||
|
AS_HELP_STRING([--enable-all-plugins], [Enable all plugins, default: auto]),
|
||||||
|
enable_all_plugins=$enableval, enable_all_plugins=auto)
|
||||||
AC_PLUGIN([alsa-utils], [no], [Save and restore ALSA sound settings using alsactl])
|
AC_PLUGIN([alsa-utils], [no], [Save and restore ALSA sound settings using alsactl])
|
||||||
AC_PLUGIN([dbus], [no], [Setup and start system message bus, D-Bus])
|
AC_PLUGIN([dbus], [no], [Setup and start system message bus, D-Bus])
|
||||||
AC_PLUGIN([modules-load], [no], [Scans /etc/modules-load.d for modules to load])
|
AC_PLUGIN([modules-load], [no], [Scans /etc/modules-load.d for modules to load])
|
||||||
|
AC_PLUGIN([modprobe], [yes], [Coldplug modules using modalias magic])
|
||||||
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.])
|
||||||
|
AC_PLUGIN([hook-scripts], [no], [Trigger script execution from hook points])
|
||||||
AC_PLUGIN([hotplug], [yes], [Setup and start udev or mdev hotplug daemon])
|
AC_PLUGIN([hotplug], [yes], [Setup and start udev or mdev hotplug daemon])
|
||||||
|
AC_PLUGIN([rtc], [yes], [Save and restore RTC using hwclock])
|
||||||
|
AC_PLUGIN([tty], [yes], [Automatically activate new TTYs, e.g. USB-to-serial])
|
||||||
|
AC_PLUGIN([urandom], [yes], [Setup and save random seed at boot/shutdown])
|
||||||
|
AC_PLUGIN([testserv], [no], [Test plugin to start test serv daemon])
|
||||||
|
|
||||||
# Check for extra arguments or packages
|
# Check for extra arguments or packages
|
||||||
|
AC_ARG_WITH(fstab,
|
||||||
|
AS_HELP_STRING([--with-fstab=FILE], [System default fstab, default $sysconfdir/fstab]),
|
||||||
|
[fstab=$withval], [fstab=yes])
|
||||||
|
|
||||||
AC_ARG_WITH(heading,
|
AC_ARG_WITH(heading,
|
||||||
AS_HELP_STRING([--with-heading=GREET], [Display GREET instead of Finit version at boot]),
|
AS_HELP_STRING([--with-heading=GREET], [Heading for boot progress. Default: PRETTY_NAME from /etc/os-release, fallback to "Finit vX.YY"]),
|
||||||
[heading=$withval], [heading=yes])
|
[heading=$withval], [heading=yes])
|
||||||
|
|
||||||
AC_ARG_WITH(config,
|
AC_ARG_WITH(config,
|
||||||
@@ -116,46 +125,75 @@ AC_ARG_WITH(sysconfig,
|
|||||||
AS_HELP_STRING([--with-sysconfig=DIR], [System environment directory, sourced by .conf files, default /etc/default & /etc/conf.d]),
|
AS_HELP_STRING([--with-sysconfig=DIR], [System environment directory, sourced by .conf files, default /etc/default & /etc/conf.d]),
|
||||||
[sysconfig=$withval], [sysconfig=default])
|
[sysconfig=$withval], [sysconfig=default])
|
||||||
|
|
||||||
|
AC_ARG_WITH(group,
|
||||||
|
AS_HELP_STRING([--with-group=NAME], [Group for /run/finit/socket (initctl), default: root]),
|
||||||
|
[group=$withval], [group=root])
|
||||||
|
|
||||||
AC_ARG_WITH(hostname,
|
AC_ARG_WITH(hostname,
|
||||||
AS_HELP_STRING([--with-hostname=NAME], [If /etc/hostname is missing, default: noname]),
|
AS_HELP_STRING([--with-hostname=NAME], [If /etc/hostname is missing, default: noname]),
|
||||||
[hostname=$withval], [hostname=yes])
|
[hostname=$withval], [hostname=yes])
|
||||||
|
|
||||||
AC_ARG_WITH(runlevel,
|
AC_ARG_WITH(runlevel,
|
||||||
AS_HELP_STRING([--with-runlevel=N], [Runlevel to switch to after bootstrap, default: 2]),
|
AS_HELP_STRING([--with-runlevel=N], [Runlevel to switch to after bootstrap [1-9], default: 2]),
|
||||||
[runlevel=$withval], [runlevel=yes])
|
[runlevel=$withval], [runlevel=yes])
|
||||||
|
|
||||||
AC_ARG_WITH(random-seed,
|
AC_ARG_WITH(random-seed,
|
||||||
AS_HELP_STRING([--with-random-seed=FILE], [Save a random seed for /dev/urandom across reboots, default /var/lib/misc/random-seed]),
|
AS_HELP_STRING([--with-random-seed=FILE], [Save a random seed for /dev/urandom across reboots, default /var/lib/misc/random-seed]),
|
||||||
[random_seed=$withval], [random_seed=yes])
|
[random_seed=$withval], [random_seed=yes])
|
||||||
|
|
||||||
|
AC_ARG_WITH(keventd,
|
||||||
|
AS_HELP_STRING([--with-keventd], [Enable built-in keventd, default: no]),, [with_keventd=no])
|
||||||
|
|
||||||
|
AC_ARG_WITH(sulogin,
|
||||||
|
AS_HELP_STRING([--with-sulogin], [Enable built-in sulogin, default: no.]),, [with_sulogin=no])
|
||||||
|
|
||||||
|
AC_ARG_WITH(watchdog,
|
||||||
|
AS_HELP_STRING([--with-watchdog=[DEV]], [Enable built-in watchdog, default: /dev/watchdog]),
|
||||||
|
[watchdog=$withval], [with_watchdog=no watchdog=])
|
||||||
|
|
||||||
|
AC_ARG_WITH(hook-scripts-path,
|
||||||
|
AS_HELP_STRING([--with-hook-scripts-path=DIR], [Base directory for hook scripts, default $libexecdir/finit/hook]),
|
||||||
|
[hook_scripts_path=$withval], [hook_scripts_path=yes])
|
||||||
|
|
||||||
|
AC_ARG_WITH(plugin-path,
|
||||||
|
AS_HELP_STRING([--with-plugin-path=DIR], [Search path for external plugins, default /usr/lib/finit/plugins:/usr/local/lib/finit/plugins]),
|
||||||
|
[plugin_path=$withval], [plugin_path=yes])
|
||||||
|
|
||||||
|
AC_ARG_WITH(rtc-date,
|
||||||
|
AS_HELP_STRING([--with-rtc-date=DATE], [If RTC date/time is too old, restore to DATE, format "YYYY-MM-DD HH:MM", default "2000-01-01 00:00"]),
|
||||||
|
[rtc_date=$withval], [rtc_date=no])
|
||||||
|
|
||||||
### Enable features ###########################################################################
|
### Enable features ###########################################################################
|
||||||
|
|
||||||
# Create config.h from selected features and fallback defautls
|
# Create config.h from selected features and fallback defaults
|
||||||
AS_IF([test "x$enable_emergency_shell" = "xyes"], [
|
|
||||||
AC_DEFINE(EMERGENCY_SHELL, 1, [Fork off init and let PID 1 wait and start /bin/sh if init crashes.])])
|
|
||||||
|
|
||||||
AS_IF([test "x$enable_fallback_shell" = "xyes"], [
|
|
||||||
AC_DEFINE(FALLBACK_SHELL, 1, [Start /bin/sh on console if no TTYs.])])
|
|
||||||
|
|
||||||
AS_IF([test "x$enable_auto_reload" = "xyes"], [
|
AS_IF([test "x$enable_auto_reload" = "xyes"], [
|
||||||
AC_DEFINE(AUTO_RELOAD, 1, [Finit automatically does `initctl reload` on any .conf change])])
|
AC_DEFINE(AUTO_RELOAD, 1, [Finit automatically does `initctl reload` on any .conf change])])
|
||||||
|
|
||||||
AS_IF([test "x$enable_watchdog" = "xyes"], [
|
AS_IF([test "x$enable_kernel_cmdline" = "xyes"], [
|
||||||
AC_DEFINE(BUILTIN_WATCHDOG, 1, [Enable built-in watchdog, kicks on /dev/watchdog])])
|
AC_DEFINE(KERNEL_CMDLINE, 1, [Dumpster diving after init args from /proc/cmdline])])
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_fastboot" = "xyes"], [
|
||||||
|
AC_DEFINE(FAST_BOOT, 1, [Skip fsck check on filesystems listed in /etc/fstab])])
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_fsckfix" = "xyes"], [
|
||||||
|
AC_DEFINE(FSCK_FIX, 1, [Run fsck fix mode (options: -yf) on filesystems listed in /etc/fstab])])
|
||||||
|
|
||||||
AS_IF([test "x$enable_redirect" = "xyes"], [
|
AS_IF([test "x$enable_redirect" = "xyes"], [
|
||||||
AC_DEFINE(REDIRECT_OUTPUT, 1, [Enable redirection of service output to /dev/null])])
|
AC_DEFINE(REDIRECT_OUTPUT, 1, [Enable redirection of service output to /dev/null])])
|
||||||
|
|
||||||
### Disable features ###########################################################################
|
### Disable features ###########################################################################
|
||||||
AS_IF([test "x$enable_logit" != "xno"], [
|
|
||||||
AC_DEFINE(LOGIT_ENABLED, 1, [Enable logit tool, used for log redirection by Finit])])
|
|
||||||
|
|
||||||
AS_IF([test "x$enable_logrotate" != "xno"], [
|
AS_IF([test "x$enable_logrotate" != "xno"], [
|
||||||
AC_DEFINE(LOGROTATE_ENABLED, 1, [Enable built-in rotation of /var/log/wtmp et al.])])
|
AC_DEFINE(LOGROTATE_ENABLED, 1, [Enable built-in rotation of /var/log/wtmp et al.])])
|
||||||
|
|
||||||
AM_CONDITIONAL(LOGROTATE, [test "x$enable_logrotate" = "xyes"])
|
AM_CONDITIONAL(LOGROTATE, [test "x$enable_logrotate" = "xyes"])
|
||||||
|
|
||||||
### With features ##############################################################################
|
### With features ##############################################################################
|
||||||
|
AS_IF([test "x$with_fstab" != "xno"], [
|
||||||
|
AS_IF([test "x$fstab" = "xyes"], [fstab=$sysconfdir/fstab])
|
||||||
|
AC_EXPAND_DIR(fstab_path, "$fstab")
|
||||||
|
AC_DEFINE_UNQUOTED(FINIT_FSTAB, "$fstab_path", [Built-in default: /etc/fstab])],[
|
||||||
|
AC_DEFINE_UNQUOTED(FINIT_FSTAB, NULL, [No built-in default fstab])])
|
||||||
|
|
||||||
AS_IF([test "x$with_config" != "xno"], [
|
AS_IF([test "x$with_config" != "xno"], [
|
||||||
AS_IF([test "x$conf" = "xyes"], [
|
AS_IF([test "x$conf" = "xyes"], [
|
||||||
conf=$sysconfdir/finit.conf])])
|
conf=$sysconfdir/finit.conf])])
|
||||||
@@ -183,9 +221,13 @@ AS_IF([test "x$with_sysconfig" != "xno"], [
|
|||||||
[System environment, default /etc/default & /etc/conf.d])])])
|
[System environment, default /etc/default & /etc/conf.d])])])
|
||||||
|
|
||||||
AS_IF([test "x$with_heading" != "xno"], [
|
AS_IF([test "x$with_heading" != "xno"], [
|
||||||
AS_IF([test "x$heading" = "xyes"], [
|
AS_IF([test "x$heading" = "xyes"], [heading=""])
|
||||||
heading="$PACKAGE_NAME v$PACKAGE_VERSION"])])
|
AC_DEFINE_UNQUOTED(INIT_OSHEADING, "$heading", [Displayed by Finit at boot, defaults to /etc/os-release PRETTY_NAME])])
|
||||||
AC_DEFINE_UNQUOTED(INIT_HEADING, "$heading", [Displayed by Finit at boot])
|
|
||||||
|
AS_IF([test "x$with_group" != "xno"], [
|
||||||
|
AS_IF([test "x$group" = "xyes"], [
|
||||||
|
group=root])])
|
||||||
|
AC_DEFINE_UNQUOTED(DEFGROUP, "$group", [For /run/finit/socket])
|
||||||
|
|
||||||
AS_IF([test "x$with_hostname" != "xno"], [
|
AS_IF([test "x$with_hostname" != "xno"], [
|
||||||
AS_IF([test "x$hostname" = "xyes"], [
|
AS_IF([test "x$hostname" = "xyes"], [
|
||||||
@@ -204,28 +246,74 @@ AS_IF([test "x$with_random_seed" != "xno"], [
|
|||||||
AC_EXPAND_DIR(random_path, "$random_seed")
|
AC_EXPAND_DIR(random_path, "$random_seed")
|
||||||
AC_DEFINE_UNQUOTED(RANDOMSEED, "$random_path", [Improve random at boot by seeding it with sth from before.])])
|
AC_DEFINE_UNQUOTED(RANDOMSEED, "$random_path", [Improve random at boot by seeding it with sth from before.])])
|
||||||
|
|
||||||
|
AS_IF([test "x$rtc_date" != "xno"], [
|
||||||
|
AC_DEFINE(RTC_TIMESTAMP_CUSTOM, "$rtc_date", [Custom RTC restore date, default: 2000-01-01 00:00])], [
|
||||||
|
rtc_date=""])
|
||||||
|
|
||||||
|
AS_IF([test "x$with_keventd" != "xno"], [with_keventd=yes])
|
||||||
|
|
||||||
|
AS_IF([test "x$with_sulogin" != "xno"], [with_sulogin=yes])
|
||||||
|
|
||||||
|
AS_IF([test "x$with_watchdog" != "xno"], [
|
||||||
|
AS_IF([test "x$watchdog" = "xyes"], [
|
||||||
|
watchdog=/dev/watchdog])
|
||||||
|
with_watchdog=yes
|
||||||
|
AC_DEFINE_UNQUOTED(WDT_DEVNODE, "$watchdog", [Built-in watchdog device node])], [
|
||||||
|
watchdog=])
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_hook_scripts_plugin" != "xno"], [
|
||||||
|
AS_IF([test "x$hook_scripts_path" = "xyes"], [hook_scripts_path=$libexecdir/finit/hook])
|
||||||
|
AC_EXPAND_DIR(hook_scripts_path, "$hook_scripts_path")
|
||||||
|
AC_DEFINE_UNQUOTED(PLUGIN_HOOK_SCRIPTS_PATH, "$hook_scripts_path", [Built-in default: $libexecdir/finit])])
|
||||||
|
|
||||||
|
AS_IF([test "x$with_plugin_path" != "xno"], [
|
||||||
|
AS_IF([test "x$plugin_path" = "xyes"], [plugin_path=/usr/lib/finit/plugins:/usr/local/lib/finit/plugins])
|
||||||
|
AC_EXPAND_DIR(plugin_path, "$plugin_path")
|
||||||
|
AC_DEFINE_UNQUOTED(EXTERNAL_PLUGIN_PATH, "$plugin_path", [Built-in default: /usr/lib/finit/plugins:/usr/local/lib/finit/plugins])])
|
||||||
|
|
||||||
# Control build with automake flags
|
# Control build with automake flags
|
||||||
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
||||||
AM_CONDITIONAL(WATCHDOGD, [test "x$enable_watchdog" = "xyes"])
|
AM_CONDITIONAL(KEVENTD, [test "x$with_keventd" != "xno"])
|
||||||
AM_CONDITIONAL(LOGIT, [test "x$enable_logit" = "xyes"])
|
AM_CONDITIONAL(SULOGIN, [test "x$with_sulogin" != "xno"])
|
||||||
|
AM_CONDITIONAL(WATCHDOGD, [test "x$with_watchdog" != "xno"])
|
||||||
AM_CONDITIONAL(DOC, [test "x$enable_doc" = "xyes"])
|
AM_CONDITIONAL(DOC, [test "x$enable_doc" = "xyes"])
|
||||||
AM_CONDITIONAL(CONTRIB, [test "x$enable_contrib" = "xyes"])
|
AM_CONDITIONAL(CONTRIB, [test "x$enable_contrib" = "xyes"])
|
||||||
|
AM_CONDITIONAL(TESTSERV, [test "x$enable_testserv_plugin" = "xyes"])
|
||||||
|
|
||||||
# Override default libdir, used for plugins and rescue.conf
|
# Override default libdir, used for plugins and rescue.conf
|
||||||
pkglibdir=$libdir/finit
|
pkglibdir=$libdir/finit
|
||||||
AC_SUBST(pkglibexecdir)
|
AC_SUBST(pkglibexecdir)
|
||||||
AC_EXPAND_DIR(pkglibexecdir, "$libexecdir/finit")
|
AC_EXPAND_DIR(pkglibexecdir, "$libexecdir/finit")
|
||||||
AC_DEFINE_UNQUOTED(FINIT_LIBPATH_, "$pkglibexecdir", [Finit libexec path])
|
AC_DEFINE_UNQUOTED(FINIT_EXECPATH_, "$pkglibexecdir", [Finit libexec path])
|
||||||
|
|
||||||
AC_EXPAND_DIR(plugin_path, "$libdir/finit/plugins")
|
AC_EXPAND_DIR(plugin_path, "$pkglibdir/plugins")
|
||||||
AC_SUBST(plugin_path)
|
AC_SUBST(plugin_path)
|
||||||
AC_DEFINE_UNQUOTED(PLUGIN_PATH, "$plugin_path", [Finit plugin path])
|
AC_DEFINE_UNQUOTED(PLUGIN_PATH, "$plugin_path", [Finit plugin path])
|
||||||
|
|
||||||
AC_EXPAND_DIR(rescue_conf, "$libdir/finit/rescue.conf")
|
AC_EXPAND_DIR(tmpfiles_path, "$libdir/tmpfiles.d")
|
||||||
|
AC_SUBST(tmpfiles_path)
|
||||||
|
AC_DEFINE_UNQUOTED(TMPFILES_PATH, "$tmpfiles_path", [Main tmpfiles.d/, override in /etc])
|
||||||
|
|
||||||
|
AC_EXPAND_DIR(finit_tmpfiles, "$pkglibdir/tmpfiles.d")
|
||||||
|
AC_SUBST(finit_tmpfiles)
|
||||||
|
AC_DEFINE_UNQUOTED(FINIT_TMPFILES, "$finit_tmpfiles", [Finit tmpfiles.d/ .conf path])
|
||||||
|
|
||||||
|
AC_EXPAND_DIR(system_path, "$pkglibdir/system")
|
||||||
|
AC_SUBST(system_path)
|
||||||
|
AC_DEFINE_UNQUOTED(FINIT_SYSPATH, "$system_path", [Static services, previously generated at runtime by plugins])
|
||||||
|
|
||||||
|
AC_EXPAND_DIR(rescue_conf, "$pkglibdir/rescue.conf")
|
||||||
AC_DEFINE_UNQUOTED(RESCUE_CONF, "$rescue_conf", [Finit rescue mode .conf])
|
AC_DEFINE_UNQUOTED(RESCUE_CONF, "$rescue_conf", [Finit rescue mode .conf])
|
||||||
AC_EXPAND_DIR(sample_conf, "$libdir/finit/sample.conf")
|
AC_EXPAND_DIR(sample_conf, "$pkglibdir/sample.conf")
|
||||||
AC_DEFINE_UNQUOTED(SAMPLE_CONF, "$sample_conf", [Finit sameple.conf for initctl create])
|
AC_DEFINE_UNQUOTED(SAMPLE_CONF, "$sample_conf", [Finit sameple.conf for initctl create])
|
||||||
|
|
||||||
|
AS_IF([test "$heading" = ""], [heading="<DEFAULT>"])
|
||||||
|
AS_IF([test "$heading" = "no"], [heading="<NONE>"])
|
||||||
|
|
||||||
|
RTC_DATE=$rtc_date
|
||||||
|
AS_IF([test "$rtc_date" = ""], [RTC_DATE="<DEFAULT>"])
|
||||||
|
AS_IF([test "$rtc_date" = "no"], [RTC_DATE="<DEFAULT>"])
|
||||||
|
|
||||||
# Generate all files
|
# Generate all files
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|
||||||
@@ -237,6 +325,7 @@ cat <<EOF
|
|||||||
Exec prefix...........: $eprefix
|
Exec prefix...........: $eprefix
|
||||||
Sysconfdir............: `eval echo $sysconfdir`
|
Sysconfdir............: `eval echo $sysconfdir`
|
||||||
Localstatedir.........: `eval echo $localstatedir`
|
Localstatedir.........: `eval echo $localstatedir`
|
||||||
|
Default fstab.........: `eval echo $fstab`
|
||||||
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
|
Finit plugin path.....: $plugin_path
|
||||||
@@ -249,16 +338,20 @@ cat <<EOF
|
|||||||
Behavior:
|
Behavior:
|
||||||
Boot heading..........: $heading
|
Boot heading..........: $heading
|
||||||
Plugins...............: $plugins
|
Plugins...............: $plugins
|
||||||
|
RTC restore date......: $RTC_DATE
|
||||||
|
|
||||||
Optional features:
|
Optional features:
|
||||||
Install doc/..........: $enable_doc
|
Install doc/..........: $enable_doc
|
||||||
Install contrib/......: $enable_contrib
|
Install contrib/......: $enable_contrib
|
||||||
Built-in watchdogd....: $enable_watchdog
|
Built-in keventd......: $with_keventd
|
||||||
|
Built-in sulogin......: $with_sulogin
|
||||||
|
Built-in watchdogd....: $with_watchdog $watchdog
|
||||||
Built-in logrotate....: $enable_logrotate
|
Built-in logrotate....: $enable_logrotate
|
||||||
Scripting tool logit..: $enable_logit
|
Skip fsck check.......: $enable_fastboot
|
||||||
Emergency shell.......: $enable_emergency_shell
|
Run fsck fix mode.....: $enable_fsckfix
|
||||||
Fallback shell........: $enable_fallback_shell
|
Redirect output.......: $enable_redirect
|
||||||
Default hostname......: $hostname
|
Default hostname......: $hostname
|
||||||
|
Default group.........: $group
|
||||||
Default runlevel......: $runlevel
|
Default runlevel......: $runlevel
|
||||||
|
|
||||||
------------- Compiler version --------------
|
------------- Compiler version --------------
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
SUBDIRS = finit.d
|
SUBDIRS = finit.d
|
||||||
docsdir := @docdir@/contrib/alpine
|
docsdir := @docdir@/contrib/alpine
|
||||||
docs_DATA = README.md finit.conf alpine-release build.sh install.sh rc.local
|
docs_DATA = README.md finit.conf build.sh install.sh rc.local
|
||||||
EXTRA_DIST = $(docs_DATA)
|
EXTRA_DIST = $(docs_DATA)
|
||||||
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
3.6.2
|
|
||||||
@@ -17,8 +17,8 @@ PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig ./configure \
|
|||||||
--prefix=/usr --exec-prefix= \
|
--prefix=/usr --exec-prefix= \
|
||||||
--sysconfdir=/etc --localstatedir=/var \
|
--sysconfdir=/etc --localstatedir=/var \
|
||||||
--enable-dbus-plugin --enable-x11-common-plugin \
|
--enable-dbus-plugin --enable-x11-common-plugin \
|
||||||
--enable-alsa-utils-plugin --enable-watchdog \
|
--enable-alsa-utils-plugin --with-watchdog \
|
||||||
--with-heading="Alpine Linux 3.13"
|
--with-keventd --with-sulogin
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "*** Building ..."
|
echo "*** Building ..."
|
||||||
@@ -35,4 +35,3 @@ fi
|
|||||||
echo
|
echo
|
||||||
echo "*** Done"
|
echo "*** Done"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,22 @@
|
|||||||
# Default is 2
|
# Default is 2
|
||||||
#runlevel 2
|
#runlevel 2
|
||||||
|
|
||||||
|
# Top-level cgroups and their default settings. All groups mandatory
|
||||||
|
# but more can be added, max 8 groups in total currently. The cgroup
|
||||||
|
# 'root' is also available, reserved for RT processes. Settings are
|
||||||
|
# as-is, only one shorthand 'mem.' exists, other than that it's the
|
||||||
|
# cgroup v2 controller default names.
|
||||||
|
#cgroup init cpu.weight:100
|
||||||
|
#cgroup user cpu.weight:100
|
||||||
|
#cgroup system cpu.weight:9700
|
||||||
|
|
||||||
|
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
|
||||||
|
# Finit upon receiving SIGINT (from the kernel).
|
||||||
|
#task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
|
||||||
|
|
||||||
|
# Task to run if the kernel gets a power fail condition is pressed.
|
||||||
|
# Asserted by Finit upon receiving SIGPWR (from the kernel).
|
||||||
|
#task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
|
||||||
|
|
||||||
## Bootstrap services and tasks
|
## Bootstrap services and tasks
|
||||||
# Can be listed here or in /etc/finit.d/*.conf
|
# Can be listed here or in /etc/finit.d/*.conf
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
docsdir := @docdir@/contrib/alpine/finit.d/available
|
docsdir := @docdir@/contrib/alpine/finit.d/available
|
||||||
docs_DATA = acpid.conf crond.conf dropbear.conf getty.conf keymap.conf \
|
docs_DATA = acpid.conf crond.conf dropbear.conf getty.conf keymap.conf \
|
||||||
lxdm.conf modules.conf ntpd.conf klogd.conf syslog.conf \
|
lxdm.conf modules.conf ntpd.conf syslog.conf watchdog.conf
|
||||||
watchdog.conf
|
|
||||||
EXTRA_DIST = $(docs_DATA)
|
EXTRA_DIST = $(docs_DATA)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
# Consoles to start getty on when system is up
|
# Consoles to start getty on when system is up
|
||||||
tty [12345] /dev/tty1 noclear nowait
|
tty [12345] /dev/ttyS0 noclear
|
||||||
tty [2345] /dev/tty2 noclear nowait
|
tty [12345] /dev/tty1 noclear nowait
|
||||||
tty [2345] /dev/tty3 noclear nowait
|
tty [2345] /dev/tty2 noclear nowait
|
||||||
|
tty [2345] /dev/tty3 noclear nowait
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
# Start klogd as soon as possible, after syslogd, should always run
|
|
||||||
service [S12345] <pid/syslogd> env:-/etc/conf.d/klogd klogd -n $KLOGD_OPTS -- Kernel log daemon
|
|
||||||
@@ -4,3 +4,4 @@
|
|||||||
#module evdev
|
#module evdev
|
||||||
#module mousedev
|
#module mousedev
|
||||||
#module 8139cp
|
#module 8139cp
|
||||||
|
module softdog
|
||||||
|
|||||||
@@ -1,2 +1,4 @@
|
|||||||
# Start syslogd as soon as possible, should always run
|
# Start syslogd as soon as possible, should always run
|
||||||
service [S12345] env:-/etc/conf.d/syslog syslogd -n $SYSLOGD_OPTS -- Syslog daemon
|
# Start klogd as soon as possible, but after syslogd
|
||||||
|
service [S12345] env:-/etc/conf.d/syslog syslogd -n $SYSLOGD_OPTS -- Syslog daemon
|
||||||
|
service [S12345] <pid/syslogd> env:-/etc/conf.d/klogd klogd -n $KLOGD_OPTS -- Kernel log daemon
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ if [ "x`id -u`" != "x0" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Adjust base directory
|
# Adjust base directory
|
||||||
if [ -e alpine-release ]; then
|
grep -q alpine Makefile 2>/dev/null
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
cd ../..
|
cd ../..
|
||||||
elif [ ! -e autogen.sh ]; then
|
elif [ ! -e configure.ac ]; then
|
||||||
echo "*** Please run this script from the Finit base directory."
|
echo "*** Please run this script from the Finit base directory."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -4,5 +4,5 @@
|
|||||||
#
|
#
|
||||||
# Each line is run in sequence.
|
# Each line is run in sequence.
|
||||||
#
|
#
|
||||||
# NOTE: Remeber to set the executable bit!
|
# NOTE: Remember to set the executable bit!
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
SUBDIRS = finit.d grub.d
|
SUBDIRS = finit.d
|
||||||
docsdir := @docdir@/contrib/debian
|
docsdir := @docdir@/contrib/debian
|
||||||
docs_DATA = README.md finit.conf os-release build.sh install.sh
|
docs_DATA = README.md finit.conf build.sh install.sh
|
||||||
EXTRA_DIST = $(docs_DATA)
|
EXTRA_DIST = $(docs_DATA)
|
||||||
|
|||||||
@@ -20,29 +20,42 @@ tools pre-systemd work as intended.
|
|||||||
|
|
||||||
root@debian:~# apt install initscripts console-setup
|
root@debian:~# apt install initscripts console-setup
|
||||||
|
|
||||||
|
> **Note:** as of Debian 11 (Bullseye), libuev and libite are part of
|
||||||
|
> the main section of Debian. So just install the -dev packages :)
|
||||||
|
|
||||||
The following script can then be used to configure, build, install and
|
The following script can then be used to configure, build, install and
|
||||||
set up your system to run Finit:
|
set up your system to run Finit:
|
||||||
|
|
||||||
user@debian:~/finit$ contrib/debian/build.sh
|
user@debian:~/finit$ contrib/debian/build.sh
|
||||||
|
|
||||||
However, since `/sbin/init` already exists on your system, the script
|
However, since `/sbin/init` already exists on your system, the script
|
||||||
creates another entry in your GRUB config, in `/etc/grub.d/40_custom`,
|
creates another entry in your GRUB config by updating `$SUPPORTED_INITS`
|
||||||
where `init=/sbin/finit` is added to your kernel line. It is of course
|
in `/etc/grub.d/10_inux` and run `update-grub`. On reboot you will find
|
||||||
also possible to change the default init to Finit, if you do you can
|
a (finit) entry in the "Advanced options for Debian GNU/Linux" section.
|
||||||
remove the custom Grub entry:
|
It is of course also possible to change the default init to Finit:
|
||||||
|
|
||||||
user@debian:~/finit# cd /sbin
|
user@debian:~/finit# cd /sbin
|
||||||
user@debian:/sbin# sudo rm init
|
user@debian:/sbin# sudo mv init oldinit
|
||||||
user@debian:/sbin# sudo ln -s finit init
|
user@debian:/sbin# sudo ln -s finit init
|
||||||
|
|
||||||
Before rebooting, check the default [/etc/finit.conf](finit.conf) and
|
Before rebooting, check the default [/etc/finit.conf](finit.conf) and
|
||||||
`/etc/finit.d/*.conf` files. The build + install script above provides
|
`/etc/finit.d/*.conf` files. The build + install script above provides
|
||||||
a few sample `.conf` files. See `initctl list` after boot for a list of
|
a few sample `.conf` files. See `initctl ls` after boot for a list of
|
||||||
enabled and available services.
|
enabled and available services, you can then use `enable` and `disable`
|
||||||
|
comands to `initctl`, followed by `reload` to activate your changes.
|
||||||
|
|
||||||
You can also use a standard [/etc/rc.local](rc.local) for one-shot tasks
|
You can also use a standard [/etc/rc.local](rc.local) for one-shot tasks
|
||||||
and initialization like keyboard language etc.
|
and initialization like keyboard language etc.
|
||||||
|
|
||||||
|
> **NOTE:** X Window system, you may need to `sudo apt install elogind`
|
||||||
|
> (Bullseye and later), followed by `initctl reload` to activate it (it
|
||||||
|
> is enabled by default), and logout/login again. The elogind daemon
|
||||||
|
> ensures a regular non-root user can start and interact with an X
|
||||||
|
> session, otherwise keyboard and mouse won't work. When you're happy,
|
||||||
|
> you can enable the lightdm.conf, change the default runlevel to 3, and
|
||||||
|
> presto! you have a desktop again.
|
||||||
|
|
||||||
|
|
||||||
Have fun!
|
Have fun!
|
||||||
/Joachim ツ
|
/Joachim ツ
|
||||||
|
|
||||||
|
|||||||
@@ -25,9 +25,8 @@ echo
|
|||||||
--prefix=/usr --exec-prefix= \
|
--prefix=/usr --exec-prefix= \
|
||||||
--sysconfdir=/etc --localstatedir=/var \
|
--sysconfdir=/etc --localstatedir=/var \
|
||||||
--enable-dbus-plugin --enable-x11-common-plugin \
|
--enable-dbus-plugin --enable-x11-common-plugin \
|
||||||
--enable-alsa-utils-plugin \
|
--enable-alsa-utils-plugin --with-keventd \
|
||||||
--with-random-seed=/var/lib/urandom/random-seed \
|
--with-random-seed=/var/lib/urandom/random-seed
|
||||||
--with-heading="Debian GNU/Linux"
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo
|
echo
|
||||||
@@ -60,6 +59,3 @@ else
|
|||||||
echo "*** Use 'sudo contrib/debian/install.sh' later to install Finit"
|
echo "*** Use 'sudo contrib/debian/install.sh' later to install Finit"
|
||||||
echo
|
echo
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,22 @@
|
|||||||
# Default is 2
|
# Default is 2
|
||||||
#runlevel 2
|
#runlevel 2
|
||||||
|
|
||||||
|
# Top-level cgroups and their default settings. All groups mandatory
|
||||||
|
# but more can be added, max 8 groups in total currently. The cgroup
|
||||||
|
# 'root' is also available, reserved for RT processes. Settings are
|
||||||
|
# as-is, only one shorthand 'mem.' exists, other than that it's the
|
||||||
|
# cgroup v2 controller default names.
|
||||||
|
#cgroup init cpu.weight:100
|
||||||
|
#cgroup user cpu.weight:100
|
||||||
|
#cgroup system cpu.weight:9700
|
||||||
|
|
||||||
|
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
|
||||||
|
# Finit upon receiving SIGINT (from the kernel).
|
||||||
|
#task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
|
||||||
|
|
||||||
|
# Task to run if the kernel gets a power fail condition is pressed.
|
||||||
|
# Asserted by Finit upon receiving SIGPWR (from the kernel).
|
||||||
|
#task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
|
||||||
|
|
||||||
## Bootstrap services and tasks
|
## Bootstrap services and tasks
|
||||||
# Can be listed here or in /etc/finit.d/*.conf
|
# Can be listed here or in /etc/finit.d/*.conf
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
SUBDIRS = available
|
SUBDIRS = available
|
||||||
docsdir := @docdir@/contrib/debian/finit.d
|
docsdir := @docdir@/contrib/debian/finit.d
|
||||||
d_LINKS = console-setup.conf getty.conf keyboard-setup.conf \
|
d_LINKS = acpid.conf apparmor.conf avahi-daemon.conf \
|
||||||
modules.conf rsyslogd.conf sshd.conf
|
bluetooth.conf console-setup.conf elogind.conf \
|
||||||
|
getty.conf keyboard-setup.conf modules.conf \
|
||||||
|
plymouth-quit.conf rsyslogd.conf sshd.conf
|
||||||
|
|
||||||
install-exec-hook:
|
install-exec-hook:
|
||||||
@$(MKDIR_P) $(DESTDIR)$(docsdir)/available
|
@$(MKDIR_P) $(DESTDIR)$(docsdir)/available
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
docsdir := @docdir@/contrib/debian/finit.d/available
|
docsdir := @docdir@/contrib/debian/finit.d/available
|
||||||
docs_DATA = acpid.conf console-setup.conf getty.conf keyboard-setup.conf \
|
docs_DATA = acpid.conf apparmor.conf avahi-daemon.conf bluetooth.conf \
|
||||||
lightdm.conf modules.conf rsyslogd.conf sntpd.conf \
|
console-setup.conf elogind.conf getty.conf \
|
||||||
sshd.conf syslogd.conf xdm.conf
|
keyboard-setup.conf lightdm.conf modules.conf sntpd.conf \
|
||||||
|
plymouth-quit.conf rsyslogd.conf sshd.conf syslogd.conf \
|
||||||
|
xdm.conf
|
||||||
EXTRA_DIST = $(docs_DATA)
|
EXTRA_DIST = $(docs_DATA)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
task [2345] <sys/pwr/ac,pid/syslogd> halt:usr1 env:-/etc/default/anacron anacron -d -q $ANACRON_ARGS -- Anacron jobs
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
sysv [S] /etc/init.d/apparmor -- AppArmor initialization
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
service [2345] env:-/etc/default/avahi-daemon avahi-daemon -s $AVAHI_DAEMON_OPTS -- Avahi mDNS/DNS-SD Stack
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# To ignore errors like "org.freedesktop.hostname1", update the env file with
|
||||||
|
# "--noplugin=hostname", i.e. append to BLUETOOTHD_OPTS
|
||||||
|
service [2345] log:null env:-/etc/default/bluetooth /usr/libexec/bluetooth/bluetoothd -n $BLUETOOTHD_OPTS -- Bluetooth service
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
service [2345] <sys/pwr/ac,pid/syslogd> env:-/etc/default/cron cron -f $EXTRA_OPTS -- Background job processing daemon
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# On some systems, bootstrap can be really quick and cause elogind
|
||||||
|
# to not start before a user has managed to log in. To prevent
|
||||||
|
# this, add <pid/elogind> as condition to your TTYs in getty.conf
|
||||||
|
service [2345] <pid/syslogd> /lib/elogind/elogind -- Login manager
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
# Consoles to start getty on when system is up
|
# Consoles to start getty on when system is up
|
||||||
tty [12345] /dev/tty1 linux noclear nowait
|
tty [12345] /dev/tty1 linux noclear nowait
|
||||||
tty [2345] /dev/tty2 linux noclear nowait
|
tty [2345] /dev/tty2 linux nowait
|
||||||
tty [2345] /dev/tty3 linux noclear nowait
|
tty [2345] /dev/tty3 linux nowait
|
||||||
|
tty [2345] /dev/tty4 linux nowait
|
||||||
|
tty [2345] /dev/tty5 linux nowait
|
||||||
|
tty [2345] /dev/tty6 linux nowait
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# Need to stop plymouth, or it'll block stdin on tty1
|
||||||
|
task [S] /usr/bin/plymouth quit -- Stopping Plymouth Boot Screen
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
exec tail -n +3 $0
|
|
||||||
# This file provides an easy way to add custom menu entries. Simply type the
|
|
||||||
# menu entries you want to add after this comment. Be careful not to change
|
|
||||||
# the 'exec tail' line above.
|
|
||||||
|
|
||||||
menuentry '$MENU with Finit' --class $TYPE --class gnu-linux --class gnu --class os --user {
|
|
||||||
insmod gzio
|
|
||||||
insmod part_msdos
|
|
||||||
insmod ext2
|
|
||||||
search --no-floppy --fs-uuid --set=root $BOOT
|
|
||||||
linux /vmlinuz root=UUID=$ROOT ro quiet init=/sbin/finit
|
|
||||||
initrd /initrd.img
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
docsdir := @docdir@/contrib/debian/grub.d
|
|
||||||
docs_DATA = 40_custom
|
|
||||||
EXTRA_DIST = $(docs_DATA)
|
|
||||||
@@ -8,10 +8,10 @@ if [ "x`id -u`" != "x0" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Adjust base directory
|
# Adjust base directory
|
||||||
grep -q Debian os-release 2>/dev/null
|
grep -q debian Makefile 2>/dev/null
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
cd ../..
|
cd ../..
|
||||||
elif [ ! -e autogen.sh ]; then
|
elif [ ! -e configure.ac ]; then
|
||||||
echo "*** Please run this script from the Finit base directory."
|
echo "*** Please run this script from the Finit base directory."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@@ -23,7 +23,7 @@ echo "/sbin/finit - PID 1"
|
|||||||
echo "/lib/finit/plugins/* - All enabled Finit plugins"
|
echo "/lib/finit/plugins/* - All enabled Finit plugins"
|
||||||
echo "/etc/finit.conf - Finit configuration file"
|
echo "/etc/finit.conf - Finit configuration file"
|
||||||
echo "/etc/finit.d/ - Finit services"
|
echo "/etc/finit.d/ - Finit services"
|
||||||
echo "/etc/grub.d/40_custom - Add menu entry to the Grub boot loader"
|
echo "/etc/grub.d/10_linux - Add Finit to Grub's SUPPORTED_INITS"
|
||||||
echo
|
echo
|
||||||
read -p "Do you want to continue (y/N)? " yorn
|
read -p "Do you want to continue (y/N)? " yorn
|
||||||
echo
|
echo
|
||||||
@@ -38,12 +38,18 @@ if [ "x$yorn" = "xy" -o "x$yorn" = "xY" ]; then
|
|||||||
cp -va finit.d /etc/
|
cp -va finit.d /etc/
|
||||||
|
|
||||||
echo "*** Setting up a GRUB boot entry ..."
|
echo "*** Setting up a GRUB boot entry ..."
|
||||||
MENU=`grep gnu-linux /boot/grub/grub.cfg |head -1 |sed "s/menuentry '\([^']*\).*/\1/"`
|
fn=/etc/grub.d/10_linux
|
||||||
TYPE=`grep gnu-linux /boot/grub/grub.cfg |head -1 |sed "s/.*' --class \([a-z]*\).*/\1/"`
|
if [ -e $fn ]; then
|
||||||
BOOT=`grep set=root /boot/grub/grub.cfg |head -1 |sed 's/.* \([a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*\).*/\1/'`
|
if `grep SUPPORTED_INITS $fn |head -1 |grep -q finit`; then
|
||||||
ROOT=`grep root=UUID /boot/grub/grub.cfg |head -1 |sed 's/.*UUID=\([a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*\).*/\1/'`
|
echo "Already installed, done."
|
||||||
cat grub.d/40_custom | sed "s,\$BOOT,$BOOT,;s,\$ROOT,$ROOT,;s,\$TYPE,$TYPE,;s,\$MENU,$MENU," >/etc/grub.d/40_custom
|
else
|
||||||
update-grub
|
echo "Adding Finit to list of SUPPORTED_INITS ..."
|
||||||
|
sed -i 's/SUPPORTED_INITS="[^"]*/& finit:\/sbin\/finit/' $fn
|
||||||
|
update-grub
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Cannot find $fn, you'll have to set up your bootloader on your own."
|
||||||
|
fi
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "*** Done"
|
echo "*** Done"
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
PRETTY_NAME="Debian GNU/Linux 8 (jessie)"
|
|
||||||
NAME="Debian GNU/Linux"
|
|
||||||
VERSION_ID="8"
|
|
||||||
VERSION="8 (jessie)"
|
|
||||||
ID=debian
|
|
||||||
HOME_URL="http://www.debian.org/"
|
|
||||||
SUPPORT_URL="http://www.debian.org/support"
|
|
||||||
BUG_REPORT_URL="https://bugs.debian.org/"
|
|
||||||
+37
-2
@@ -8,6 +8,18 @@ module evdev
|
|||||||
module loop
|
module loop
|
||||||
module psmouse
|
module psmouse
|
||||||
|
|
||||||
|
# Top-level cgroups and their default settings. All groups mandatory
|
||||||
|
# but more can be added, max 8 groups in total currently. The cgroup
|
||||||
|
# 'root' is also available, reserved for RT processes. Settings are
|
||||||
|
# as-is, only one shorthand 'mem.' exists, other than that it's the
|
||||||
|
# cgroup v2 controller default names.
|
||||||
|
cgroup init cpu.weight:100
|
||||||
|
cgroup user cpu.weight:100
|
||||||
|
cgroup system cpu.weight:9700 cpu.max:50000
|
||||||
|
|
||||||
|
# Example extra cgroup
|
||||||
|
cgroup maint cpu.weight:100
|
||||||
|
|
||||||
# Runlevel to start after bootstrap, runlevel 'S'
|
# Runlevel to start after bootstrap, runlevel 'S'
|
||||||
runlevel 2
|
runlevel 2
|
||||||
|
|
||||||
@@ -16,13 +28,21 @@ network service networking start
|
|||||||
|
|
||||||
# Max file size for each log file: 100 kiB, rotate max 4 copies:
|
# Max file size for each log file: 100 kiB, rotate max 4 copies:
|
||||||
# log => log.1 => log.2.gz => log.3.gz => log.4.gz
|
# log => log.1 => log.2.gz => log.3.gz => log.4.gz
|
||||||
log size=100k count=4
|
log size:100k count:4
|
||||||
|
|
||||||
# Virtual consoles to start getty on
|
# Virtual consoles to start getty on
|
||||||
tty /dev/tty1
|
tty /dev/tty1
|
||||||
tty /dev/tty2
|
tty /dev/tty2
|
||||||
tty /dev/tty3
|
tty /dev/tty3
|
||||||
|
|
||||||
|
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
|
||||||
|
# Finit upon receiving SIGINT (from the kernel).
|
||||||
|
task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
|
||||||
|
|
||||||
|
# Task to run if the kernel gets a power fail condition is pressed.
|
||||||
|
# Asserted by Finit upon receiving SIGPWR (from the kernel).
|
||||||
|
task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
|
||||||
|
|
||||||
# Alternative method instead of runparts
|
# Alternative method instead of runparts
|
||||||
#task [S] /etc/init.d/keyboard-setup start -- Setting up preliminary keymap
|
#task [S] /etc/init.d/keyboard-setup start -- Setting up preliminary keymap
|
||||||
#task [S] /etc/init.d/acpid start -- Starting ACPI Daemon
|
#task [S] /etc/init.d/acpid start -- Starting ACPI Daemon
|
||||||
@@ -30,9 +50,24 @@ tty /dev/tty3
|
|||||||
#run [2] /etc/init.d/networking start -- Start networking
|
#run [2] /etc/init.d/networking start -- Start networking
|
||||||
|
|
||||||
# Services to be monitored and respawned as needed
|
# Services to be monitored and respawned as needed
|
||||||
|
|
||||||
|
# klgod and syslogd are placed in the maint cgroup
|
||||||
|
cgroup.maint
|
||||||
service [2345] <pid/syslogd> klogd -n -- Kernel logging server
|
service [2345] <pid/syslogd> klogd -n -- Kernel logging server
|
||||||
service [2345] syslogd -n -- Syslog server
|
service [2345] syslogd -n -- Syslog server
|
||||||
service [3] gdm -- GNOME Display Manager
|
|
||||||
|
# gdm in the system cgroup (default when read from it's own .conf file)
|
||||||
|
cgroup.system
|
||||||
|
service [3] cgroup:cpu.weight:250,mem.max:10M gdm -- GNOME Display Manager
|
||||||
|
|
||||||
|
# Start SSH daemon with opts from /etc/default/ssh (if available), move
|
||||||
|
# to user cgroup with cpu.weight:250. Default for services is system
|
||||||
|
# group. Default weight in user group is 100 (above). Max length of
|
||||||
|
# cgroup argument is (currently) 63 chars.
|
||||||
|
#
|
||||||
|
# Notice alternative syntax where current cgroup is only set for this
|
||||||
|
# particular service.
|
||||||
|
service [2345] cgroup.user:cpu.weight:250,mem.max:10M env:-/etc/default/ssh /usr/sbin/sshd -D $SSHD_OPTS -- OpenSSH daemon
|
||||||
|
|
||||||
# The BusyBox ntpd does not use syslog when running in the foreground
|
# The BusyBox ntpd does not use syslog when running in the foreground
|
||||||
# So we use this trick to redirect stdout/stderr to a log file. The
|
# So we use this trick to redirect stdout/stderr to a log file. The
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
In Finit issue #196 we were reminded [1] of a missing inotify flag in
|
||||||
|
Linux older kernels, IN_MASK_CREATE. Finit makes use of this internally
|
||||||
|
for monitoring PID conditions, and more. This is a central mechanism to
|
||||||
|
synchronize services at boot and reload at runtime.
|
||||||
|
|
||||||
|
The following patch for Linux 4.9.0, was provided by Andy Savage for
|
||||||
|
other people that may want to run Finit on slightly older kernels.
|
||||||
|
|
||||||
|
[1]: https://github.com/troglobit/finit/issues/196
|
||||||
|
|
||||||
|
Index: fs/notify/inotify/inotify_user.c
|
||||||
|
===================================================================
|
||||||
|
--- fs.orig/notify/inotify/inotify_user.c
|
||||||
|
+++ fs/notify/inotify/inotify_user.c
|
||||||
|
@@ -522,6 +522,7 @@ static int inotify_update_existing_watch
|
||||||
|
__u32 old_mask, new_mask;
|
||||||
|
__u32 mask;
|
||||||
|
int add = (arg & IN_MASK_ADD);
|
||||||
|
+ int create = (arg & IN_MASK_CREATE);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mask = inotify_arg_to_mask(arg);
|
||||||
|
@@ -529,6 +530,8 @@ static int inotify_update_existing_watch
|
||||||
|
fsn_mark = fsnotify_find_inode_mark(group, inode);
|
||||||
|
if (!fsn_mark)
|
||||||
|
return -ENOENT;
|
||||||
|
+ else if (create)
|
||||||
|
+ return -EEXIST;
|
||||||
|
|
||||||
|
i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);
|
||||||
|
|
||||||
|
@@ -726,6 +729,10 @@ SYSCALL_DEFINE3(inotify_add_watch, int,
|
||||||
|
if (unlikely(!f.file))
|
||||||
|
return -EBADF;
|
||||||
|
|
||||||
|
+ /* IN_MASK_ADD and IN_MASK_CREATE don't make sense together */
|
||||||
|
+ if (unlikely((mask & IN_MASK_ADD) && (mask & IN_MASK_CREATE)))
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
/* verify that this is indeed an inotify instance */
|
||||||
|
if (unlikely(f.file->f_op != &inotify_fops)) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
@@ -814,7 +821,7 @@ static int __init inotify_user_setup(voi
|
||||||
|
BUILD_BUG_ON(IN_ISDIR != FS_ISDIR);
|
||||||
|
BUILD_BUG_ON(IN_ONESHOT != FS_IN_ONESHOT);
|
||||||
|
|
||||||
|
- BUG_ON(hweight32(ALL_INOTIFY_BITS) != 21);
|
||||||
|
+ BUG_ON(hweight32(ALL_INOTIFY_BITS) != 22);
|
||||||
|
|
||||||
|
inotify_inode_mark_cachep = KMEM_CACHE(inotify_inode_mark, SLAB_PANIC);
|
||||||
|
|
||||||
|
Index: include/linux/inotify.h
|
||||||
|
===================================================================
|
||||||
|
--- include.orig/linux/inotify.h
|
||||||
|
+++ include/linux/inotify.h
|
||||||
|
@@ -17,6 +17,6 @@ extern struct ctl_table inotify_table[];
|
||||||
|
IN_DELETE_SELF | IN_MOVE_SELF | IN_UNMOUNT | \
|
||||||
|
IN_Q_OVERFLOW | IN_IGNORED | IN_ONLYDIR | \
|
||||||
|
IN_DONT_FOLLOW | IN_EXCL_UNLINK | IN_MASK_ADD | \
|
||||||
|
- IN_ISDIR | IN_ONESHOT)
|
||||||
|
+ IN_MASK_CREATE | IN_ISDIR | IN_ONESHOT)
|
||||||
|
|
||||||
|
#endif /* _LINUX_INOTIFY_H */
|
||||||
|
Index: include/uapi/linux/inotify.h
|
||||||
|
===================================================================
|
||||||
|
--- include.orig/uapi/linux/inotify.h
|
||||||
|
+++ include/uapi/linux/inotify.h
|
||||||
|
@@ -52,6 +52,7 @@ struct inotify_event {
|
||||||
|
#define IN_ONLYDIR 0x01000000 /* only watch the path if it is a directory */
|
||||||
|
#define IN_DONT_FOLLOW 0x02000000 /* don't follow a sym link */
|
||||||
|
#define IN_EXCL_UNLINK 0x04000000 /* exclude events on unlinked objects */
|
||||||
|
+#define IN_MASK_CREATE 0x10000000 /* only create watches */
|
||||||
|
#define IN_MASK_ADD 0x20000000 /* add to the mask of an already existing watch */
|
||||||
|
#define IN_ISDIR 0x40000000 /* event occurred against dir */
|
||||||
|
#define IN_ONESHOT 0x80000000 /* only send event once */
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
SUBDIRS = finit.d
|
SUBDIRS = finit.d
|
||||||
docsdir := @docdir@/contrib/void
|
docsdir := @docdir@/contrib/void
|
||||||
docs_DATA = README.md finit.conf build.sh install.sh rc.local xbps
|
docs_DATA = README.md finit.conf build.sh install.sh rc.local
|
||||||
EXTRA_DIST = $(docs_DATA)
|
EXTRA_DIST = $(docs_DATA)
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig ./configure \
|
|||||||
--prefix=/usr --exec-prefix= \
|
--prefix=/usr --exec-prefix= \
|
||||||
--sysconfdir=/etc --localstatedir=/var \
|
--sysconfdir=/etc --localstatedir=/var \
|
||||||
--enable-dbus-plugin --enable-x11-common-plugin \
|
--enable-dbus-plugin --enable-x11-common-plugin \
|
||||||
--enable-alsa-utils-plugin --enable-watchdog \
|
--enable-alsa-utils-plugin --with-watchdog \
|
||||||
--with-heading="Void Linux"
|
--with-keventd --with-sulogin
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "*** Building ..."
|
echo "*** Building ..."
|
||||||
@@ -35,4 +35,3 @@ fi
|
|||||||
echo
|
echo
|
||||||
echo "*** Done"
|
echo "*** Done"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
|
|||||||
@@ -5,5 +5,22 @@
|
|||||||
# Default is 2
|
# Default is 2
|
||||||
#runlevel 2
|
#runlevel 2
|
||||||
|
|
||||||
|
# Top-level cgroups and their default settings. All groups mandatory
|
||||||
|
# but more can be added, max 8 groups in total currently. The cgroup
|
||||||
|
# 'root' is also available, reserved for RT processes. Settings are
|
||||||
|
# as-is, only one shorthand 'mem.' exists, other than that it's the
|
||||||
|
# cgroup v2 controller default names.
|
||||||
|
#cgroup init cpu.weight:100
|
||||||
|
#cgroup user cpu.weight:100
|
||||||
|
#cgroup system cpu.weight:9700
|
||||||
|
|
||||||
|
# Task to run if ctrl-alt-del is pressed. This condition is asserted by
|
||||||
|
# Finit upon receiving SIGINT (from the kernel).
|
||||||
|
#task <sys/key/ctrlaltdel> [12345789] initctl reboot -- Rebooting system
|
||||||
|
|
||||||
|
# Task to run if the kernel gets a power fail condition is pressed.
|
||||||
|
# Asserted by Finit upon receiving SIGPWR (from the kernel).
|
||||||
|
#task <sys/pwr/fail> [12345789] initctl poweroff -- Shutting down system
|
||||||
|
|
||||||
## Bootstrap services and tasks
|
## Bootstrap services and tasks
|
||||||
# Can be listed here or in /etc/finit.d/*.conf
|
# Can be listed here or in /etc/finit.d/*.conf
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
docsdir := @docdir@/contrib/void/finit.d/available
|
docsdir := @docdir@/contrib/void/finit.d/available
|
||||||
docs_DATA = acpid.conf crond.conf dhcpcd.conf dmeventd.conf getty.conf \
|
docs_DATA = acpid.conf crond.conf dhcpcd.conf dmeventd.conf getty.conf \
|
||||||
keymap.conf klogd.conf lxdm.conf modules.conf ntpd.conf \
|
keymap.conf lxdm.conf modules.conf ntpd.conf \
|
||||||
sshd.conf syslogd.conf uuidd.conf
|
sshd.conf syslog.conf uuidd.conf
|
||||||
EXTRA_DIST = $(docs_DATA)
|
EXTRA_DIST = $(docs_DATA)
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
# Start klogd as soon as possible, should always run
|
|
||||||
service [S12345] <pid/syslogd> klogd -n -- Kernel log daemon
|
|
||||||
@@ -4,3 +4,4 @@
|
|||||||
#module evdev
|
#module evdev
|
||||||
#module mousedev
|
#module mousedev
|
||||||
#module 8139cp
|
#module 8139cp
|
||||||
|
module softdog
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# Start syslogd as soon as possible, should always run
|
||||||
|
# Start klogd as soon as possible, but after syslogd
|
||||||
|
service [S12345] syslogd -n -- Syslog daemon
|
||||||
|
service [S12345] <pid/syslogd> klogd -n -- Kernel log daemon
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
# Start syslogd as soon as possible, should always run
|
|
||||||
service [S12345] syslogd -n -- Syslog daemon
|
|
||||||
@@ -8,9 +8,10 @@ if [ "x`id -u`" != "x0" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Adjust base directory
|
# Adjust base directory
|
||||||
if [ -e xbps ]; then
|
grep -q void Makefile 2>/dev/null
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
cd ../..
|
cd ../..
|
||||||
elif [ ! -e autogen.sh ]; then
|
elif [ ! -e configure.ac ]; then
|
||||||
echo "*** Please run this script from the Finit base directory."
|
echo "*** Please run this script from the Finit base directory."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -4,4 +4,4 @@
|
|||||||
#
|
#
|
||||||
# Each line is run in sequence.
|
# Each line is run in sequence.
|
||||||
#
|
#
|
||||||
# NOTE: Remeber to set the executable bit!
|
# NOTE: Remember to set the executable bit!
|
||||||
|
|||||||
+18
-6
@@ -19,19 +19,31 @@ Some of these are also registered in the issue tracker on GitHub.
|
|||||||
* Add new (complimentary) .svc file format to slowly migrate away
|
* Add new (complimentary) .svc file format to slowly migrate away
|
||||||
from the very terse one-liner format currently used
|
from the very terse one-liner format currently used
|
||||||
* Allow running as non-pid1 => read .conf and RCSD form cmdline
|
* Allow running as non-pid1 => read .conf and RCSD form cmdline
|
||||||
* When a process dies, and Finit does not restart it, we should collect
|
|
||||||
a `siginfo_t` from the SIGCHLD signal and supply to the user in case
|
|
||||||
`initctl status <process>` is called to debug the issue.
|
|
||||||
* Add `finit.conf` support for UPS notification (SIGPWR) to start a task
|
* Add `finit.conf` support for UPS notification (SIGPWR) to start a task
|
||||||
using, e.g. <sys/power/{ok,fail,low}> conditions. More info in sig.c
|
using, e.g. <sys/power/{ok,fail,low}> conditions. More info in sig.c
|
||||||
|
|
||||||
|
As of Finit v4.1 SIGPWR generates <sys/power/fail> condition and it
|
||||||
|
is up to a task to check why and take appropriate action.
|
||||||
* Add `finit.conf` support for ctrl-alt-delete (SIGINT) and kbrequest,
|
* Add `finit.conf` support for ctrl-alt-delete (SIGINT) and kbrequest,
|
||||||
i.e. KeyboardSignal, (SIGWINCH) behavior. Using conditions to a task,
|
i.e. KeyboardSignal, (SIGWINCH) behavior. Using conditions to a task,
|
||||||
e.g, <sys/key/ctrlaltdel> and <sys/key/signal> like SIGPWR handling.
|
e.g, <sys/key/ctrlaltdel> and <sys/key/signal> like SIGPWR handling.
|
||||||
* Write man pages for finit and `finit.conf`, steal from the excellent
|
|
||||||
`pimd` man pages ...
|
As of Finit v4.1 SIGINT generates <sys/key/ctrlaltdel>, but there is
|
||||||
* Add support for timed shutdown in Finit, including cancelled shutdown
|
no check if the signal actually originates from the kernel. To get
|
||||||
|
this verification, a new libuEv release is needed. As of June 6 -21
|
||||||
|
that functionality is not yet released.
|
||||||
|
|
||||||
|
|
||||||
|
Initctl
|
||||||
|
-------
|
||||||
|
|
||||||
|
* Add support for timed shutdown in Finit, including cancelled shutdown:
|
||||||
|
|
||||||
|
shutdown -h 03:35 "foobar was here"
|
||||||
|
|
||||||
* Add support for JSON output, or similar, from `initctl show`, e.g.
|
* Add support for JSON output, or similar, from `initctl show`, e.g.
|
||||||
`initctl show --json`
|
`initctl show --json`
|
||||||
|
* Add support for `-s` to redirect all output to syslog, for scripting
|
||||||
|
|
||||||
|
|
||||||
Init
|
Init
|
||||||
|
|||||||
+17
-14
@@ -1,6 +1,8 @@
|
|||||||
Bootstrap
|
Bootstrap
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
0. Get bearings, disable kernel logs, initialize TTY and print banner,
|
||||||
|
unless `HOOK_BANNER` is defined, then call that instead
|
||||||
1. Prepare emergency shell, if enabled
|
1. Prepare emergency shell, if enabled
|
||||||
2. Set up initial signal handlers
|
2. Set up initial signal handlers
|
||||||
3. Set up default $PATH early
|
3. Set up default $PATH early
|
||||||
@@ -9,12 +11,16 @@ Bootstrap
|
|||||||
6. Load all `.so` plugins
|
6. Load all `.so` plugins
|
||||||
7. Call `fsck` on file systems listed in `/etc/fstab`
|
7. Call `fsck` on file systems listed in `/etc/fstab`
|
||||||
8. Populate `/dev` using either udev or mdev, depending on system type
|
8. Populate `/dev` using either udev or mdev, depending on system type
|
||||||
9. Parse `/etc/finit.conf` and all `/etc/finit.d/*.conf` files
|
9. Parse `/etc/finit.conf`
|
||||||
10. Start built-in watchdog, if enabled
|
10. Start built-in watchdog, if enabled and `WDT_DEVNODE` exists. This
|
||||||
11. Set hostname
|
means any WDT that requires a kernel module need to be either
|
||||||
|
compiled into the kernel, or insmod'ed in `/etc/finit.conf`
|
||||||
|
11. Load all `/etc/finit.d/*.conf` files and set hostname
|
||||||
12. Remount `/` read-write if `/` is listed in `/etc/fstab` without `ro`
|
12. Remount `/` read-write if `/` is listed in `/etc/fstab` without `ro`
|
||||||
13. Call 1st level hooks, `HOOK_ROOTFS_UP`
|
13. Call 1st level hooks, `HOOK_ROOTFS_UP`
|
||||||
14. Mount all file systems listed in `/etc/fstab` and swap, if available
|
14. Mount all file systems listed in `/etc/fstab` and swap, if available.
|
||||||
|
On mount error `HOOK_MOUNT_ERROR` is called. After mount, regardless
|
||||||
|
of error, `HOOK_MOUNT_POST` is called
|
||||||
15. Enable SysV init signals
|
15. Enable SysV init signals
|
||||||
16. Call 2nd level hooks, `HOOK_BASEFS_UP`
|
16. Call 2nd level hooks, `HOOK_BASEFS_UP`
|
||||||
17. Cleanup stale files from `/tmp/*` et al, handled by `bootmisc` plugin
|
17. Cleanup stale files from `/tmp/*` et al, handled by `bootmisc` plugin
|
||||||
@@ -34,18 +40,15 @@ Bootstrap
|
|||||||
24. Call 4th level hooks, `HOOK_SVC_UP`
|
24. Call 4th level hooks, `HOOK_SVC_UP`
|
||||||
25. Call `/etc/rc.local`, if it exists and is an executable shell script
|
25. Call `/etc/rc.local`, if it exists and is an executable shell script
|
||||||
26. Call 5th level (last) hooks, `HOOK_SYSTEM_UP`
|
26. Call 5th level (last) hooks, `HOOK_SYSTEM_UP`
|
||||||
27. Start all configured TTYs, or a fallback shell on `/dev/console`
|
27. Start all configured TTYs
|
||||||
|
|
||||||
In (19) and (22) tasks and services defined in `/etc/finit.conf` and
|
In (19) and (23) tasks and services defined in `/etc/finit.conf` and
|
||||||
`/etc/sysctl.d/*.conf` are started. Remember, all `service` and `task`
|
`/etc/finit.d/*.conf` are started.
|
||||||
stanzas are started in parallel and `run` in sequence, and in the order
|
|
||||||
listed. Hence, to emulate a SysV `/etc/init.d/rcS` one could write a
|
|
||||||
long `finit.conf` with only `run` statements.
|
|
||||||
|
|
||||||
Notice the five hook points that are called at various point in the
|
Notice the seven hook points that are called at various point in the
|
||||||
bootstrap process. This is where plugins can extend the boot in any way
|
bootstrap process. This is where plugins can extend the boot in any
|
||||||
they please. There are other hook points, e.g. `HOOK_MOUNT_ERROR`, for
|
way they please. There are other hook points available, for more on
|
||||||
more on this see [plugins.md](plugins.md).
|
this, see [plugins.md](plugins.md).
|
||||||
|
|
||||||
For instance, at `HOOK_BASEFS_UP` a plugin could read an XML file from a
|
For instance, at `HOOK_BASEFS_UP` a plugin could read an XML file from a
|
||||||
USB stick, convert/copy its contents to the system's `/etc/` directory,
|
USB stick, convert/copy its contents to the system's `/etc/` directory,
|
||||||
|
|||||||
+43
-20
@@ -27,10 +27,10 @@ optional plugins to enable. It depends on two external libraries:
|
|||||||
PKG_CONFIG_LIBDIR=/usr/local/lib/pkgconfig ./configure
|
PKG_CONFIG_LIBDIR=/usr/local/lib/pkgconfig ./configure
|
||||||
|
|
||||||
The configure script checks for all dependencies, including the correct
|
The configure script checks for all dependencies, including the correct
|
||||||
version of the above mentioned libraries. Currently requried versions:
|
version of the above mentioned libraries. Currently required versions:
|
||||||
|
|
||||||
- libite v2.2.0
|
- libite v2.2.0, or later
|
||||||
- libuEv v2.2.0
|
- libuEv v2.2.0, or later
|
||||||
|
|
||||||
|
|
||||||
Configure
|
Configure
|
||||||
@@ -53,6 +53,10 @@ Below are a few of the main switches to configure:
|
|||||||
built-ins (.o files) and all external libraries, except the C library
|
built-ins (.o files) and all external libraries, except the C library
|
||||||
will be linked statically.
|
will be linked statically.
|
||||||
|
|
||||||
|
* `--enable-kernel-cmdline`: Enable Finit pre-4.1 parsing of init args from
|
||||||
|
`/proc/cmdline`, this is *not recommended* since Finit may be running as the
|
||||||
|
init for container apps that can see the host's `/proc` filesystem
|
||||||
|
|
||||||
* `--enable-alsa-utils-plugin`: Enable the optional `alsa-utils.so` sound plugin.
|
* `--enable-alsa-utils-plugin`: Enable the optional `alsa-utils.so` sound plugin.
|
||||||
|
|
||||||
* `--enable-dbus-plugin`: Enable the optional D-Bus `dbus.so` plugin.
|
* `--enable-dbus-plugin`: Enable the optional D-Bus `dbus.so` plugin.
|
||||||
@@ -61,8 +65,19 @@ Below are a few of the main switches to configure:
|
|||||||
|
|
||||||
* `--enable-x11-common-plugin`: Enable the optional X Window `x11-common.so` plugin.
|
* `--enable-x11-common-plugin`: Enable the optional X Window `x11-common.so` plugin.
|
||||||
|
|
||||||
|
* `--with-sulogin`: Enable bundled `sulogin` program. Default is to use the
|
||||||
|
system `sulogin(8)`. The sulogin shipped with Finit *allows password-less*
|
||||||
|
login if the `root` user is disabled or has no password at all.
|
||||||
|
|
||||||
For more configure flags, see <kbd>./configure --help</kbd>
|
For more configure flags, see <kbd>./configure --help</kbd>
|
||||||
|
|
||||||
|
> **Note:** the configure script is not available in the GIT sources. It is
|
||||||
|
> however included in (officially supported) released tarballs. The
|
||||||
|
> idea is that you should not need GNU autotools to build, only the
|
||||||
|
> above mentioned dependencies, a POSIX shell, a C compiler and make.
|
||||||
|
> Any contributing to Finit can generate it from `configure.ac` using
|
||||||
|
> the `autogen.sh` script.
|
||||||
|
|
||||||
|
|
||||||
Example
|
Example
|
||||||
-------
|
-------
|
||||||
@@ -70,16 +85,16 @@ Example
|
|||||||
First, unpack the archive:
|
First, unpack the archive:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ tar xf finit-3.0.tar.xz
|
$ tar xf finit-4.3.tar.gz
|
||||||
$ cd finit-3.0/
|
$ cd finit-4.3/
|
||||||
```
|
```
|
||||||
|
|
||||||
Then configure, build and install:
|
Then configure, build and install:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ ./configure --prefix=/usr --exec-prefix= \
|
$ ./configure --prefix=/usr --exec-prefix= \
|
||||||
--sysconfdir=/etc --localstatedir=/var \
|
--sysconfdir=/etc --localstatedir=/var \
|
||||||
--with-heading="Alpine Linux 3.13" --with-hostname=alpine
|
--with-keventd --with-watchdog
|
||||||
$ make
|
$ make
|
||||||
.
|
.
|
||||||
.
|
.
|
||||||
@@ -87,13 +102,13 @@ $ make
|
|||||||
$ DESTDIR=/tmp/finit make install
|
$ DESTDIR=/tmp/finit make install
|
||||||
```
|
```
|
||||||
|
|
||||||
In this example the [finit-3.0.tar.xz][1] archive is unpacked to the
|
In this example the [finit-4.3.tar.gz][1] archive is unpacked to the
|
||||||
user's home directory, configured, built and installed to a temporary
|
user's home directory, configured, built and installed to a temporary
|
||||||
staging directory. The environment variable `DESTDIR` controls the
|
staging directory. The environment variable `DESTDIR` controls the
|
||||||
destination directory when installing, very useful for building binary
|
destination directory when installing, very useful for building binary
|
||||||
standalone packages.
|
standalone packages.
|
||||||
|
|
||||||
Finit 3.0 and later can detect if it runs on an embedded system, or a
|
Finit 4.1 and later can detect if it runs on an embedded system, or a
|
||||||
system that use BusyBox tools instead of udev & C:o. On such systems
|
system that use BusyBox tools instead of udev & C:o. On such systems
|
||||||
`mdev` instead of `udev` is used. However, remember to also change the
|
`mdev` instead of `udev` is used. However, remember to also change the
|
||||||
Linux config to:
|
Linux config to:
|
||||||
@@ -142,32 +157,40 @@ enabled. The default Finit rescue mode configuration is installed into
|
|||||||
|
|
||||||
By default the a root shell, without login, is started.
|
By default the a root shell, without login, is started.
|
||||||
|
|
||||||
|
> **Note:** in this mode `initctl` will not work. Use the `-f` flag to
|
||||||
|
> force `reboot`, `shutdown`, or `poweroff`.
|
||||||
|
|
||||||
|
|
||||||
Debugging
|
Debugging
|
||||||
---------
|
---------
|
||||||
|
|
||||||
Edit, or append to, the kernel command line: remove `quiet` to enable
|
Edit, or append to, the kernel command line: remove `quiet` to enable
|
||||||
kernel messages and add `debug` to enable Finit debug messages.
|
kernel messages and add `finit.debug` to enable Finit debug messages.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
append="init=/sbin/finit debug"
|
append="init=/sbin/finit -- finit.debug"
|
||||||
```
|
```
|
||||||
|
|
||||||
To debug startup issues, in particular issues with getty/login, try
|
Notice the `--` separator.
|
||||||
`configure --enable-fallback-shell`. When no TTYs are detected, and
|
|
||||||
Finit is configured with this option, Finit will try to start a bare
|
To debug startup issues, in particular issues with getty/login, add
|
||||||
`/bin/sh` on the boot console. Remember, this is only for debugging
|
the following to your Finit .conf file:
|
||||||
and would leave your production system potentially wide open.
|
|
||||||
|
tty [12345789] notty noclear
|
||||||
|
|
||||||
|
The `notty` option ensures reusing the stdin/stdout set up by the
|
||||||
|
kernel. Remember, this is only for debugging and would leave your
|
||||||
|
production system potentially wide open.
|
||||||
|
|
||||||
There is also a rescue shell available, in case Finit crashes and the
|
There is also a rescue shell available, in case Finit crashes and the
|
||||||
kernel usually reboots: `configure --enable-emergency-shell`. However,
|
kernel usually reboots: `configure --enable-emergency-shell`. However,
|
||||||
the behavior of Finit is severely limited when this is enabled, so use
|
the behavior of Finit is severely limited when this is enabled, so use
|
||||||
it only for debugging start up issues when Finit crashes.
|
it only for debugging start up issues when Finit crashes.
|
||||||
|
|
||||||
**NOTE:** Neither of these two configure options should be enabled on
|
**NOTE:** Neither of these options should be enabled on production
|
||||||
production systems since they can potentially give a user root access.
|
systems since they can potentially give a user root access.
|
||||||
|
|
||||||
|
|
||||||
[1]: ftp://troglobit.com/finit/finit-3.0.tar.xz
|
[1]: ftp://troglobit.com/finit/finit-4.3.tar.gz
|
||||||
[libuEv]: https://github.com/troglobit/libuev
|
[libuEv]: https://github.com/troglobit/libuev
|
||||||
[libite]: https://github.com/troglobit/libite
|
[libite]: https://github.com/troglobit/libite
|
||||||
|
|||||||
+70
-10
@@ -6,15 +6,57 @@ passed on the Linux kernel command line. Not limited to Finit.
|
|||||||
|
|
||||||
The `bool` setting is one of `on, off, true false, 1, 0`.
|
The `bool` setting is one of `on, off, true false, 1, 0`.
|
||||||
|
|
||||||
|
> **NOTE:** remember to use `--` to separate kernel parameters from
|
||||||
|
> parameters to init. E.g., `init=/sbin/finit -- finit.debug rescue`
|
||||||
|
|
||||||
* `debug`: Enable kernel debug. Debug messages are printed to the
|
* `debug`: Enable kernel debug. Debug messages are printed to the
|
||||||
console until Finit starts up.
|
console until Finit starts up, unless `loglevel=7` (below) is used.
|
||||||
|
|
||||||
|
* `finit.cond=foo[,bar[,baz]]`: set `<boot/foo>` condition, optionally
|
||||||
|
multiple conditions can be set using the same option, separated with a
|
||||||
|
comma. Alternatively, multiple `foo.cond=arg` can be given. Each will
|
||||||
|
result in a `<boot/arg>` condition being set to control the rest of the
|
||||||
|
system bootstrap.
|
||||||
|
|
||||||
|
Very useful for selecting different boot modes, e.g. manufacturing test,
|
||||||
|
firmware upgrade, or rescue mode.
|
||||||
|
|
||||||
|
> Note: `<boot/...>` conditions cannot be cleared with `initctl`!
|
||||||
|
|
||||||
|
* `finit.config=/path/to/alternative/finit.conf`: override the
|
||||||
|
compile-time bootstrap config file, default:
|
||||||
|
|
||||||
|
./configure --with-config=/etc/finit.conf
|
||||||
|
|
||||||
|
Useful when starting up in various rescue mode, factory, or
|
||||||
|
production test setups. Use the top-level configuration file
|
||||||
|
directive `rcsd /path/to/finit.d` to override the default
|
||||||
|
rcS.d directory.
|
||||||
|
|
||||||
* `finit.debug[=bool]`: Enable finit debug. This is operated
|
* `finit.debug[=bool]`: Enable finit debug. This is operated
|
||||||
independently of the kernel debug setting. New as of Finit v4.
|
independently of the kernel `debug` setting. New as of Finit v4.
|
||||||
|
|
||||||
* `finit.show_status[=bool]`: Control finit boot progress, including
|
* `finit.fstab=</path/to/etc/fstab.alternative>`: Tell Finit to use an
|
||||||
banner.
|
alternate `fstab` to mount the file system from. Remember, this file
|
||||||
|
must be on the `root=...` file system provided to Finit from the
|
||||||
|
kernel. By default the built-in fstab is used, which itself defaults
|
||||||
|
to `/etc/fstab`, but can be changed at build time with:
|
||||||
|
|
||||||
|
./configure --with-fstab=/path/to/fstab
|
||||||
|
|
||||||
|
It is even possible to disable a built-in default using:
|
||||||
|
|
||||||
|
./configure --without-fstab
|
||||||
|
|
||||||
|
Making `finit.fstab=/path/to/fstab` a *mandatory* command line option.
|
||||||
|
Note, if the command line fstab is missing, Finit falls back to the
|
||||||
|
built-in fstab, and if both are missing, the system treats this as a
|
||||||
|
bad `fsck` and thus calls `sulogin`. If, in turn, `sulogin` is not
|
||||||
|
available on the system, Finit calls reboot, which is also what will
|
||||||
|
happen when a user exits from `sulogin`.
|
||||||
|
|
||||||
|
* `finit.status[=bool]`: Control finit boot progress, including banner.
|
||||||
|
(Used to be `finit.show_status`, which works but is deprecated.)
|
||||||
|
|
||||||
* `finit.status_style=<classic,modern>`: Set Finit boot progress style,
|
* `finit.status_style=<classic,modern>`: Set Finit boot progress style,
|
||||||
when enabled.
|
when enabled.
|
||||||
@@ -24,23 +66,41 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
|
|||||||
signals and has no job control. Recommend using, and modifying,
|
signals and has no job control. Recommend using, and modifying,
|
||||||
`rescue` mode instead.
|
`rescue` mode instead.
|
||||||
|
|
||||||
|
* `loglevel=<0-7>`, sets the kernel's log level, which is more granular
|
||||||
|
than `debug`. Also, when `loglevel=7`, Finit will *not disable*
|
||||||
|
kernel logs to the console. This is very useful when debugging the
|
||||||
|
kernel at system bring-up. Since `loglevel=7` is the same as `debug`
|
||||||
|
this means you have to use `quiet` for a quiet boot, until sysklogd
|
||||||
|
takes over logging of kernel events.
|
||||||
|
|
||||||
* `panic=SEC`: By default the kernel does not reboot after a kernel
|
* `panic=SEC`: By default the kernel does not reboot after a kernel
|
||||||
panic. This setting will cause a kernel reboot after SEC seconds.
|
panic. This setting will cause a kernel reboot after SEC seconds.
|
||||||
|
|
||||||
* `quiet`: Suppress kernel logging to console, except for warnings and
|
* `quiet`: Suppress kernel logging to console, except for warnings and
|
||||||
errors.
|
errors. Also, see `loglevel` and `quiet` above.
|
||||||
|
|
||||||
* `rescue`: Start Finit rescue mode; no network, no `fsck` of file
|
* `rescue`: Start rescue/maintenance mode. If your system comes with
|
||||||
systems in `/etc/fstab`, no `/etc/rc.local`, no `runparts`. The
|
the bundled `sulogin` program (Finit, or from util-linux/Busybox),
|
||||||
configuration is read from `/lib/finit/rescue.conf`, and can be
|
you will be given a root login to a maintenance shell. However, if
|
||||||
modified by the operator.
|
`sulogin` is missing, the file `/lib/finit/rescue.conf` is read and
|
||||||
|
the system booted in a limited fallback mode. See [config.md][]
|
||||||
|
for more information.
|
||||||
|
|
||||||
|
**Note:** in this mode `initctl` will not work. Correct the problem
|
||||||
|
and use `reboot -f` to force reboot.
|
||||||
|
|
||||||
* `single`, or `S`: Single user mode, runlevel 1, in Finit. Useful to
|
* `single`, or `S`: Single user mode, runlevel 1, in Finit. Useful to
|
||||||
debug problems with the regular runlevel. All services and TTYs in
|
debug problems with the regular runlevel. All services and TTYs in
|
||||||
`[1]` will be started, so a `tty [1] @console nologin` configuration
|
`[1]` will be started, so a `tty [1] @console nologin` configuration
|
||||||
presents you with a root console without login.
|
presents you with a root console without login.
|
||||||
|
|
||||||
For more on kernel boot paramaters, see the man page [bootparam(7)][].
|
* `1-9`, except `6`: override the configured `runlevel`. Like the `S`
|
||||||
|
and `rescue`, giving a single number on the kernel command line tells
|
||||||
|
Finit to ignore any `runlevel` in `/etc/finit.conf` as well as the
|
||||||
|
configure fallback `--with-runlevel=N` setting. Remember, `6` is the
|
||||||
|
reboot runlevel and is not permitted. Any other values are ignored.
|
||||||
|
|
||||||
|
For more on kernel boot parameters, see the man page [bootparam(7)][].
|
||||||
|
|
||||||
|
[config.md]: config.md#rescue-mode
|
||||||
[bootparam(7)]: https://www.man7.org/linux/man-pages/man7/bootparam.7.html
|
[bootparam(7)]: https://www.man7.org/linux/man-pages/man7/bootparam.7.html
|
||||||
|
|||||||
+53
-17
@@ -13,9 +13,9 @@ Finit Conditions
|
|||||||
Introduction
|
Introduction
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Conditions are a new addition to Finit, introduced in v3, with the
|
Conditions are a relatively new addition to Finit, introduced in v3,
|
||||||
intention of providing a mechanism for common synchronization problems.
|
with the intention of providing a mechanism for common synchronization
|
||||||
For example:
|
problems. For example:
|
||||||
|
|
||||||
- *"wait for service A to start before starting service B"*, or
|
- *"wait for service A to start before starting service B"*, or
|
||||||
- *"wait for basic network access to be available"*
|
- *"wait for basic network access to be available"*
|
||||||
@@ -35,7 +35,7 @@ service to run.
|
|||||||
In this example the Network monitor daemon `netd` is not started until
|
In this example the Network monitor daemon `netd` is not started until
|
||||||
both the `pid/setupd` *and* `pid/zebra` conditions are satisfied. A
|
both the `pid/setupd` *and* `pid/zebra` conditions are satisfied. A
|
||||||
`pid/` condition is satisfied by the corresponding service's PID file
|
`pid/` condition is satisfied by the corresponding service's PID file
|
||||||
being created.
|
being created, i.e., the service's default readiness notification.
|
||||||
|
|
||||||
**NOTE:** Conditions also stop services when a condition is no longer
|
**NOTE:** Conditions also stop services when a condition is no longer
|
||||||
asserted. I.e., if the Zebra process above stops or restarts, netd
|
asserted. I.e., if the Zebra process above stops or restarts, netd
|
||||||
@@ -46,11 +46,16 @@ Triggering
|
|||||||
----------
|
----------
|
||||||
|
|
||||||
Conditions are mainly triggered (asserted) by built-in plugins, e.g.,
|
Conditions are mainly triggered (asserted) by built-in plugins, e.g.,
|
||||||
`netlink.so` and `pidfile.so`, see below for built-in conditions. Finit
|
|
||||||
also supports user-defined conditions, sometimes referred to as static
|
- `netlink.so`: provides `<net/...>`
|
||||||
or one-shot conditions. They live in the `<usr/...` namespace and are
|
- `pidfile.so`: provides `<pid/...>`
|
||||||
constrained to a flat hierarchy without any sub-directories, unlike the
|
- Cmdline `finit.cond=arg`: provides `<boot/arg>`
|
||||||
pidfile plugin, for instance.
|
|
||||||
|
See below for built-in conditions. Finit also supports user-defined
|
||||||
|
conditions, sometimes referred to as static or one-shot conditions.
|
||||||
|
They live in the `<usr/...>` namespace and are constrained to a flat
|
||||||
|
hierarchy without any sub-directories, unlike the pidfile plugin, for
|
||||||
|
instance.
|
||||||
|
|
||||||
User-defined conditions are controlled using the `initctl cond set` and
|
User-defined conditions are controlled using the `initctl cond set` and
|
||||||
`initctl cond clear` commands:
|
`initctl cond clear` commands:
|
||||||
@@ -87,12 +92,35 @@ Static (one-shot) conditions, like `usr/`, never enter the `flux` state.
|
|||||||
Built-in Conditions
|
Built-in Conditions
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
Finit comes with a `pidfile` and `netlink` plugin. When enabled, the
|
Finit comes with a set of plugins for conditions:
|
||||||
`pidfile` plugin watches `/var/run/` (recursively) for PID files created
|
|
||||||
by the monitored services, and sets a corresponding condition in the
|
- `devmon` (built-in)
|
||||||
`pid/` namespace. Similarily, the `netlink` plugin provides basic
|
- `netlink`
|
||||||
conditions for when an interface is brought up/down and when a default
|
- `pidfile`
|
||||||
route (gateway) is set, in the `net/` namespace.
|
- `sys`
|
||||||
|
- `usr`
|
||||||
|
|
||||||
|
The `devmon` (built-in) plugin monitors `/dev` and `/dev/dir` for device
|
||||||
|
nodes being created and removed. It is active only when a run, task, or
|
||||||
|
service has declared a `<dev/foo>` or `<dev/dir/bar>` condition.
|
||||||
|
|
||||||
|
The `pidfile` plugin (recursively) watches `/run/` (recursively) for PID
|
||||||
|
files created by the monitored services, and sets a corresponding
|
||||||
|
condition in the `pid/` namespace.
|
||||||
|
|
||||||
|
Similarly, the `netlink` plugin provides basic conditions for when an
|
||||||
|
interface is brought up/down and when a default route (gateway) is set,
|
||||||
|
in the `net/` namespace.
|
||||||
|
|
||||||
|
The `sys` and `usr` plugins monitor are passive condition monitors where
|
||||||
|
the action is provided by `keventd`, signal handlers, and in the case of
|
||||||
|
`usr`, the end-user via the `initctl` tool.
|
||||||
|
|
||||||
|
Additionally, the various states of a run/task/sysv/service can also be
|
||||||
|
used as conditions, the image above shows the state names. The syntax
|
||||||
|
for a `service` type process: `<service/foo/STATE>`. The other types,
|
||||||
|
in particular run/task/sysv, there are the additional states `success`
|
||||||
|
and `failure`.
|
||||||
|
|
||||||
With the example listed above, finit does not start the `/sbin/netd`
|
With the example listed above, finit does not start the `/sbin/netd`
|
||||||
daemon until `setupd` and `zebra` has started *and* created their PID
|
daemon until `setupd` and `zebra` has started *and* created their PID
|
||||||
@@ -111,6 +139,14 @@ Built-in conditions:
|
|||||||
- `net/<IFNAME>/exist`
|
- `net/<IFNAME>/exist`
|
||||||
- `net/<IFNAME>/up`
|
- `net/<IFNAME>/up`
|
||||||
- `net/<IFNAME>/running`
|
- `net/<IFNAME>/running`
|
||||||
|
- `service/<NAME[:ID]>/<STATE>`
|
||||||
|
- `{run, task, sysv}/<NAME[:ID]>/{<STATE>, success, failure}`
|
||||||
|
- `sys/pwr/ac`
|
||||||
|
- `sys/pwr/fail`
|
||||||
|
- `sys/key/ctrlaltdel`
|
||||||
|
- `usr/foo`
|
||||||
|
- `boot/arg`
|
||||||
|
- `dev/node` and `dev/dir/node`
|
||||||
|
|
||||||
**Note:** `up` means administratively up, the interface flag `IFF_UP`.
|
**Note:** `up` means administratively up, the interface flag `IFF_UP`.
|
||||||
`running` is the `IFF_RUNNING` flag, meaning operatively up. The
|
`running` is the `IFF_RUNNING` flag, meaning operatively up. The
|
||||||
@@ -156,7 +192,7 @@ Debugging
|
|||||||
If a service is not being started as it should, the problem might be
|
If a service is not being started as it should, the problem might be
|
||||||
that one of its conditions is not in the expected state. Use the
|
that one of its conditions is not in the expected state. Use the
|
||||||
command `initctl status` to inspect service status. Services in the
|
command `initctl status` to inspect service status. Services in the
|
||||||
`ready` state are pending a condition.
|
`waiting` state are pending a condition.
|
||||||
|
|
||||||
In that situation, running `initctl cond show` reveals which of the
|
In that situation, running `initctl cond show` reveals which of the
|
||||||
conditions that are not satisfied. Listed as `off` below.
|
conditions that are not satisfied. Listed as `off` below.
|
||||||
@@ -173,7 +209,7 @@ PID IDENT STATUS CONDITION (+ ON, ~ FLUX, - OFF)
|
|||||||
|
|
||||||
Here we can see that `netd` is allowed to run since both its conditions
|
Here we can see that `netd` is allowed to run since both its conditions
|
||||||
are in the `on` state, as indicated by the `+`-prefix. `udhcpc` however
|
are in the `on` state, as indicated by the `+`-prefix. `udhcpc` however
|
||||||
is not allowed to run since `net/vlan1/exist` condition is not satsifed.
|
is not allowed to run since `net/vlan1/exist` condition is not satisfied.
|
||||||
As indicated by the `-`-prefix.
|
As indicated by the `-`-prefix.
|
||||||
|
|
||||||
To fake interface `vlan1` suddenly appearing, and test what happens to
|
To fake interface `vlan1` suddenly appearing, and test what happens to
|
||||||
|
|||||||
+736
-69
@@ -1,12 +1,21 @@
|
|||||||
Configuration
|
Finit Configuration
|
||||||
=============
|
===================
|
||||||
|
|
||||||
* [Introduction](#introduction)
|
* [Introduction](#introduction)
|
||||||
|
* [Configuration Files](#configuration-files)
|
||||||
|
* [Runlevels](#runlevels)
|
||||||
|
* [Managing Services](#managing-services)
|
||||||
|
* [Environment Variables](#environment-variables)
|
||||||
|
* [Service Environment](#service-environment)
|
||||||
|
* [Service Synchronization](#service-synchronization)
|
||||||
* [Service Wrapper Scripts](#service-wrapper-scripts)
|
* [Service Wrapper Scripts](#service-wrapper-scripts)
|
||||||
|
* [Templating](#templating)
|
||||||
|
* [Cgroups](#cgroups)
|
||||||
* [Configuration File Syntax](#configuration-file-syntax)
|
* [Configuration File Syntax](#configuration-file-syntax)
|
||||||
* [Hostname](#hostname)
|
* [Hostname](#hostname)
|
||||||
* [Kernel Modules](#kernel-modules)
|
* [Kernel Modules](#kernel-modules)
|
||||||
* [Networking](#networking)
|
* [Networking](#networking)
|
||||||
|
* [Alternate rcS.d/](#alternate-rcs-d-)
|
||||||
* [Resource Limits](#resource-limits)
|
* [Resource Limits](#resource-limits)
|
||||||
* [Runlevels](#runlevels)
|
* [Runlevels](#runlevels)
|
||||||
* [One-shot Commands (sequence)](#one-shot-commands--sequence-)
|
* [One-shot Commands (sequence)](#one-shot-commands--sequence-)
|
||||||
@@ -19,42 +28,170 @@ Configuration
|
|||||||
* [TTYs and Consoles](#ttys-and-consoles)
|
* [TTYs and Consoles](#ttys-and-consoles)
|
||||||
* [Non-privileged Services](#non-privileged-services)
|
* [Non-privileged Services](#non-privileged-services)
|
||||||
* [Redirecting Output](#redirecting-output)
|
* [Redirecting Output](#redirecting-output)
|
||||||
|
* [Rescue Mode](#rescue-mode)
|
||||||
* [Limitations](#limitations)
|
* [Limitations](#limitations)
|
||||||
* [/etc/finit.conf](#etcfinitconf)
|
* [/etc/finit.conf](#etcfinitconf)
|
||||||
* [/etc/finit.d](#etcfinitd)
|
* [/etc/finit.d](#etcfinitd)
|
||||||
|
* [Watchdog](#watchdog)
|
||||||
|
* [keventd](#keventd)
|
||||||
|
|
||||||
|
|
||||||
Introduction
|
Introduction
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Finit can be configured using only the original `/etc/finit.conf` file
|
Finit is a process starter and service monitor designed to run as PID 1
|
||||||
or in combination with `/etc/finit.d/*.conf`. Useful for package-based
|
on Linux. It consists of [plugins](plugins.md) and configuration files.
|
||||||
Linux distributions -- each package can provide its own "script" file.
|
Plugins start at [hook points](plugins.md#hooks) and can run various set
|
||||||
|
up, or install event handlers that later provide runtime services, e.g.,
|
||||||
|
PID file monitoring, or [conditions](conditions.md).
|
||||||
|
|
||||||
- `/etc/finit.conf`: main configuration file
|
|
||||||
- `/etc/finit.d/*.conf`: snippets, usually one service per file
|
|
||||||
|
|
||||||
Not all configuration directives are available in `/etc/finit.d/*.conf`
|
### Configuration Files
|
||||||
and some directives are only available at bootstrap, runlevel `S`, see
|
|
||||||
the section [Limitations](#limitations) below for details.
|
|
||||||
|
|
||||||
To add a new service, simply drop a `.conf` file in `/etc/finit.d` and
|
Originally Finit was configured using a single file, `/etc/finit.conf`.
|
||||||
run `initctl reload`. (It is also possible to `SIGHUP` to PID 1, or
|
Although still possible, today we recommended using the Apache-style
|
||||||
call `finit q`, but that has been deprecated with the `initctl` tool).
|
`available/*.conf` and `enabled/*.conf` layaout. These are called
|
||||||
Finit monitors all known active `.conf` files, so if you want to force
|
dynamic services, in contrast to static -- the only difference being
|
||||||
a restart of any service you can simply touch its corresponding `.conf`
|
where they are installed and if the `initctl` tool can manage them.
|
||||||
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/`
|
/etc/
|
||||||
and use `initctl enable` to enable a service `.conf` file. This may be
|
|- finit.d/
|
||||||
useful in particular to Linux distributions that may want to install all
|
| |- available/
|
||||||
files for a package and let the user decide when to enable a service.
|
| | `- my-service.conf
|
||||||
|
: |- enabled/
|
||||||
|
: | `- my-service.conf -> ../available/my-service.conf
|
||||||
|
: :
|
||||||
|
: |- static-service.conf
|
||||||
|
: `- another-static.conf # eg. bootstrap run/task commands
|
||||||
|
:
|
||||||
|
`- finit.conf # global settings
|
||||||
|
|
||||||
|
At bootstrap, and `initctl reload`, all .conf files are read, starting
|
||||||
|
with `finit.conf`, then, in alphabetical order, all `finit.d/*.conf`
|
||||||
|
files, and finally (still in alphabetical order) all `enabled/*.conf`
|
||||||
|
files.
|
||||||
|
|
||||||
|
> **Note:** the `finit.conf` and `finit.d/` names are only defaults.
|
||||||
|
> They can be changed at compile-time with two `configure` options:
|
||||||
|
> `--with-config=/etc/foo.conf` and `--with-rcsd=/var/foo.d`.
|
||||||
|
>
|
||||||
|
> They can also be overridden from the [kernel command line](cmdline.md)
|
||||||
|
> using: `-- finit.config=/etc/bar.conf` and in that file use the
|
||||||
|
> top-level configuration directive `rcsd /path/to/finit.d`.
|
||||||
|
|
||||||
|
|
||||||
|
### Filesystem Layout
|
||||||
|
|
||||||
|
Finit is most comfortable with a traditional style Linux filesystem
|
||||||
|
layout, as specified in the [FHS][]:
|
||||||
|
|
||||||
|
/.
|
||||||
|
|- bin/
|
||||||
|
|- dev/ # Mounted automatically if devtmpfs is available
|
||||||
|
| |- pts/ # Mounted automatically by Finit if it exists
|
||||||
|
| `- shm/ # Mounted automatically by Finit if it exists
|
||||||
|
|- etc/
|
||||||
|
| |- finit.d/
|
||||||
|
| | |- available/
|
||||||
|
| | `- enabled/
|
||||||
|
| `- finit.conf
|
||||||
|
|- home/
|
||||||
|
|- lib/
|
||||||
|
|- libexec/
|
||||||
|
|- mnt/
|
||||||
|
|- proc/ # Mounted automatically by Finit if it exists
|
||||||
|
|- root/
|
||||||
|
|- run/ # Mounted automatically by Finit if it exists
|
||||||
|
| `- lock/ # Created automatically if Finit mounts /run
|
||||||
|
|- sbin/
|
||||||
|
|- sys/ # Mounted automatically by Finit if it exists
|
||||||
|
|- tmp/ # Mounted automatically by Finit if it exists
|
||||||
|
|- usr/
|
||||||
|
`- var/
|
||||||
|
|- cache/
|
||||||
|
|- db/
|
||||||
|
|- lib/
|
||||||
|
| `- misc/
|
||||||
|
|- lock/
|
||||||
|
|- log/
|
||||||
|
|- run -> ../run
|
||||||
|
|- spool/
|
||||||
|
`- tmp/
|
||||||
|
|
||||||
|
Finit starts (very early) by mounting `/dev`, `/proc/`, and `/sys`,
|
||||||
|
unless they (i.e., `/dev`) are already mounted. When all plugins and
|
||||||
|
other, core Finit functions, have been set up, all relevant filesystems
|
||||||
|
(`PASS > 0`) are checked and mounted from the selected `fstab`, either
|
||||||
|
the default `/etc/fstab`, or any custom one selected from the command
|
||||||
|
line, or at build time.
|
||||||
|
|
||||||
|
Any file system not listed `fstab` are automatically mounted by Finit,
|
||||||
|
as listed above, provided their respective mount point exists.
|
||||||
|
|
||||||
|
With all filesystems mounted, Finit calls `swapon`.
|
||||||
|
|
||||||
|
At shutdown, and after having stopped all services and other lingering
|
||||||
|
processes killed, filesystems are unmounted in the reverse order, and
|
||||||
|
`swapoff` is called.
|
||||||
|
|
||||||
|
[FHS]: https://refspecs.linuxfoundation.org/FHS_3.0/fhs/index.html
|
||||||
|
|
||||||
|
### Runlevels
|
||||||
|
|
||||||
|
- ` S`: bootStrap
|
||||||
|
- ` 1`: Single user mode
|
||||||
|
- `2-5`: traditional multi-user mode
|
||||||
|
- ` 6`: reboot
|
||||||
|
- `7-9`: multi-user mode (extra)
|
||||||
|
- ` 0`: shutdown
|
||||||
|
|
||||||
|
Runlevels are declared per service/run/task/sysv command. Starting in
|
||||||
|
runlevel S ([bootStrap](bootstrap.md)), usually only for tasks supposed
|
||||||
|
to run once at boot, and services like `syslogd`, which you need to
|
||||||
|
start and run throughout the whole time your system is up. Before `S`
|
||||||
|
is started, however, Finit performs a lot of housekeeping tasks like
|
||||||
|
mounting all filesystems, calling `fsck` if needed, and making sure the
|
||||||
|
everything is OK.
|
||||||
|
|
||||||
|
task [S] /lib/console-setup/console-setup.sh
|
||||||
|
service [S12345] env:-/etc/default/rsyslog rsyslogd -n $RSYSLOGD_ARGS
|
||||||
|
|
||||||
|
After runlevel S, Finit proceeds to runlevel 2. (This can be changed in
|
||||||
|
`/etc/finit.conf` using the `runlevel N` directive.) Before starting
|
||||||
|
the services in runlevel 2, Finit first stops everything that is not
|
||||||
|
allowed to run in 2, and then brings up networking. Networking is
|
||||||
|
expected to be available in all runlevels except: S, 1 (single user
|
||||||
|
level), 6, and 0. Networking is enabled either by the `network script`
|
||||||
|
directive, or if you have an `/etc/network/interfaces` file, Finit calls
|
||||||
|
`ifup -a` -- at the very least the loopback interface is brought up.
|
||||||
|
|
||||||
|
> **Note:** when moving from runlevel S to 2, all run/task/services that
|
||||||
|
> were constrained to runlevel S only are dropped from bookkeeping. So
|
||||||
|
> when reaching the prompt, `initctl` will not show these run/tasks.
|
||||||
|
> This is a safety mechanism to prevent bootstrap-only tasks from
|
||||||
|
> accidentally being run again. E.g., `console-setup.sh` above.
|
||||||
|
|
||||||
|
|
||||||
|
### Managing Services
|
||||||
|
|
||||||
|
Using `initctl disable my-service` the symlink (above) is removed and
|
||||||
|
the service is queued for removal. Several changes can be made to the
|
||||||
|
system, but it is not until `initctl reload` is called that the changes
|
||||||
|
are activated.
|
||||||
|
|
||||||
|
To add a new static service, drop a `.conf` file in `/etc/finit.d/` and
|
||||||
|
run `initctl reload`. (It is also possible to `SIGHUP` PID 1, or call
|
||||||
|
`finit q`, but that has been deprecated with the `initctl` tool). Finit
|
||||||
|
monitors all known active `.conf` files, so if you want to force a
|
||||||
|
restart of any service you can touch its corresponding `.conf` file in
|
||||||
|
`/etc/finit.d` and call `initctl reload`. Finit handles all conditions
|
||||||
|
and dependencies between services automatically, see below section on
|
||||||
|
[Service Synchronization](#service-synchronization) for more details.
|
||||||
|
|
||||||
On `initctl reload` the following is checked for all services:
|
On `initctl reload` the following is checked for all services:
|
||||||
|
|
||||||
- If a service's `.conf` file has been removed, or its conditions are no
|
- If a service's `.conf` file has been removed, or its conditions are no
|
||||||
longer satisifed, the service is stopped.
|
longer satisfied, the service is stopped.
|
||||||
- If the file is modified, or a service it depends on has been reloaded,
|
- If the file is modified, or a service it depends on has been reloaded,
|
||||||
the service is reloaded (stopped and started).
|
the service is reloaded (stopped and started).
|
||||||
- If a new service is added it is automatically started — respecting
|
- If a new service is added it is automatically started — respecting
|
||||||
@@ -63,9 +200,37 @@ On `initctl reload` the following is checked for all services:
|
|||||||
For more info on the different states of a service, see the separate
|
For more info on the different states of a service, see the separate
|
||||||
document [Finit Services](service.md).
|
document [Finit Services](service.md).
|
||||||
|
|
||||||
> When running <kbd>make install</kbd> no default `/etc/finit.conf` is
|
|
||||||
> installed since system requirements differ too much. There are some
|
### Environment Variables
|
||||||
> examples in the `contrib/` directory, which can be used as a base.
|
|
||||||
|
In Finit v4.3 support for setting environment variables in `finit.conf`,
|
||||||
|
and any `*.conf`, was added. It is worth noting that these are global
|
||||||
|
and *shared with all* services -- the only way to have service-local
|
||||||
|
environment is detailed in the next section.
|
||||||
|
|
||||||
|
The syntax for global environment variables is straight forward. In
|
||||||
|
Finit v4.4 the `set` keyword was added for completeness, but the old
|
||||||
|
syntax (without the `set ` prefix) is still honored:
|
||||||
|
|
||||||
|
set foo=bar
|
||||||
|
set baz="qux"
|
||||||
|
|
||||||
|
On reload of .conf files, all tracked environment variables are cleared
|
||||||
|
so if `foo=bar` is removed from `finit.conf`, or any `finit.d/*.conf`
|
||||||
|
file, it will no longer be used by Finit or any new (!) started
|
||||||
|
run/tasks or services. The environment of already started processes can
|
||||||
|
not be changed.
|
||||||
|
|
||||||
|
The only variables reset to sane defaults on .conf reload are:
|
||||||
|
|
||||||
|
PATH=_PATH_STDPATH
|
||||||
|
SHELL=_PATH_BSHELL
|
||||||
|
LOGNAME=root
|
||||||
|
USER=root
|
||||||
|
|
||||||
|
It is entirely possible to override these as well from the .conf files,
|
||||||
|
but be careful. Changing SHELL changes the behavior of `system()` and a
|
||||||
|
lot of other commands as well.
|
||||||
|
|
||||||
|
|
||||||
Service Environment
|
Service Environment
|
||||||
@@ -96,6 +261,67 @@ the `ps` command we can see that the process is started with:
|
|||||||
> `-` is used, a missing environment file does *not* block the start.
|
> `-` is used, a missing environment file does *not* block the start.
|
||||||
|
|
||||||
|
|
||||||
|
Service Synchronization
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Finit was created for fast booting systems. Faster than a regular SysV
|
||||||
|
Init based system at the time. Early on the need for a guaranteed start
|
||||||
|
order of services (daemons) arose. I.e., service `A` must be guaranteed
|
||||||
|
to have started (and be ready!) before `B`. The model that was chosen
|
||||||
|
to determine this was very simple: PID files.
|
||||||
|
|
||||||
|
Early on in UNIX daemons were controlled with basic IPC like signals,
|
||||||
|
and the way for a user to know that a daemon was ready to respond to
|
||||||
|
signals (minimally having set up its signal handler), was to tell the
|
||||||
|
user;
|
||||||
|
|
||||||
|
> "Hey, you can send signals to me using the PID in this file:
|
||||||
|
> `/var/run/daemon.pid`".
|
||||||
|
|
||||||
|
Since most systems run fairly unchanged after boot, Finit could rely on
|
||||||
|
the PID file for `A` being created before launching `B`. This method
|
||||||
|
has worked well for a long time, and for systems based on Open Source it
|
||||||
|
was easy to either add PID file support to a daemon without support for
|
||||||
|
it, or fix ordering issues (PID file created before signal handler is
|
||||||
|
set up) in existing daemons.
|
||||||
|
|
||||||
|
However, with the advent of other Init systems (Finit is rather old),
|
||||||
|
most notably systemd and s6, other methods for signaling "readiness"
|
||||||
|
arrived and daemons were adapted to these new schemes to a larger
|
||||||
|
extent.
|
||||||
|
|
||||||
|
As of Finit v4.4 partial support for systemd and s6 is available. The
|
||||||
|
native PID file mode of operation is still default, the other's can be
|
||||||
|
defined per service, like this:
|
||||||
|
|
||||||
|
service notify:systemd foo
|
||||||
|
service notify:s6 bar
|
||||||
|
|
||||||
|
To synchronize two services the following condition can be used:
|
||||||
|
|
||||||
|
service notify:systemd A
|
||||||
|
service <service/A/ready> B
|
||||||
|
|
||||||
|
For details on the syntax and options, see below.
|
||||||
|
|
||||||
|
> **Note:** on `initctl reload` conditions are normally set in "flux",
|
||||||
|
> while figuring out which to stop, start or restart. Services that
|
||||||
|
> need to be restarted have their `ready` condition removed prior to
|
||||||
|
> Finit sending them SIGHUP (if they support that), or stop-starting
|
||||||
|
> them. A daemon is expected to reassert its readiness, e.g. systemd
|
||||||
|
> style daemons to write `READY=1\n`.
|
||||||
|
>
|
||||||
|
> However, the s6 notify mode does not support this because in s6 you
|
||||||
|
> are expected to close your notify descriptor after having written
|
||||||
|
> `\n`. This means s6 style daemons currently must be stop-started.
|
||||||
|
> (Declare the service with `<!>` in its condition statement.)
|
||||||
|
>
|
||||||
|
> For native PID file style readiness notification a daemon is expected
|
||||||
|
> to either create its PID file, if it does not exist yet, or touch it
|
||||||
|
> using `utimensat()` or similar. This triggers both the `<pid/>` and
|
||||||
|
> `<.../ready>` conditions.
|
||||||
|
|
||||||
|
|
||||||
Service Wrapper Scripts
|
Service Wrapper Scripts
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
@@ -128,9 +354,115 @@ example employs a wrapper script in `/etc/start.d`.
|
|||||||
> instead of sending SIGHUP at restart/reload events.
|
> instead of sending SIGHUP at restart/reload events.
|
||||||
|
|
||||||
|
|
||||||
|
Templating
|
||||||
|
----------
|
||||||
|
|
||||||
|
Finit comes with rudimentary support for templating, similar to that of
|
||||||
|
systemd. Best illustrated with an example:
|
||||||
|
|
||||||
|
$ initctl show avahi-autoipd@
|
||||||
|
service :%i avahi-autoipd --syslog %i -- ZeroConf for %i
|
||||||
|
|
||||||
|
To enable ZeroConf for, e.g., eth0, use
|
||||||
|
|
||||||
|
$ initctl enable avahi-autoipd@eth0.conf
|
||||||
|
|
||||||
|
The enabled symlink will be set up to avahi-autoipd@.conf and every in‐
|
||||||
|
stance of %i will in the instantiated directive be replaced with eth0.
|
||||||
|
Inspect the result with:
|
||||||
|
|
||||||
|
$ initctl status avahi-autoipd:eth0
|
||||||
|
|
||||||
|
|
||||||
|
Cgroups
|
||||||
|
-------
|
||||||
|
|
||||||
|
There are three major cgroup configuration directives:
|
||||||
|
|
||||||
|
1. Global top-level group: init, system, user, or a custom group
|
||||||
|
2. Selecting a top-level group for a set of run/task/services
|
||||||
|
3. Per run/task/service limits
|
||||||
|
|
||||||
|
Top-level group configuration.
|
||||||
|
|
||||||
|
# Top-level cgroups and their default settings. All groups mandatory
|
||||||
|
# but more can be added, max 8 groups in total currently. The cgroup
|
||||||
|
# 'root' is also available, reserved for RT processes. Settings are
|
||||||
|
# as-is, only one shorthand 'mem.' exists, other than that it's the
|
||||||
|
# cgroup v2 controller default names.
|
||||||
|
cgroup init cpu.weight:100
|
||||||
|
cgroup user cpu.weight:100
|
||||||
|
cgroup system cpu.weight:9800
|
||||||
|
|
||||||
|
Adding an extra cgroup `maint/` will require you to adjust the weight of
|
||||||
|
the above three. We leave `init/` and `user/` as-is reducing weight of
|
||||||
|
`system/` to 9700.
|
||||||
|
|
||||||
|
cgroup system cpu.weight:9700
|
||||||
|
|
||||||
|
# Example extra cgroup 'maint'
|
||||||
|
cgroup maint cpu.weight:100
|
||||||
|
|
||||||
|
By default, the `system/` cgroup is selected for almost everything. The
|
||||||
|
`init/` cgroup is reserved for PID 1 itself and its closest relatives.
|
||||||
|
The `user/` cgroup is for local TTY logins spawned by getty.
|
||||||
|
|
||||||
|
To select a different top-level cgroup, e.g. `maint/`, one can either
|
||||||
|
define it for a group of run/task/service directives in a `.conf` or per
|
||||||
|
each stanza:
|
||||||
|
|
||||||
|
cgroup.maint
|
||||||
|
service [...] <...> /path/to/foo args -- description
|
||||||
|
service [...] <...> /path/to/bar args -- description
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
service [...] <...> cgroup.maint /path/to/foo args -- description
|
||||||
|
|
||||||
|
The latter form also allows per-stanza limits on the form:
|
||||||
|
|
||||||
|
service [...] <...> cgroup.maint:cpu.max:10000,mem.max:655360 /path/to/foo args -- description
|
||||||
|
|
||||||
|
Notice the comma separation and the `mem.` exception to the rule: every
|
||||||
|
cgroup setting maps directly to cgroup v2 syntax. I.e., `cpu.max` maps
|
||||||
|
to the file `/sys/fs/cgroup/maint/foo/cpu.max`. There is no filtering,
|
||||||
|
except for expanding the shorthand `mem.` to `memory.`, if the file is
|
||||||
|
not available, either the cgroup controller is not available in your
|
||||||
|
Linux kernel, or the name is misspelled.
|
||||||
|
|
||||||
|
> Linux cgroups and details surrounding values are not explained in the
|
||||||
|
> Finit documentation. The Linux admin-guide cover this well:
|
||||||
|
> <https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html>
|
||||||
|
|
||||||
|
|
||||||
Configuration File Syntax
|
Configuration File Syntax
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
|
The file format is line based, empty lines and comments, lines starting
|
||||||
|
with `#`, are ignored. A configuration directive starts with a keyword
|
||||||
|
followed by a space and the rest of the line is treated as the value.
|
||||||
|
|
||||||
|
As of Finit v4.4, configuration directives can be broken up in multiple
|
||||||
|
lines using the continuation character `\`, and trailing comments are
|
||||||
|
also allowed. Example:
|
||||||
|
|
||||||
|
```aconf
|
||||||
|
# Escape \# chars if you want them literal in, e.g., descriptions
|
||||||
|
service name:sysklogd [S123456789] \
|
||||||
|
env:-/etc/default/sysklogd \
|
||||||
|
syslogd -F $SYSLOGD_ARGS \
|
||||||
|
-- System log daemon \# 1 # Comments allowed now
|
||||||
|
```
|
||||||
|
|
||||||
|
The .conf files `/etc/finit.conf` and `/etc/finit.d/*` support the
|
||||||
|
following directives:
|
||||||
|
|
||||||
|
|
||||||
|
> **Note:** not all directives are available in `/etc/finit.d/*.conf`
|
||||||
|
> and some directives are only available at [bootstrap][], runlevel `S`,
|
||||||
|
> see [Limitations](#limitations) below for details.
|
||||||
|
|
||||||
|
|
||||||
### Hostname
|
### Hostname
|
||||||
|
|
||||||
**Syntax:** `host <NAME>`, or `hostname <NAME>`
|
**Syntax:** `host <NAME>`, or `hostname <NAME>`
|
||||||
@@ -140,7 +472,7 @@ the contents of that file is used.
|
|||||||
|
|
||||||
Deprecated. We recommend using `/etc/hostname` instead.
|
Deprecated. We recommend using `/etc/hostname` instead.
|
||||||
|
|
||||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||||
|
|
||||||
|
|
||||||
### Kernel Modules
|
### Kernel Modules
|
||||||
@@ -158,7 +490,7 @@ BusyBox mdev tool, add to `/etc/mdev.conf`:
|
|||||||
|
|
||||||
$MODALIAS=.* root:root 0660 @modprobe -b "$MODALIAS"
|
$MODALIAS=.* root:root 0660 @modprobe -b "$MODALIAS"
|
||||||
|
|
||||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||||
|
|
||||||
|
|
||||||
### Networking
|
### Networking
|
||||||
@@ -171,9 +503,30 @@ Deprecated. We recommend using dedicated task/run stanzas per runlevel,
|
|||||||
or `/etc/network/interfaces` if you have a system with `ifupdown`, like
|
or `/etc/network/interfaces` if you have a system with `ifupdown`, like
|
||||||
Debian, Ubuntu, Linux Mint, or an embedded BusyBox system.
|
Debian, Ubuntu, Linux Mint, or an embedded BusyBox system.
|
||||||
|
|
||||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||||
|
|
||||||
|
|
||||||
|
### Alternate finit.d/
|
||||||
|
|
||||||
|
**Syntax:** `rcsd /path/to/finit.d`
|
||||||
|
|
||||||
|
The Finit rcS.d directory is set at compile time with:
|
||||||
|
|
||||||
|
./configure --with-rcsd=/etc/finit.d
|
||||||
|
|
||||||
|
A system with multiple use-cases may be bootstrapped with different
|
||||||
|
configurations, starting with the kernel command line option:
|
||||||
|
|
||||||
|
-- finit.config=/etc/factory.conf
|
||||||
|
|
||||||
|
This file in turn can use the `rcsd` directive to tell Finit to use
|
||||||
|
another set of .conf files, e.g.:
|
||||||
|
|
||||||
|
rcsd /etc/factory.d
|
||||||
|
|
||||||
|
> **Note:** this directive is only available from the top-level
|
||||||
|
> bootstrap .conf file.
|
||||||
|
|
||||||
### Resource Limits
|
### Resource Limits
|
||||||
|
|
||||||
**Syntax:** `rlimit [hard|soft] RESOURCE <LIMIT|unlimited>`
|
**Syntax:** `rlimit [hard|soft] RESOURCE <LIMIT|unlimited>`
|
||||||
@@ -205,13 +558,16 @@ stanzas can share the same rlimits if they are in the same .conf.
|
|||||||
|
|
||||||
**Syntax:** `runlevel <N>`
|
**Syntax:** `runlevel <N>`
|
||||||
|
|
||||||
Defines the system runlevel to go to after bootstrap (S) has completed.
|
The system runlevel to go to after [bootstrap][] (S) has completed. `N`
|
||||||
N is the runlevel number 0-9, where 6 is reserved for reboot and 0 for
|
is the runlevel number 0-9, where 6 is reserved for reboot and 0 for
|
||||||
halt.
|
halt.
|
||||||
|
|
||||||
Default: 2
|
It is recommended to keep runlevel 1 as single-user mode, because
|
||||||
|
Finit disables networking in this mode.
|
||||||
|
|
||||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
*Default:* 2
|
||||||
|
|
||||||
|
> **Note:** only read and executed in runlevel S ([bootstrap][]).
|
||||||
|
|
||||||
|
|
||||||
### One-shot Commands (sequence)
|
### One-shot Commands (sequence)
|
||||||
@@ -257,6 +613,10 @@ calls `init-script restart` on `initctl reload`. Similar to how
|
|||||||
|
|
||||||
Forking services started with `sysv` scripts can be monitored by Finit
|
Forking services started with `sysv` scripts can be monitored by Finit
|
||||||
by declaring the PID file to look for: `pid:!/path/to/pidfile.pid`.
|
by declaring the PID file to look for: `pid:!/path/to/pidfile.pid`.
|
||||||
|
Notice the leading `!`, it signifies Finit should not try to create the
|
||||||
|
file, but rather watch that file for the resulting forked-off PID. This
|
||||||
|
syntax also works for forking daemons that do not have a command line
|
||||||
|
option to run it in the foreground, more on this below in `service`.
|
||||||
|
|
||||||
> `<COND>` is described in the [Services](#services) section.
|
> `<COND>` is described in the [Services](#services) section.
|
||||||
|
|
||||||
@@ -266,8 +626,13 @@ by declaring the PID file to look for: `pid:!/path/to/pidfile.pid`.
|
|||||||
**Syntax:** `service [LVLS] <COND> /path/to/daemon ARGS -- Optional description`
|
**Syntax:** `service [LVLS] <COND> /path/to/daemon ARGS -- Optional description`
|
||||||
|
|
||||||
Service, or daemon, to be monitored and automatically restarted if it
|
Service, or daemon, to be monitored and automatically restarted if it
|
||||||
exits prematurely. Finit tries to restart services that die 10 times
|
exits prematurely. Finit tries to restart services that die, by
|
||||||
before giving up, then you have to `initctl restart NAME` it manually.
|
default 10 times before giving up and marking them as *crashed*.
|
||||||
|
After which they have to be manually restarted with `initctl restart
|
||||||
|
NAME`. The limits controling this are configurable, see the options
|
||||||
|
below.
|
||||||
|
|
||||||
|
> **Tip:** to allow endless restarts, see below option `respawn`
|
||||||
|
|
||||||
For daemons that support it, we recommend appending `--foreground`,
|
For daemons that support it, we recommend appending `--foreground`,
|
||||||
`--no-background`, `-n`, `-F`, or similar command line argument to
|
`--no-background`, `-n`, `-F`, or similar command line argument to
|
||||||
@@ -275,9 +640,19 @@ prevent them from forking off a sub-process in the background. This is
|
|||||||
the most reliable way to monitor a service.
|
the most reliable way to monitor a service.
|
||||||
|
|
||||||
However, not all daemons support running in the foreground, or they may
|
However, not all daemons support running in the foreground, or they may
|
||||||
start logging to the foreground as well, these are called forking
|
start logging to the foreground as well, these are forking daemons and
|
||||||
services and are supported using the same syntax as forking `sysv`
|
are supported using the same syntax as forking `sysv` services, using
|
||||||
services, using the `pid:!/path/to/pidfile.pid` syntax.
|
the `pid:!/path/to/pidfile.pid` syntax. There is an alternative syntax
|
||||||
|
that may be more intuitive, where Finit can also guess the PID file
|
||||||
|
based on the daemon's command name:
|
||||||
|
|
||||||
|
service type:forking ntpd -- NTP daemon
|
||||||
|
|
||||||
|
This example lets BusyBox `ntpd` daemonize itself. Finit uses the
|
||||||
|
basename of the binary to guess the PID file to watch for the PID:
|
||||||
|
`/var/run/ntpd.pid`. If Finit guesses wrong, you have to submit the
|
||||||
|
full `pid:!/path/to/file.pid`.
|
||||||
|
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
@@ -304,10 +679,56 @@ modified with an optional `pid:`-argument:
|
|||||||
|
|
||||||
pid[:[/path/to/]filename[.pid]]
|
pid[:[/path/to/]filename[.pid]]
|
||||||
|
|
||||||
For example, by adding `pid:/run/foo.pid` to the service `/sbin/bar`,
|
For example, by adding `pid:/run/bar.pid` to the service `/sbin/bar`,
|
||||||
that PID file will, not only be created and removed automatically, but
|
that PID file will, not only be created and removed automatically, but
|
||||||
also be used by the Finit condition subsystem. So a service/run/task
|
also be used by the Finit condition subsystem. So a service/run/task
|
||||||
can depend on `<pid/bar>`.
|
can depend on `<pid/bar>`, like this foo will not be started until bar
|
||||||
|
has started:
|
||||||
|
|
||||||
|
service pid:/run/bar.pid bar -- Bar Service
|
||||||
|
service <pid/bar> foo -- Foo Service
|
||||||
|
|
||||||
|
Needless to say, it is better if `bar` creates its own PID file when it
|
||||||
|
has completed starting up and is ready for service.
|
||||||
|
|
||||||
|
As an alternative "readiness" notification, Finit supports both systemd
|
||||||
|
and s6 style notification. This can be enabled by using the `notify`
|
||||||
|
option:
|
||||||
|
|
||||||
|
* `notify:systemd` -- tells Finit the service uses the `sd_notify()`
|
||||||
|
API to signal PID 1 when it has completed its startup and is ready
|
||||||
|
to service events. The [sd_notify()][] API expects `NOTIFY_SOCKET`
|
||||||
|
to be set to the socket where the application can send `"READY=1\n"`
|
||||||
|
when it is starting up or has processed a `SIGHUP`.
|
||||||
|
* `notify:s6` -- puts Finit in s6 compatibility mode. Compared to the
|
||||||
|
systemd notification, [s6 expect][] compliant daemons to send `"\n"`
|
||||||
|
and then close their socket. Finit takes care of "hard-wiring" the
|
||||||
|
READY state as long as the application is running, events across any
|
||||||
|
`SIGHUP`. Since s6 can give its applications the descriptor number
|
||||||
|
(must be >3) on then command line, Finit provides the following
|
||||||
|
syntax (`%n` is replaced by Finit with then descriptor number):
|
||||||
|
|
||||||
|
service [S12345789] notify:s6 mdevd -O 4 -D %n
|
||||||
|
|
||||||
|
[sd_notify()]: https://www.freedesktop.org/software/systemd/man/sd_notify.html
|
||||||
|
[s6 expect]: https://skarnet.org/software/s6/notifywhenup.html
|
||||||
|
|
||||||
|
When a service is ready, either by Finit detecting its PID file, or
|
||||||
|
their respective readiness mechanism has been triggered, Finit creates
|
||||||
|
then service's ready condition which other services can depend on:
|
||||||
|
|
||||||
|
$ initctl -v cond get service/mdevd/ready
|
||||||
|
on
|
||||||
|
|
||||||
|
This can be used to synchronize the start of another run/task/service:
|
||||||
|
|
||||||
|
task [S] <service/mdevd/ready> @root:root mdevd-coldplug
|
||||||
|
|
||||||
|
Finit waits for `mdevd` to notify it, before starting `mdevd-coldplug`.
|
||||||
|
Notice how both start in runlevel S, and the coldplug task only runs in
|
||||||
|
S. When the system moves to runlevel 2 (the default), coldplug is no
|
||||||
|
longer part of the running configuration (`initctl show`), this is to
|
||||||
|
ensure that coldplug is not called more than once.
|
||||||
|
|
||||||
> For a detailed description of conditions, and how to debug them,
|
> For a detailed description of conditions, and how to debug them,
|
||||||
> see the [Finit Conditions](conditions.md) document.
|
> see the [Finit Conditions](conditions.md) document.
|
||||||
@@ -324,6 +745,46 @@ optional `name` argument:
|
|||||||
|
|
||||||
name:<service-name>
|
name:<service-name>
|
||||||
|
|
||||||
|
If multiple instances of a service, with the same `name`, exist. Set
|
||||||
|
the identifier `:ID` to prevent Finit from replacing previous instances:
|
||||||
|
|
||||||
|
service :eth1 ssdpd eth1 -- Windows discovery on eth1
|
||||||
|
service :eth2 ssdpd eth2 -- Windows discovery on eth2
|
||||||
|
|
||||||
|
If you have conflicting services and want to prevent them from starting,
|
||||||
|
use the `conflict:` argument:
|
||||||
|
|
||||||
|
service [S12345789] udevd -- Device event management daemon
|
||||||
|
run [S] conflict:udevd mdev -s -- Populating device tree
|
||||||
|
|
||||||
|
Multiple conflicting services can be separated using `,`:
|
||||||
|
|
||||||
|
service :1 abc
|
||||||
|
service :2 abc
|
||||||
|
service conflict:abc:1,abc:2 cde
|
||||||
|
|
||||||
|
As mentioned previously, services are automatically restarted, this is
|
||||||
|
configurable with the following options:
|
||||||
|
|
||||||
|
* `restart:NUM` -- number of times Finit tries to restart a crashing
|
||||||
|
service, default: 10, max: 255. When this limit is reached the
|
||||||
|
service is marked *crashed* and must be restarted manually with
|
||||||
|
`initctl restart NAME`
|
||||||
|
* `restart_sec:SEC` -- number of seconds before Finit tries to restart
|
||||||
|
a crashing service, default: 2 seconds for the first five retries,
|
||||||
|
then back-off to 5 seconds. The maximum of this configured value
|
||||||
|
and the above (2 and 5) will be used
|
||||||
|
* `restart:always` -- no upper limit on the number of times Finit
|
||||||
|
tries to restart a crashing service. Same as `restart:-1`
|
||||||
|
* `norestart` -- dont restart on failures, same as `restart:0`
|
||||||
|
* `respawn` -- bypasses the `restart` mechanism completely, allows
|
||||||
|
endless restarts. Useful in many use-cases, but not what `service`
|
||||||
|
was originally designed for so not the default behavior
|
||||||
|
* `oncrash:reboot` -- when all retries have failed, and the service
|
||||||
|
has *crashed*, if this option is set the system is rebooted.
|
||||||
|
* `oncrash:script` -- similarly, but instead of rebooting, call the
|
||||||
|
`post:script` action if set, see below.
|
||||||
|
|
||||||
When stopping a service (run/task/sysv/service), either manually or
|
When stopping a service (run/task/sysv/service), either manually or
|
||||||
when moving to another runlevel, Finit starts by sending `SIGTERM`, to
|
when moving to another runlevel, Finit starts by sending `SIGTERM`, to
|
||||||
allow the process to shut down gracefully. If the process has not
|
allow the process to shut down gracefully. If the process has not
|
||||||
@@ -333,6 +794,25 @@ process using a different signal, use the option `halt:SIGNAL`, e.g.,
|
|||||||
use the option `kill:SEC`, e.g., `kill:10` to wait 10 seconds before
|
use the option `kill:SEC`, e.g., `kill:10` to wait 10 seconds before
|
||||||
sending `SIGKILL`.
|
sending `SIGKILL`.
|
||||||
|
|
||||||
|
Services support `pre:script` and `post:script` actions as well. These
|
||||||
|
run as the same `@USER:GROUP` as the service itself, with any `env:file`
|
||||||
|
sourced. The scripts must use an absolute path, but are executed from
|
||||||
|
the `$HOME` of the given user. The scripts are not called with any
|
||||||
|
argument (currently), but both get the `SERVICE_IDENT=foo` environment
|
||||||
|
variable set. Here `foo` denotes the identity of the service, which if
|
||||||
|
there are multiple services named `foo`, may be `foo:1`, or any unique
|
||||||
|
identifier specified in the .conf file. The `post:script` is called
|
||||||
|
with an additional set of environment variables:
|
||||||
|
|
||||||
|
- `EXIT_CODE=[exited,signal]`: set to one of `exited` or `signal`
|
||||||
|
- `EXIT_STATUS=[num,SIGNAME]`: set to one of exit status code from
|
||||||
|
the program, if it exited normally, or the signal name (`HUP`,
|
||||||
|
`TERM`, etc.) if it exited due to signal
|
||||||
|
|
||||||
|
These script actions *must terminate*, so they have a default execution
|
||||||
|
time of 3 seconds before they are SIGKILLed, this can be adjusted using
|
||||||
|
the above `kill:SEC` syntax.
|
||||||
|
|
||||||
|
|
||||||
### Run-parts Scripts
|
### Run-parts Scripts
|
||||||
|
|
||||||
@@ -341,17 +821,53 @@ sending `SIGKILL`.
|
|||||||
Call [run-parts(8)][] on `DIR` to run start scripts. All executable
|
Call [run-parts(8)][] on `DIR` to run start scripts. All executable
|
||||||
files, or scripts, in the directory are called, in alphabetic order.
|
files, or scripts, in the directory are called, in alphabetic order.
|
||||||
The scripts in this directory are executed at the very end of runlevel
|
The scripts in this directory are executed at the very end of runlevel
|
||||||
`S`, bootstrap.
|
`S`, [bootstrap][].
|
||||||
|
|
||||||
It can be beneficial to use `S01name`, `S02othername`, etc. if there
|
A common use-case for runparts scripts is to create and enable/disable
|
||||||
is a dependency order between the scripts. Symlinks to existing
|
services, which Finit will then apply when changing runlevel from S to
|
||||||
daemons can talso be used, but make sure they daemonize by default.
|
whatever the next runlevel is set to be (default 2). E.g., generate a
|
||||||
|
`/etc/chrony.conf` and `initctl enable chronyd`.
|
||||||
|
|
||||||
Similar to the `/etc/rc.local` shell script, make sure that all your
|
**Limitations:**
|
||||||
services and programs either terminate or start in the background or
|
|
||||||
you will block Finit.
|
Scripts called from `runparts`, or hook scripts (see below), are limited
|
||||||
|
in what they can do and expect from Finit:
|
||||||
|
|
||||||
|
1. Finit is single threaded and all scripts executed from these two
|
||||||
|
mechanisms are limited to file system operations (early or late
|
||||||
|
hooks may not have write access!) and standard UNIX programs.
|
||||||
|
2. Thus, it is *not possible* to call `initctl` to query status of
|
||||||
|
services since that calls Finit over the `/run/finit/socket`.
|
||||||
|
3. Confusingly enough, there are some commands to `initctl` that are
|
||||||
|
available; `ls`, `enable`, `disable`, `touch`, `create`, `delete`,
|
||||||
|
and all the `cond` commands. Because all these are basically just
|
||||||
|
wrappers for manipulating files (again, write access for early/late
|
||||||
|
hooks may not be available).
|
||||||
|
|
||||||
|
Also, similar to the `/etc/rc.local` shell script, make sure that all
|
||||||
|
your services and programs either terminate or start in the background
|
||||||
|
or you will block Finit.
|
||||||
|
|
||||||
|
> **Note:** `runparts` scrips are only read and executed in runlevel S
|
||||||
|
> ([bootstrap][]). See [hook scripts](plugins.md#hooks) for other ways
|
||||||
|
> to run scripts at certain points during the complete lifetime of the
|
||||||
|
> system.
|
||||||
|
|
||||||
|
**Recommendations:**
|
||||||
|
|
||||||
|
It can be beneficial to use `01-name`, `02-othername`, etc., to ensure
|
||||||
|
the scripts are started in that order, e.g., if there is a dependency
|
||||||
|
order between scripts. Symlinks to existing daemons can talso be used,
|
||||||
|
but make sure they daemonize (background) themselves properly, otherwise
|
||||||
|
Finit will lock up.
|
||||||
|
|
||||||
|
If `S[0-9]foo` and `K[0-9]bar` style naming is used, the executable will
|
||||||
|
be called with an extra argument, `start` and `stop`, respectively.
|
||||||
|
E.g., `S01foo` will be called as `S01foo start`. Of course, `S01foo`
|
||||||
|
and `K01foo` may be a symlink to to `another/directory/foo`.
|
||||||
|
|
||||||
|
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
||||||
|
|
||||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
|
||||||
|
|
||||||
### Including Finit Configs
|
### Including Finit Configs
|
||||||
|
|
||||||
@@ -377,24 +893,40 @@ size limit is reached.
|
|||||||
|
|
||||||
### TTYs and Consoles
|
### TTYs and Consoles
|
||||||
|
|
||||||
**Syntax:** `tty [LVLS] <DEV> [BAUD] [noclear] [nowait] [nologin] [TERM]`
|
**Syntax:** `tty [LVLS] <COND> DEV [BAUD] [noclear] [nowait] [nologin] [TERM]`
|
||||||
`tty [LVLS] <CMD> <ARGS> [noclear] [nowait]`
|
`tty [LVLS] <COND> CMD <ARGS> [noclear] [nowait]`
|
||||||
|
`tty [LVLS] <COND> [notty] [rescue]`
|
||||||
|
|
||||||
The first variant of this option uses the built-in getty on the given
|
The first variant of this option uses the built-in getty on the given
|
||||||
TTY device DEV, in the given runlevels. The DEV may be the special
|
TTY device DEV, in the given runlevels. DEV may be the special keyword
|
||||||
keyword `@console`, or `console`, useful on embedded systems.
|
`@console`, which is expanded from `/sys/class/tty/console/active`,
|
||||||
|
useful on embedded systems.
|
||||||
|
|
||||||
The default baud rate is 0, i.e., keep kernel default.
|
The default baud rate is 0, i.e., keep kernel default.
|
||||||
|
|
||||||
|
> The `tty` stanza inherits runlevel, condition (and other feature)
|
||||||
|
> parsing from the `service` stanza. So TTYs can run in one or many
|
||||||
|
> runlevels and depend on any condition supported by Finit. This is
|
||||||
|
> useful e.g. to depend on `<pid/elogind>` before starting a TTY.
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
tty [12345] /dev/ttyAMA0 115200 noclear vt220
|
tty [12345] /dev/ttyAMA0 115200 noclear vt220
|
||||||
|
|
||||||
The second `tty` syntax variant is for using an external getty, like
|
The second `tty` syntax variant is for using an external getty, like
|
||||||
agetty or the BusyBox getty.
|
agetty or the BusyBox getty.
|
||||||
|
|
||||||
By default both variants *clear* the TTY and *wait* for the user to
|
The third variant is for board bringup and the `rescue` boot mode. No
|
||||||
press enter before starting getty.
|
device node is required in this variant, the same output that the kernel
|
||||||
|
uses is reused for stdio. If the `rescue` option is omitted, a shell is
|
||||||
|
started (`nologin`, `noclear`, and `nowait` are implied), if the rescue
|
||||||
|
option is set the bundled `/libexec/finit/sulogin` is started to present
|
||||||
|
a bare-bones root login prompt. If the root (uid:0, gid:0) user does
|
||||||
|
not have a password set, no rescue is possible. For more information,
|
||||||
|
see the [Rescue Mode](#rescue-mode) section.
|
||||||
|
|
||||||
|
By default, the first two syntax variants *clear* the TTY and *wait* for
|
||||||
|
the user to press enter before starting getty.
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
@@ -423,16 +955,23 @@ uses `ttyS0`, `ttyAMA0`, `ttyMXC0`, or anything else. Finit figures
|
|||||||
it out by querying sysfs: `/sys/class/tty/console/active`. The speed
|
it out by querying sysfs: `/sys/class/tty/console/active`. The speed
|
||||||
can be omitted to keep the kernel default.
|
can be omitted to keep the kernel default.
|
||||||
|
|
||||||
|
> Most systems get by fine by just using `console`, which will evaluate
|
||||||
|
> to `/dev/console`. If you have to use `@console` to get any output,
|
||||||
|
> you may have some issue with your kernel config.
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
tty [12345] @console noclear vt220
|
tty [12345] @console noclear vt220
|
||||||
|
|
||||||
On really bare bones systems Finit offers a fallback shell, which
|
On really bare bones systems, or for board bringup, Finit can give you a
|
||||||
should not be enabled on production systems since. This because it
|
shell prompt as soon as [bootstrap][] is done, without opening any
|
||||||
may give a user root access without having to log in. However, for
|
device node:
|
||||||
bringup and system debugging it can come in handy:
|
|
||||||
|
|
||||||
configure --enable-fallback-shell
|
tty [12345789] notty
|
||||||
|
|
||||||
|
This should of course not be enabled on production systems. Because it
|
||||||
|
may give a user root access without having to log in. However, for
|
||||||
|
board bringup and system debugging it can come in handy.
|
||||||
|
|
||||||
One can also use the `service` stanza to start a stand-alone shell:
|
One can also use the `service` stanza to start a stand-alone shell:
|
||||||
|
|
||||||
@@ -442,8 +981,8 @@ One can also use the `service` stanza to start a stand-alone shell:
|
|||||||
### Non-privileged Services
|
### Non-privileged Services
|
||||||
|
|
||||||
Every `run`, `task`, or `service` can also list the privileges the
|
Every `run`, `task`, or `service` can also list the privileges the
|
||||||
`/path/to/cmd` should be executed with. Simply prefix the path with
|
`/path/to/cmd` should be executed with. Prefix the command with
|
||||||
`[@USR[:GRP]]` like this:
|
`@USR[:GRP]`, group is optional, like this:
|
||||||
|
|
||||||
run [2345] @joe:users logger "Hello world"
|
run [2345] @joe:users logger "Hello world"
|
||||||
|
|
||||||
@@ -484,24 +1023,152 @@ Log rotation is controlled using the global `log` setting.
|
|||||||
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
|
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
|
||||||
|
|
||||||
|
|
||||||
|
### Misc Settings
|
||||||
|
|
||||||
|
**Syntax:** `reboot-delay <0-60>`
|
||||||
|
|
||||||
|
Optional delay at reboot (or shutdown or halt) to allow kernel
|
||||||
|
filesystem threads to complete after calling `sync(2)` before
|
||||||
|
rebooting. This applies primarily to filesystems that do not
|
||||||
|
have a reboot notifier implemented. At the point of writing,
|
||||||
|
the only known filesystems affected are: ubifs, jffs2.
|
||||||
|
|
||||||
|
*Default:* 0 (disabled)
|
||||||
|
|
||||||
|
When enabled (non-zero), this delay runs after file systems have been
|
||||||
|
unmounted and the root filesystem has been remounted read-only, and
|
||||||
|
sync(2) has been called, twice.
|
||||||
|
|
||||||
|
> "On Linux, sync is only guaranteed to schedule the dirty blocks for
|
||||||
|
> writing; it can actually take a short time before all the blocks are
|
||||||
|
> finally written.
|
||||||
|
|
||||||
|
|
||||||
|
Rescue Mode
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Finit supports a rescue mode which is activated by the `rescue` option
|
||||||
|
on the kernel command line. See [cmdline docs](cmdline.md) for how to
|
||||||
|
activate it.
|
||||||
|
|
||||||
|
The rescue mode comes in two flavors; *traditional* and *fallback*.
|
||||||
|
|
||||||
|
> **Note:** in this mode `initctl` will not work. Use the `-f` flag to
|
||||||
|
> force `reboot`, `shutdown`, or `poweroff`.
|
||||||
|
|
||||||
|
|
||||||
|
### Traditional
|
||||||
|
|
||||||
|
This is what most users expect. A very early maintenance login prompt,
|
||||||
|
served by the bundled `/libexec/finit/sulogin` program, or the standard
|
||||||
|
`sulogin` from util-linux or BusyBox is searched for in the UNIX default
|
||||||
|
`$PATH`. If a successful login is made, or the user exits (Ctrl-D), the
|
||||||
|
rescue mode is ended and the system boots up normally.
|
||||||
|
|
||||||
|
> **Note:** if the user (UID 0 and GID 0) does not have a password, or
|
||||||
|
> __the account is locked__, the user is presented with a password-less
|
||||||
|
> `"Press enter to enter maintenance mode."`, prompt which opens up a
|
||||||
|
> root shell.
|
||||||
|
|
||||||
|
|
||||||
|
### Fallback
|
||||||
|
|
||||||
|
If no `sulogin` program is found, Finit tries to bring up as much of its
|
||||||
|
own functionality as possible, yet limiting many aspects, meaning; no
|
||||||
|
network, no `fsck` of file systems in `/etc/fstab`, no `/etc/rc.local`,
|
||||||
|
no `runparts`, and most plugins are skipped (except those that provide
|
||||||
|
functionality for the condition subsystem).
|
||||||
|
|
||||||
|
Instead of reading `/etc/finit.conf` et al, system configuration is read
|
||||||
|
from `/lib/finit/rescue.conf`, which can be freely modified by the
|
||||||
|
system administrator.
|
||||||
|
|
||||||
|
The bundled default `rescue.conf` contains nothing more than:
|
||||||
|
|
||||||
|
runlevel 1
|
||||||
|
tty [12345] rescue
|
||||||
|
|
||||||
|
The `tty` has the `rescue` option set, which works similar to the board
|
||||||
|
bring-up tty option `notty`. The major difference being that `sulogin`
|
||||||
|
is started to query for root/admin password. If `sulogin` is not found,
|
||||||
|
`rescue` behaves like `notty` and gives a plain root shell prompt.
|
||||||
|
|
||||||
|
If Finit cannot find `/lib/finit/rescue.conf` it defaults to:
|
||||||
|
|
||||||
|
tty [12345] rescue
|
||||||
|
|
||||||
|
There is no way to exit the *fallback* rescue mode.
|
||||||
|
|
||||||
|
|
||||||
Limitations
|
Limitations
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
As of Finit v4 there are no limitations to where `.conf` settings can be
|
As of Finit v4 there are no limitations to where `.conf` settings can be
|
||||||
placed. Except for the system/global `rlimit`, which can only be set
|
placed. Except for the system/global `rlimit` and `cgroup` top-level
|
||||||
from `/etc/finit.conf`, since it is the first `.conf` file Finit reads.
|
group declarations, which can only be set from `/etc/finit.conf`, since
|
||||||
|
it is the first `.conf` file Finit reads.
|
||||||
|
|
||||||
Originally, `/etc/finit.conf` was the only way to set up a Finit system.
|
Originally, `/etc/finit.conf` was the only way to set up a Finit system.
|
||||||
Today it is mainly used for bootstrap settings like system hostname,
|
Today it is mainly used for bootstrap settings like system hostname,
|
||||||
network bringup and system shutdown. These can now also be set in any
|
early module loading for watchdogd, network bringup and system shutdown.
|
||||||
`.conf` file in `/etc/finit.d`.
|
These can now also be set in any `.conf` file in `/etc/finit.d`.
|
||||||
|
|
||||||
There is, however, nothing preventing you from having all configuration
|
There is, however, nothing preventing you from having all configuration
|
||||||
settings in `/etc/finit.conf`.
|
settings in `/etc/finit.conf`.
|
||||||
|
|
||||||
> **Note:** The `/etc/finit.d` directory was previously the default
|
> **Note:** The `/etc/finit.d` directory was previously the default
|
||||||
> Finit `runparts` directory. Finit no longer has a default
|
> Finit [runparts](#run-parts-scripts) directory. Finit >=v4.0
|
||||||
> `runparts`, make sure to update your setup, or the finit
|
> no longer has a default `runparts` directory, make sure to
|
||||||
> configuration, accordingly.
|
> update your setup, or the finit configuration, accordingly.
|
||||||
|
|
||||||
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
|
||||||
|
Watchdog
|
||||||
|
--------
|
||||||
|
|
||||||
|
When built `--with-watchdog` a separate service is built and installed
|
||||||
|
in `/libexec/finit/watchdogd`. If this exists at runtime, and the WDT
|
||||||
|
device node exists, Finit will start it and treat it as the elected
|
||||||
|
watchdog service to delegate its reboot to. See [bootstrap][] for
|
||||||
|
details. This delegation is to ensure that the system is rebooted by a
|
||||||
|
hardware watchdog timer -- on many embedded systems this is crucial to
|
||||||
|
ensure all circuits on the board are properly reset for the next boot,
|
||||||
|
in effect ensuring the system works the same after both a power-on and
|
||||||
|
reboot event.
|
||||||
|
|
||||||
|
The delegation is performed at the very last steps of system shutdown,
|
||||||
|
if reboot has been selected and an elected watchdog is known, first a
|
||||||
|
`SIGPWR` is sent to advise watchdogd of the pending reboot. Then, when
|
||||||
|
the necessary steps of preparing the system for shutdown (umount etc.)
|
||||||
|
are completed, Finit sends `SIGTERM` to watchdogd and puts itself in a
|
||||||
|
10 sec timeout loop waiting for the WDT to reset the board. If a reset
|
||||||
|
is not done before the timeout, Finit falls back to`reboot(RB_AUTOBOOT)`
|
||||||
|
which tells the kernel to do the reboot.
|
||||||
|
|
||||||
|
An external watchdog service can also be used. The more advanced cousin
|
||||||
|
[watchdogd](https://github.com/troglobit/watchdogd/) is the recommended
|
||||||
|
option here. It can register itself with Finit using the same IPC as
|
||||||
|
`initctl`. If the bundled watchdogd is running a hand-over takes place,
|
||||||
|
so it's safe to have both services installed on a system. For the
|
||||||
|
hand-over to work it requires that the WDT driver supports the safe exit
|
||||||
|
functionality where `"V"` is written to the device before closing the
|
||||||
|
device descriptor. If the kernel driver has been built without this,
|
||||||
|
the only option is to remove `/libexec/finit/watchdogd` or build without
|
||||||
|
it at configure time.
|
||||||
|
|
||||||
|
[bootstrap]: bootstrap.md
|
||||||
|
|
||||||
|
|
||||||
|
keventd
|
||||||
|
-------
|
||||||
|
|
||||||
|
The kernel event daemon bundled with Finit is a simple uevent monitor
|
||||||
|
for `/sys/class/power_supply`. It provides the `sys/pwr/ac` condition,
|
||||||
|
which can be useful to prevent power hungry services like anacron to run
|
||||||
|
when a laptop is only running on battery, for instance.
|
||||||
|
|
||||||
|
Since keventd is not an integral part of Finit yet it is not enabled by
|
||||||
|
default. Enable it using `./configuure --with-keventd`. The bundled
|
||||||
|
contrib build scripts for Debian, Alpine, and Void have this enabled.
|
||||||
|
|
||||||
|
This daemon is planned to be extended with monitoring of other uevents,
|
||||||
|
patches and ideas are welcome in the issue tracker.
|
||||||
|
|||||||
+138
-25
@@ -8,7 +8,8 @@ Hooks & Plugins
|
|||||||
* [Shutdown Hooks](#shutdown-hooks)
|
* [Shutdown Hooks](#shutdown-hooks)
|
||||||
|
|
||||||
Finit can be extended to add general functionality in the form of I/O
|
Finit can be extended to add general functionality in the form of I/O
|
||||||
monitors, or hook plugins.
|
monitors, or hook plugins. It is even possible to run scripts at these
|
||||||
|
hook points, see below.
|
||||||
|
|
||||||
The following sections detail existing plugins and hook points. For
|
The following sections detail existing plugins and hook points. For
|
||||||
more information, see the plugins listed below.
|
more information, see the plugins listed below.
|
||||||
@@ -34,26 +35,75 @@ For your convenience a set of *optional* plugins are available:
|
|||||||
* *dbus.so*: Setup and start system message bus, D-Bus, at boot.
|
* *dbus.so*: Setup and start system message bus, D-Bus, at boot.
|
||||||
_Optional plugin._
|
_Optional plugin._
|
||||||
|
|
||||||
|
* *hook-scripts.so*: Trigger the execution of scripts from plugin hook
|
||||||
|
points (see [Hooks](#hooks)). _Optional plugin._
|
||||||
|
|
||||||
|
This plugin is particularly useful for early boot debugging that needs
|
||||||
|
to take place before regular services are available.
|
||||||
|
|
||||||
|
For example, say that you want to enable some kernel tracing before
|
||||||
|
modules are loaded. With hook scripts, you can just drop in a shell
|
||||||
|
script in `/libexec/finit/hook/mount/all/` that will poke the right
|
||||||
|
control files in tracefs.
|
||||||
|
|
||||||
|
Scripts are located in `/libexec/finit/hook` by default, this can be
|
||||||
|
customized at build-time using the `--with-hook-scripts-path=PATH`
|
||||||
|
argument to `configure`.
|
||||||
|
|
||||||
* *hotplug.so*: Setup and start either udev or mdev hotplug daemon, if
|
* *hotplug.so*: Setup and start either udev or mdev hotplug daemon, if
|
||||||
available.
|
available. Enabled by default.
|
||||||
|
|
||||||
|
> See the [Services](config.md#services) section in the configuration
|
||||||
|
> guide for an example how to run `mdevd`, alternative to plain mdev.
|
||||||
|
|
||||||
* *rtc.so*: Restore and save system clock from/to RTC on boot/halt.
|
* *rtc.so*: Restore and save system clock from/to RTC on boot/halt.
|
||||||
|
Enabled by default.
|
||||||
|
|
||||||
* *modules-load.so*: Scans /etc/modules-load.d for modules to modprobe.
|
* *modules-load.so*: Scans `/etc/modules-load.d/*.conf` for modules to
|
||||||
|
load using `modprobe`. Each file can contain multiple lines with the
|
||||||
|
name of the module to load. Any line starting with the standard UNIX
|
||||||
|
comment character, `#`, or `;`, is skipped.
|
||||||
|
|
||||||
|
Modules are by default loaded in runlevel `S` using the `task` stanza.
|
||||||
|
Each module gets a unique `name:modprobe.foo`, and optional`:ID`. The
|
||||||
|
runlevel can be changed per file using:
|
||||||
|
|
||||||
|
set runlevel 2345
|
||||||
|
|
||||||
|
The `:ID` is a globally incremented index, which can be disabled per
|
||||||
|
file (anywhere) using the following config line:
|
||||||
|
|
||||||
|
set noindex
|
||||||
|
|
||||||
|
To change the index used by the plugin:
|
||||||
|
|
||||||
|
set index 1234
|
||||||
|
|
||||||
|
**Note:** unlike the traditional .conf `module` directive, which load
|
||||||
|
any listed module immediately, this plugin creates a background `task`
|
||||||
|
which load the module(s) in the background. The program is modprobe,
|
||||||
|
`/sbin/modprobe`, which you can override per .conf file:
|
||||||
|
|
||||||
|
set modprobe /path/to/maybe-a-modprobe-wrapper
|
||||||
|
|
||||||
|
Since these tasks run in the background, they usually return `[ OK ]`
|
||||||
|
at boot, unless the modprobe tool does not exist. Check syslog for
|
||||||
|
warnings and the actual status of the operation using `initctl`.
|
||||||
|
|
||||||
* *netlink.so*: Listens to Linux kernel Netlink events for gateway and
|
* *netlink.so*: Listens to Linux kernel Netlink events for gateway and
|
||||||
interfaces. These events are then sent to the Finit service monitor
|
interfaces. These events are then sent to the Finit service monitor
|
||||||
for services that may want to be SIGHUP'ed on new default route or
|
for services that may want to be SIGHUP'ed on new default route or
|
||||||
interfaces going up/down.
|
interfaces going up/down. Enabled by default.
|
||||||
|
|
||||||
* *resolvconf.so*: Setup necessary files for `resolvconf` at startup.
|
* *resolvconf.so*: Setup necessary files for `resolvconf` at startup.
|
||||||
_Optional plugin._
|
_Optional plugin._
|
||||||
|
|
||||||
* *tty.so*: Watches `/dev`, using inotify, for new device nodes (TTY's)
|
* *tty.so*: Watches `/dev`, using inotify, for new device nodes (TTY's)
|
||||||
to start/stop getty consoles on them on demand. Useful when plugging
|
to start/stop getty consoles on them on demand. Useful when plugging
|
||||||
in a usb2serial converter to login to your embedded device.
|
in a usb2serial converter to login to your embedded device. Enabled
|
||||||
|
by default.
|
||||||
|
|
||||||
* *urandom.so*: Setup random seed at startup.
|
* *urandom.so*: Setup random seed at startup. Enabled by default.
|
||||||
|
|
||||||
* *x11-common.so*: Setup necessary files for X-Window. _Optional plugin._
|
* *x11-common.so*: Setup necessary files for X-Window. _Optional plugin._
|
||||||
|
|
||||||
@@ -67,38 +117,101 @@ state, etc. Available hook points are:
|
|||||||
Hooks
|
Hooks
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
In the below listings, the first label is the hook point for a C plugin,
|
||||||
|
the second is the condition name and hook script path. A hook script is
|
||||||
|
a plain shell script, or program, that does a very small dedicated job
|
||||||
|
at the below hook points.
|
||||||
|
|
||||||
|
See [Run-parts Scripts](config.md#run-parts-scripts) for details on the
|
||||||
|
requirements, possibilities, and *limitations* of hook scripts.
|
||||||
|
|
||||||
|
All hook scripts are called with at least one environment variable set,
|
||||||
|
the hook name, useful when reusing the same hook script for multiple
|
||||||
|
hook points:
|
||||||
|
|
||||||
|
- `FINIT_HOOK_NAME`: set to the second label, e.g., `hook/net/up`
|
||||||
|
- `FINIT_SHUTDOWN`: set for `hook/sys/shutdown` and later to one
|
||||||
|
of `halt`, `poweroff`, or `reboot`.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
$ mkdir -p /libexec/finit/hook/sys/down
|
||||||
|
$ cat <<EOF >/libexec/finit/hook/sys/foo.sh
|
||||||
|
#!/bin/sh
|
||||||
|
echo 'I run just before the reboot() syscall at shutdown/reboot'
|
||||||
|
echo 'I have access to /dev since devtmpfs is exempt from umount'
|
||||||
|
echo "FINIT_HOOK_NAME: $FINIT_HOOK_NAME"
|
||||||
|
if [ -n "$FINIT_SHUTDOWN" ]; then
|
||||||
|
echo "FINIT_SHUTDOWN: $FINIT_SHUTDOWN"
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
EOF
|
||||||
|
$ chmod +x /libexec/finit/hook/sys/foo.sh
|
||||||
|
|
||||||
|
> **Note:** to use hook scripts, even for pre-bootstrap and pre-shutdown
|
||||||
|
> tasks, you must build with `configure --enable-hook-scripts-plugin`.
|
||||||
|
|
||||||
### Bootstrap Hooks
|
### Bootstrap Hooks
|
||||||
|
|
||||||
* `HOOK_ROOTFS_UP`: When `finit.conf` has been read and `/` has is
|
* `HOOK_BANNER`, `hook/sys/banner`: The very first point at which a
|
||||||
mounted — very early
|
plugin can run. Intended to be used as a banner replacement.
|
||||||
|
Essentially this runs just before entering runlevel S. Assume nothing
|
||||||
|
is available, so be prepared to use absolute paths, etc.
|
||||||
|
|
||||||
* `HOOK_BASEFS_UP`: All of `/etc/fstab` is mounted, swap is available
|
* `HOOK_ROOTFS_UP`, `hook/mount/root`: When `finit.conf` has been read
|
||||||
and default init signals are setup
|
and `/` has is mounted — very early
|
||||||
|
|
||||||
* `HOOK_NETWORK_UP`: System bootstrap, runlevel S, has completed and
|
* `HOOK_MOUNT_ERROR`, `hook/mount/error`: executed if `mount -a` fails
|
||||||
networking is up (`lo` is up and the `network` script has run)
|
|
||||||
|
|
||||||
* `HOOK_SVC_UP`: All services in the active runlevel has been launched
|
* `HOOK_MOUNT_POST`, `hook/mount/post`: always executed after `mount -a`
|
||||||
|
|
||||||
* `HOOK_SYSTEM_UP`: All services *and* everything in `/etc/finit.d`
|
* `HOOK_BASEFS_UP`, `hook/mount/all`: All of `/etc/fstab` is mounted,
|
||||||
has been launched
|
swap is available and default init signals are setup
|
||||||
|
|
||||||
|
* `HOOK_SVC_PLUGIN`, `hook/svc/plugin`: Called in `conf_init()` right
|
||||||
|
before loading `/etc/finit.conf`. For plugins to register any early
|
||||||
|
run/task/services, please do NOT use any earlier hook point. That
|
||||||
|
will cause uninitialized rlimits that lead to unpredictable results
|
||||||
|
when Finit later tries to start the run/task/service.
|
||||||
|
|
||||||
|
* `HOOK_NETWORK_UP`, `hook/net/up`: System bootstrap, runlevel S, has
|
||||||
|
completed and networking is up (`lo` is up and the `network` script
|
||||||
|
has run)
|
||||||
|
|
||||||
|
* `HOOK_SVC_UP`, `hook/svc/up`: All services in the active runlevel have
|
||||||
|
been launched
|
||||||
|
|
||||||
|
* `HOOK_SYSTEM_UP`, `hook/sys/up`: All services *and* everything in
|
||||||
|
`/etc/finit.d` has been launched
|
||||||
|
|
||||||
### Runtime Hooks
|
### Runtime Hooks
|
||||||
|
|
||||||
* `HOOK_SVC_RECONF`: Called when the user has changed something in the
|
* `HOOK_SVC_RECONF`, N/A: Called when the user has changed something in
|
||||||
`/etc/finit.d` directory and issued `SIGHUP`. The hook is called when
|
the `/etc/finit.d` directory and issued `SIGHUP`. The hook is called
|
||||||
all modified/removed services have been stopped. When the hook has
|
when all modified/removed services have been stopped. When the hook
|
||||||
completed, Finit continues to start all modified and new services.
|
has completed, Finit continues to start all modified and new services.
|
||||||
|
|
||||||
* `HOOK_RUNLEVEL_CHANGE`: Called when the user has issued a runlevel
|
* `HOOK_RUNLEVEL_CHANGE`, N/A: Called when the user has issued a
|
||||||
change. The hook is called when services not matching the new
|
runlevel change. The hook is called when services not matching the
|
||||||
runlevel have been been stopped. When the hook has completed, Finit
|
new runlevel have been been stopped. When the hook has completed,
|
||||||
continues to start all services in the new runlevel.
|
Finit continues to start all services in the new runlevel.
|
||||||
|
|
||||||
### Shutdown Hooks
|
### Shutdown Hooks
|
||||||
|
|
||||||
* `HOOK_SHUTDOWN`: Called at shutdown/reboot, right before all
|
* `HOOK_NETWORK_DN`, `hook/net/down`: Called right after having changed
|
||||||
services are sent `SIGTERM`
|
to runlevel 6, or 0, when all services have received their 'stop' signal.
|
||||||
|
|
||||||
|
* `HOOK_SHUTDOWN`, `hook/sys/shutdown`: Called at shutdown/reboot, right
|
||||||
|
before all services are sent `SIGTERM`
|
||||||
|
|
||||||
|
* `HOOK_SVC_DN`, `hook/svc/down`: In shutdown/reboot, all services and
|
||||||
|
non-reserved processes have been killed. **Note:** only hook scripts
|
||||||
|
can run here!
|
||||||
|
|
||||||
|
* `HOOK_SYSTEM_DN`, `hook/sys/down`: In shutdown/reboot, called after
|
||||||
|
all non-reserved file systems have been unmounted, just before Finit
|
||||||
|
tells the kernel to reboot or shut down. **Note:** only hook scripts
|
||||||
|
can run here!
|
||||||
|
|
||||||
Plugins like `tty.so` extend finit by acting on events, they are called
|
Plugins like `tty.so` extend finit by acting on events, they are called
|
||||||
I/O plugins and are called from the finit main loop when `poll()`
|
I/O plugins and are called from the finit main loop when `poll()`
|
||||||
|
|||||||
+55
-1
@@ -1,7 +1,59 @@
|
|||||||
Finit Services
|
Finit Services
|
||||||
==============
|
==============
|
||||||
|
|
||||||

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

|
||||||
|
|
||||||
The current state depends on the two following conditions:
|
The current state depends on the two following conditions:
|
||||||
|
|
||||||
* `E`: Service enabled. In order for `E` to be satisfied, the service
|
* `E`: Service enabled. In order for `E` to be satisfied, the service
|
||||||
|
|||||||
+17
-9
@@ -12,28 +12,36 @@ have been adopted:
|
|||||||
Same effect as `finit q`, `init q`, or `initctl reload`, reloads all
|
Same effect as `finit q`, `init q`, or `initctl reload`, reloads all
|
||||||
*.conf files in `/etc/finit.d/`
|
*.conf files in `/etc/finit.d/`
|
||||||
|
|
||||||
|
This also restarts the API (initctl) socket, like SysV init and systemd
|
||||||
|
does on USR1 with their FIFO/D-Bus.
|
||||||
|
|
||||||
|
|
||||||
`SIGUSR1`
|
`SIGUSR1`
|
||||||
---------
|
---------
|
||||||
|
|
||||||
Calls shutdown hooks, including `HOOK_SHUTDOWN`, stopping all running
|
Since Finit 4.1 this signal causes Finit to restart its API (initctl)
|
||||||
processes, and unmounts all file systems. Then tells kernel to halt.
|
socket, like SysV init and systemd does on USR1 with their FIFO/D-Bus.
|
||||||
Most people these days want `SIGUSR2` though.
|
|
||||||
|
Finit <= 4.0 performed a system halt (like USR2 without power-off), but
|
||||||
|
this caused compatibility problems with systemd and sysvinit on desktop
|
||||||
|
systems. Hence, since Finit 4.1 it is no longer possible to halt a
|
||||||
|
system with a signal.
|
||||||
|
|
||||||
SysV init and systemd use this to re-open their FIFO/D-Bus.
|
|
||||||
|
|
||||||
`SIGUSR2`
|
`SIGUSR2`
|
||||||
---------
|
---------
|
||||||
|
|
||||||
Like SIGUSR1, but tell kernel to power-off the system, if ACPI or
|
Calls shutdown hooks, including `HOOK_SHUTDOWN`, stopping all running
|
||||||
similar exists to actually do this. If the kernel fails power-off,
|
processes, and unmounts all file systems. Then tells kernel to power
|
||||||
Finit falls back to halt.
|
off the system, if ACPI or similar exists to actually do this. If the
|
||||||
|
kernel fails power-off, Finit falls back to halt.
|
||||||
|
|
||||||
SysV init N/A, systemd dumps its internal state to log.
|
SysV init N/A, systemd dumps its internal state to log.
|
||||||
|
|
||||||
`SIGTERM`
|
`SIGTERM`
|
||||||
---------
|
---------
|
||||||
|
|
||||||
Like `SIGUSR1`, but tell kernel to reboot the system when done.
|
Like `SIGUSR2`, but tell kernel to reboot the system when done.
|
||||||
|
|
||||||
SysV init N/A, systemd rexecutes itself.
|
SysV init N/A, systemd rexecutes itself.
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 230 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 164 KiB |
+19
-23
@@ -1,8 +1,6 @@
|
|||||||
# From https://github.com/collectd/collectd/blob/master/configure.ac
|
# From https://github.com/collectd/collectd/blob/master/configure.ac
|
||||||
# Dependency handling currently unused
|
# Dependency handling currently unused
|
||||||
|
|
||||||
define([toupper], [translit([$1], [a-z], [A-Z])])
|
|
||||||
define([sanitize], [translit([$1], [-], [_])])
|
|
||||||
define([enadis], [ifelse([$1], [yes], [disable], [enable])])
|
define([enadis], [ifelse([$1], [yes], [disable], [enable])])
|
||||||
|
|
||||||
# AC_PLUGIN(name, default, info)
|
# AC_PLUGIN(name, default, info)
|
||||||
@@ -10,27 +8,25 @@ define([enadis], [ifelse([$1], [yes], [disable], [enable])])
|
|||||||
AC_DEFUN([AC_PLUGIN],[
|
AC_DEFUN([AC_PLUGIN],[
|
||||||
m4_divert_once([HELP_ENABLE], [
|
m4_divert_once([HELP_ENABLE], [
|
||||||
Optional Plugins:])
|
Optional Plugins:])
|
||||||
|
define(PLUGGY, m4_translit([$1],[a-z-][A-Z-]))dnl
|
||||||
|
AC_ARG_ENABLE([$1-plugin], AS_HELP_STRING([--enadis($2)-$1-plugin], [$3]), [
|
||||||
|
if test "x$enableval" = "xyes"; then
|
||||||
|
enable_plugin="yes"
|
||||||
|
else
|
||||||
enable_plugin="no"
|
enable_plugin="no"
|
||||||
define(pluggy, sanitize($1))
|
fi], [
|
||||||
define(PLUGGY, toupper(pluggy))
|
if test "x$enable_all_plugins" = "xauto"; then
|
||||||
AC_ARG_ENABLE([$1-plugin], AS_HELP_STRING([--enadis($2)-$1-plugin], [$3]), [
|
if test "x$2" = "xyes"; then
|
||||||
if test "x$enableval" = "xyes"; then
|
enable_plugin="yes"
|
||||||
enable_plugin="yes"
|
|
||||||
else
|
else
|
||||||
enable_plugin="no"
|
enable_plugin="no"
|
||||||
fi], [
|
|
||||||
if test "x$enable_all_plugins" = "xauto"; then
|
|
||||||
if test "x$2" = "xyes"; then
|
|
||||||
enable_plugin="yes"
|
|
||||||
else
|
|
||||||
enable_plugin="no"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
enable_plugin="$enable_all_plugins"
|
|
||||||
fi])
|
|
||||||
if test "x$enable_plugin" = "xyes"; then
|
|
||||||
AC_DEFINE([HAVE_]PLUGGY[_PLUGIN], 1, [Define to 1 if the $1 plugin is enabled.])
|
|
||||||
plugins="$1 $plugins"
|
|
||||||
fi
|
fi
|
||||||
AM_CONDITIONAL([BUILD_]PLUGGY[_PLUGIN], test "x$enable_plugin" = "xyes")
|
else
|
||||||
enable_pluggy="$enable_plugin"])
|
enable_plugin="$enable_all_plugins"
|
||||||
|
fi])
|
||||||
|
if test "x$enable_plugin" = "xyes"; then
|
||||||
|
AC_DEFINE(HAVE_[]m4_translit($1,[-a-z],[_A-Z])_PLUGIN, 1, [Define to 1 if the $1 plugin is enabled.])
|
||||||
|
plugins="$1 $plugins"
|
||||||
|
fi
|
||||||
|
|
||||||
|
AM_CONDITIONAL(BUILD_[]m4_translit($1,[-a-z],[_A-Z])_PLUGIN, test "x$enable_plugin" = "xyes")])
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
Makefile
|
||||||
|
Makefile.in
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
dist_man8_MANS = finit.8 initctl.8
|
||||||
|
dist_man5_MANS = finit.conf.5
|
||||||
+348
@@ -0,0 +1,348 @@
|
|||||||
|
.\" Hey, EMACS: -*- nroff -*-
|
||||||
|
.\" First parameter, NAME, should be all caps
|
||||||
|
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||||
|
.\" other parameters are allowed: see man(7), man(1)
|
||||||
|
.Dd Apr 22, 2023
|
||||||
|
.\" Please adjust this date whenever revising the manpage.
|
||||||
|
.Dt FINIT 8 SMM
|
||||||
|
.Os Linux
|
||||||
|
.Sh NAME
|
||||||
|
.Nm finit
|
||||||
|
.Nd Fast init for Linux systems
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm /sbin/finit
|
||||||
|
.Op --
|
||||||
|
.Op debug
|
||||||
|
.Op finit.cond=foo[,bar[,baz]]
|
||||||
|
.Op finit.config=/path/to/alt/finit.conf
|
||||||
|
.Op finit.debug
|
||||||
|
.Op finit.fstab=/etc/fstab.alt
|
||||||
|
.Op finit.status=<on,off>
|
||||||
|
.Op finit.status_style=<classic,modern>
|
||||||
|
.Op loglevel=<0-7>
|
||||||
|
.Op panic=SEC
|
||||||
|
.Op quiet
|
||||||
|
.Op rescue | recover
|
||||||
|
.Op single | S
|
||||||
|
.Nm /sbin/telinit
|
||||||
|
.Op Fl hv
|
||||||
|
.Op q | Q | 0-9
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
Fast init for Linux systems. Reverse engineered from the EeePC
|
||||||
|
fastinit, 10+ years ago by Claudio Matsuoka, "gaps filled with frog
|
||||||
|
DNA ...". Focus is on small and embedded systems, although Finit is
|
||||||
|
fully usable on server and desktop systems as well.
|
||||||
|
.Pp
|
||||||
|
Features include:
|
||||||
|
.Bl -bullet -width 1n -compact
|
||||||
|
.It
|
||||||
|
Runlevels, defined per service
|
||||||
|
.It
|
||||||
|
One-shot tasks, services (daemons), or SysV init start/stop scripts
|
||||||
|
.It
|
||||||
|
Runparts and
|
||||||
|
.Pa /etc/rc.local
|
||||||
|
support
|
||||||
|
.It
|
||||||
|
Process supervision similar to
|
||||||
|
.Xr systemd 8
|
||||||
|
.It
|
||||||
|
Sourcing environment files
|
||||||
|
.It
|
||||||
|
Conditions for network/process/custom dependencies
|
||||||
|
.It
|
||||||
|
Process readiness notification for synchronizing system startup as well
|
||||||
|
as reconfiguration at runtime. Natively PID files are used, but systemd
|
||||||
|
.Cm sd_notify()
|
||||||
|
and s6 notification is also supported.
|
||||||
|
.It
|
||||||
|
Limited support for
|
||||||
|
.Xr tmpfiles.d 5 ,
|
||||||
|
no aging, attributes, or subvolumes
|
||||||
|
.It
|
||||||
|
Pre/Post script actions
|
||||||
|
.It
|
||||||
|
Tooling to enable/disable services
|
||||||
|
.It
|
||||||
|
Built-in getty
|
||||||
|
.It
|
||||||
|
Built-in watchdog, with support for hand-over to
|
||||||
|
.Lk https://troglobit.com/watchdogd.html watchdogd
|
||||||
|
.It
|
||||||
|
Built-in support for Debian/BusyBox
|
||||||
|
.Pa /etc/network/interfaces
|
||||||
|
.It
|
||||||
|
Cgroups v2, both configuration and monitoring in `initctl top`
|
||||||
|
.It
|
||||||
|
Plugin support for customization
|
||||||
|
.It
|
||||||
|
Proper rescue mode with bundled `sulogin` for protected maintenance shell
|
||||||
|
.El
|
||||||
|
.Sh BOOTPARAM
|
||||||
|
.Nm
|
||||||
|
support the following command line parameters to alter the behavior
|
||||||
|
at boot. Notice the
|
||||||
|
.Cm --
|
||||||
|
separator needed to tell the kernel which paramters should be given to
|
||||||
|
PID 1. For more information on this, and available kernel command line
|
||||||
|
options, see
|
||||||
|
.Xr bootparam 7 .
|
||||||
|
.Bl -tag -width pid -offset indent
|
||||||
|
.It Cm debug
|
||||||
|
Enable kernel debug. Debug messages are printed to the console until
|
||||||
|
Finit starts up, unless
|
||||||
|
.Cm loglevel=7
|
||||||
|
(below) is used.
|
||||||
|
.It Cm finit.cond=foo[,bar[,baz]]
|
||||||
|
set
|
||||||
|
.Cm <boot/foo>
|
||||||
|
condition, optionally multiple conditions can be set using the same
|
||||||
|
option, separated with a comma. Alternatively, multiple
|
||||||
|
.Cm foo.cond=arg
|
||||||
|
can be given. Each will result in a
|
||||||
|
.Cm <boot/arg>
|
||||||
|
condition being set to control the rest of the system bootstrap.
|
||||||
|
.Pp
|
||||||
|
Very useful for selecting different boot modes, e.g. manufacturing test,
|
||||||
|
firmware upgrade, or rescue mode.
|
||||||
|
.Pp
|
||||||
|
.Sy Note:
|
||||||
|
.Cm <boot/...>
|
||||||
|
conditions cannot be cleared with
|
||||||
|
.Nm initctl !
|
||||||
|
.It Cm finit.config=/path/to/alternative/finit.conf
|
||||||
|
override the compile-time bootstrap config file, default:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
./configure --with-config=/etc/finit.conf
|
||||||
|
.Ed
|
||||||
|
Useful when starting up in various rescue mode, factory, or
|
||||||
|
production test setups. Use the top-level configuration file
|
||||||
|
directive
|
||||||
|
.Cm rcsd Ar /path/to/finit.d
|
||||||
|
to override the default rcS.d directory.
|
||||||
|
.It Cm finit.debug
|
||||||
|
Enable Finit debug messages on system console and log. Sometimes useful
|
||||||
|
when doing board bringup. Before the system log daemon has started,
|
||||||
|
Finit use the kernel ring buffer,
|
||||||
|
.Pa /dev/kmsg .
|
||||||
|
.It Cm finit.fstab=/path/to/fstab.alt
|
||||||
|
Tell
|
||||||
|
.Nm
|
||||||
|
to use an alternate
|
||||||
|
.Cm fstab
|
||||||
|
to mount the file system from. Remember, this file must be on the
|
||||||
|
.Cm root=...
|
||||||
|
file system provided to Finit from the kernel. If this file is missing,
|
||||||
|
.Nm
|
||||||
|
falls back to its built-in default, which can be changed at build time
|
||||||
|
using the
|
||||||
|
.Cm --with-fstab=/path/to/footab
|
||||||
|
configure option. It is even possible to completely disable the
|
||||||
|
built-in using
|
||||||
|
.Cm --without-fstab ,
|
||||||
|
meaning
|
||||||
|
.Nm
|
||||||
|
.Sy must
|
||||||
|
be started with the
|
||||||
|
.Cm finit.fstab
|
||||||
|
option.
|
||||||
|
.Pp
|
||||||
|
Should
|
||||||
|
.Nm
|
||||||
|
discover that there is no fstab file available, including the fallback,
|
||||||
|
it triggers the same failure mode as when
|
||||||
|
.Cm fsck
|
||||||
|
fails, starting
|
||||||
|
.Xr sulogin 8 ,
|
||||||
|
if that is availble. When
|
||||||
|
.Cm sulogin
|
||||||
|
is missing, or when the user exits from
|
||||||
|
.Cm sulogin ,
|
||||||
|
the system is rebooted.
|
||||||
|
.Pp
|
||||||
|
Default fstab, unless changed at build-time:
|
||||||
|
.Pa /etc/fstab
|
||||||
|
.It Cm finit.status=<on,off>
|
||||||
|
Control finit boot progress, including banner. This used to be called
|
||||||
|
.Cm finit.show_status ,
|
||||||
|
which still works but is deprecated.
|
||||||
|
.It Cm finit.status_style=<classic,modern>
|
||||||
|
Set Finit boot progress style, when enabled.
|
||||||
|
.It Cm loglevel=<0-7>
|
||||||
|
set the kernel's log level, which is more granular than
|
||||||
|
.Cm debug .
|
||||||
|
Also, when
|
||||||
|
.Cm loglevel=7 ,
|
||||||
|
Finit will
|
||||||
|
.Em not disable
|
||||||
|
kernel logs to the console. This is very useful when debugging the
|
||||||
|
kernel at system bring-up. Since
|
||||||
|
.Cm loglevel=7
|
||||||
|
is the same as
|
||||||
|
.Cm debug
|
||||||
|
this means you have to use
|
||||||
|
.Cm quiet
|
||||||
|
for a quiet boot, until sysklogd takes over logging of kernel events.
|
||||||
|
.It Cm panic=SEC
|
||||||
|
By default the kernel does not reboot after a kernel panic. This
|
||||||
|
setting will cause a kernel reboot after
|
||||||
|
.Ar SEC
|
||||||
|
seconds.
|
||||||
|
.It Cm quiet
|
||||||
|
Suppress kernel logging to console, except for warnings and errors.
|
||||||
|
Also, see
|
||||||
|
.Cm loglevel
|
||||||
|
and
|
||||||
|
.Cm quiet
|
||||||
|
above.
|
||||||
|
.It Cm rescue | recover
|
||||||
|
Start rescue/maintenance mode. If your system comes with the bundled
|
||||||
|
.Cm sulogin
|
||||||
|
program (Finit, or from util-linux/Busybox), you will be given a root
|
||||||
|
login to a maintenance shell. However, if
|
||||||
|
.Cm sulogin
|
||||||
|
is missing, the file
|
||||||
|
.Pa /lib/finit/rescue.conf
|
||||||
|
is read and the system booted in a limited fallback mode. See
|
||||||
|
.Xr finit.conf 5
|
||||||
|
for more information.
|
||||||
|
.It Cm single | S
|
||||||
|
Single user mode, runlevel 1, in Finit. Useful to debug problems with
|
||||||
|
the regular runlevel. All services and TTYs in
|
||||||
|
.Cm [1]
|
||||||
|
will be started, e.g., a
|
||||||
|
.Cm tty [1] @console nologin
|
||||||
|
configuration presents you with a root console without login.
|
||||||
|
.Pp
|
||||||
|
.Sy Note:
|
||||||
|
by definition, single user mode does not have networking enabled. This
|
||||||
|
is also true for runlevel 1.
|
||||||
|
.El
|
||||||
|
.Sh BOOTING
|
||||||
|
.Pp
|
||||||
|
Before laucnhing services, the system needs to be bootstrapped. This
|
||||||
|
involves mounting all filesystems (not already mounted by an initramfs)
|
||||||
|
in
|
||||||
|
.Pa /etc/fstab ,
|
||||||
|
or any alternate
|
||||||
|
.Pa fstab
|
||||||
|
file provided on the Finit command line using
|
||||||
|
.Cm finit.fstab ,
|
||||||
|
ensuring that necessary filesystems like:
|
||||||
|
.Pa /dev ,
|
||||||
|
.Pa /proc ,
|
||||||
|
.Pa /sys ,
|
||||||
|
and
|
||||||
|
.Pa /run
|
||||||
|
are available and can provide the system with the services required.
|
||||||
|
.Pp
|
||||||
|
With that out of the way, a set of plugins take over:
|
||||||
|
.Pp
|
||||||
|
.Bl -tag -width bootmisc.so -offset indent
|
||||||
|
.It Cm bootmisc.so
|
||||||
|
Cleans up stale files from previous boots and default directories are
|
||||||
|
created in tmpfs filesystems
|
||||||
|
.It Cm modprobe.so
|
||||||
|
Probes kernel modules required by the system
|
||||||
|
.It Cm procps.so
|
||||||
|
Set kernel variables from
|
||||||
|
.Pa /etc/sysctl.conf
|
||||||
|
et al
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
When the plugins are done, finit reads
|
||||||
|
.Pa /etc/finit.conf
|
||||||
|
and all other enabled services in
|
||||||
|
.Pa /etc/finit.d/* .
|
||||||
|
First all services, run/tasks in runlevel S (bootStrap) are started,
|
||||||
|
When all run/tasks have completed, Finit changes to the configured
|
||||||
|
runlevel (default 2), Processes are started in parallel, in dependency
|
||||||
|
order according to their conditions.
|
||||||
|
.Pp
|
||||||
|
When all services and run/tasks have been started, the console progress
|
||||||
|
is disabled and all configured getty services are started.
|
||||||
|
.Sh CONDITIONS
|
||||||
|
The condition subysystem in Finit was initially created to track PID
|
||||||
|
files of daemons. If service/task B requires service A to have started,
|
||||||
|
Finit waits for the PID file of service A to be created/updated before
|
||||||
|
it starts service B. Conversely, if service A is stopped and its PID
|
||||||
|
file removed, service B is also stopped.
|
||||||
|
.Pp
|
||||||
|
The following condition families are available today:
|
||||||
|
.Pp
|
||||||
|
.Bl -tag -width service -offset indent
|
||||||
|
.It Cm net
|
||||||
|
Linux netlink events, e.g. net/route/default, net/eth0/up, and
|
||||||
|
net/et0/running
|
||||||
|
.It Cm pid
|
||||||
|
PID files basd on the service declaration
|
||||||
|
.Cm name:id ,
|
||||||
|
gives the condition pid/name:id
|
||||||
|
.It Cm service
|
||||||
|
Tracks run/task/service state stansitions, including readiness. E.g.,
|
||||||
|
.Cm service/foo/ready
|
||||||
|
can be used as a condition for service
|
||||||
|
.Cm bar ,
|
||||||
|
provided
|
||||||
|
.Cm foo
|
||||||
|
properly signals its readiness to Finit.
|
||||||
|
.It Cm sys
|
||||||
|
System conditions, e.g. sys/key/ctrlaltdel and sys/pwr/fail
|
||||||
|
.It Cm usr
|
||||||
|
User conditions, assert and deassert using
|
||||||
|
.Cm initctl cond [set|clr] foo
|
||||||
|
.El
|
||||||
|
.Sh SIGNALS
|
||||||
|
PID 1 is the only process that by default blocks all signals. Finit
|
||||||
|
allows for the following signals to control operation, but recommends
|
||||||
|
instead using the
|
||||||
|
.Xr initctl 8
|
||||||
|
tool.
|
||||||
|
.Pp
|
||||||
|
.Bl -tag -width TERM
|
||||||
|
.It HUP
|
||||||
|
Tell
|
||||||
|
.Nm
|
||||||
|
to reload its configuration file(s), same as
|
||||||
|
.Cm initctl reload
|
||||||
|
.It USR1
|
||||||
|
Restart API
|
||||||
|
.Cm ( initctl )
|
||||||
|
socket.
|
||||||
|
.It USR2
|
||||||
|
Tell
|
||||||
|
.Nm
|
||||||
|
to perform a system shutdown, same as
|
||||||
|
.Cm initctl poweroff
|
||||||
|
.It TERM
|
||||||
|
Like SIGUSR2 but performs a reboot, same as
|
||||||
|
.Cm initctl reboot
|
||||||
|
.It INT
|
||||||
|
Sent from kernel when Ctrl-Alt-Del is pressed (on the console), this
|
||||||
|
asserts the sys/key/ctrlaltdel condition, which can be used to start
|
||||||
|
tasks or services
|
||||||
|
.It PWR
|
||||||
|
Sent from a a power daemon on changes to UPS status, Finit asserts
|
||||||
|
the sys/pwr/fail condition
|
||||||
|
.El
|
||||||
|
.Sh FILES
|
||||||
|
.Bl -tag -width /etc/finit.d/available/*.conf -compact
|
||||||
|
.It Pa /etc/finit.conf
|
||||||
|
Main configuration file
|
||||||
|
.It Pa /etc/finit.d/*.conf
|
||||||
|
Static service definitions
|
||||||
|
.It Pa /etc/finit.d/available/*.conf
|
||||||
|
Available services
|
||||||
|
.It Pa /etc/finit.d/enabled/*.conf
|
||||||
|
Symlinks from available
|
||||||
|
.It Pa /run/finit/
|
||||||
|
Runtime files, including the condition subsystem
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr finit.conf 5
|
||||||
|
.Xr initctl 8
|
||||||
|
.Xr tmpfiles.d 5
|
||||||
|
.Sh AUTHORS
|
||||||
|
.Nm
|
||||||
|
was conceived and reverse engineered by Claudio Matsuoka. Since v1.0,
|
||||||
|
maintained by Joachim Wiberg, with contributions by many others.
|
||||||
@@ -0,0 +1,965 @@
|
|||||||
|
.\" Hey, EMACS: -*- nroff -*-
|
||||||
|
.\" First parameter, NAME, should be all caps
|
||||||
|
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||||
|
.\" other parameters are allowed: see man(7), man(1)
|
||||||
|
.Dd Apr 24, 2023
|
||||||
|
.Dt FINIT.CONF 5 SMM
|
||||||
|
.Os Linux
|
||||||
|
.Sh NAME
|
||||||
|
.Nm finit.conf
|
||||||
|
.Nd Finit configuration file format
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm /etc/finit.conf
|
||||||
|
.Nm /etc/finit.d/*.conf
|
||||||
|
.Nm /etc/finit.d/available/*.conf
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm finit
|
||||||
|
can be configured using only the original
|
||||||
|
.Pa /etc/finit.conf
|
||||||
|
file or in combination with
|
||||||
|
.Pa /etc/finit.d/*.conf .
|
||||||
|
Useful for package-based Linux distributions \(em each package can
|
||||||
|
provide its own "script" file.
|
||||||
|
.Pp
|
||||||
|
.Bl -tag -width /etc/finit.d/*.conf -offset indent -compact
|
||||||
|
.It Pa /etc/finit.conf
|
||||||
|
Main configuration file
|
||||||
|
.It Pa /etc/finit.d/*.conf
|
||||||
|
Snippets, usually one service per file
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
Not all configuration directives are available in
|
||||||
|
.Pa /etc/finit.d/*.conf
|
||||||
|
and some directives are only available at bootstrap, runlevel
|
||||||
|
.Cm S ,
|
||||||
|
see the section
|
||||||
|
.Sx Limitations
|
||||||
|
below for details.
|
||||||
|
.Sh FILES
|
||||||
|
.Bl -tag -width /etc/finit.d/available/*.conf -compact
|
||||||
|
.It Pa /etc/finit.conf
|
||||||
|
Main configuration file
|
||||||
|
.It Pa /etc/finit.d/*.conf
|
||||||
|
Static service definitions
|
||||||
|
.It Pa /etc/finit.d/available/*.conf
|
||||||
|
Available services
|
||||||
|
.It Pa /etc/finit.d/enabled/*.conf
|
||||||
|
Enabled services, symlinks from available
|
||||||
|
.El
|
||||||
|
.Sh FILE FORMAT
|
||||||
|
The file format is line based, empty lines and comments, lines starting
|
||||||
|
with `#', are ignored. A configuration directive starts with a keyword
|
||||||
|
followed by a space and the rest of the line is treated as the value.
|
||||||
|
.Pp
|
||||||
|
As of Finit v4.4, configuration directives can be broken up in multiple
|
||||||
|
lines using the continuation character `\\', and trailing comments are
|
||||||
|
also allowed. Example:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
# Escape \\# chars if you want them literal in, e.g., descriptions
|
||||||
|
service name:sysklogd [S123456789] \\
|
||||||
|
env:-/etc/default/sysklogd \\
|
||||||
|
syslogd -F $SYSLOGD_ARGS \\
|
||||||
|
-- System log daemon \\# 1 # Comments allowed now
|
||||||
|
.Ed
|
||||||
|
.Sh DIRECTIVES
|
||||||
|
This section lists all supported configuration directives. There also exist
|
||||||
|
deprecated directives, see the Markdown documentation for details on these.
|
||||||
|
.Pp
|
||||||
|
.Bl -tag -width 1n
|
||||||
|
.It Cm rlimit Oo hard|soft Oc Ar RESOURCE Aq LIMIT | unlimited
|
||||||
|
.Pp
|
||||||
|
Set the hard or soft limit for a resource, or both if that argument is
|
||||||
|
omitted.
|
||||||
|
.Ar RESOURCE
|
||||||
|
is the lower-case
|
||||||
|
.Cm RLIMIT_
|
||||||
|
string constants from
|
||||||
|
.Xr setrlimit 2 ,
|
||||||
|
without prefix. E.g. to set
|
||||||
|
.Cm RLIMIT_CPU ,
|
||||||
|
use
|
||||||
|
.Cm cpu .
|
||||||
|
.Pp
|
||||||
|
.Ar LIMIT
|
||||||
|
is an integer that depends on the resource being modified, see
|
||||||
|
the man page, or the kernel
|
||||||
|
.Pa /proc/PID/limits
|
||||||
|
file, for details.
|
||||||
|
Finit versions before v3.1 used
|
||||||
|
.Cm infinity
|
||||||
|
for
|
||||||
|
.Cm unlimited ,
|
||||||
|
which is still supported, albeit deprecated.
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
# No process is allowed more than 8MB of address space
|
||||||
|
rlimit hard as 8388608
|
||||||
|
|
||||||
|
# Core dumps may be arbitrarily large
|
||||||
|
rlimit soft core infinity
|
||||||
|
|
||||||
|
# CPU limit for all services, soft & hard = 10 sec
|
||||||
|
rlimit cpu 10
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
.Cm rlimit
|
||||||
|
can be set globally, in
|
||||||
|
.Pa /etc/finit.conf ,
|
||||||
|
or locally per each
|
||||||
|
.Pa /etc/finit.d/*.conf
|
||||||
|
read. I.e., a set of task/run/service stanzas can share the same
|
||||||
|
rlimits if they are in the same .conf.
|
||||||
|
.It Cm runlevel Aq N
|
||||||
|
The system runlevel to go to after bootstrap (S) has completed.
|
||||||
|
.Cm N
|
||||||
|
is the runlevel number 0-9, where 6 is reserved for reboot and 0 for
|
||||||
|
halt. All other can be used by operating system administrators.
|
||||||
|
Default: 2
|
||||||
|
.Pp
|
||||||
|
It s recommended to keep runlevel 1 as single-user mode, because
|
||||||
|
.Nm
|
||||||
|
disables networking in this mode.
|
||||||
|
.Pp
|
||||||
|
.Sy Note:
|
||||||
|
only read and executed in runlevel S (bootstrap).
|
||||||
|
.It Cm run Oo LVLS Oc Ao COND Ac Ar /path/to/cmd ARGS Op -- Optional description
|
||||||
|
One-shot command to run in sequence when entering a runlevel, with
|
||||||
|
optional arguments and description.
|
||||||
|
.Pp
|
||||||
|
.Cm run
|
||||||
|
commands are guaranteed to be completed before running the next
|
||||||
|
command. Highly useful if true serialization is needed. Usually
|
||||||
|
only used in the bootstrap (S) runlevel.
|
||||||
|
.Pp
|
||||||
|
.Cm Aq COND
|
||||||
|
conditions are described in
|
||||||
|
.Xr finit 8 ,
|
||||||
|
see also the
|
||||||
|
.Sx Examples
|
||||||
|
section below.
|
||||||
|
.It Cm task Oo LVLS Oc Ao COND Ac Ar /path/to/cmd ARGS Op -- Optional description
|
||||||
|
One-shot like
|
||||||
|
.Cm run ,
|
||||||
|
but starts in parallel with the next command.
|
||||||
|
.Pp
|
||||||
|
Both
|
||||||
|
.Cm run
|
||||||
|
and
|
||||||
|
.Cm task
|
||||||
|
commands are run in a shell, so pipes and redirects can be freely used:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
task [s] echo "foo" | cat >/tmp/bar
|
||||||
|
.Ed
|
||||||
|
.It Cm sysv Oo LVLS Oc Ao COND Ac Ar /path/to/script ARGS Op -- Optional description
|
||||||
|
Similar to
|
||||||
|
.Cm task
|
||||||
|
is the
|
||||||
|
.Cm sysv
|
||||||
|
stanza, which can be used to call SysV style start/stop scripts. The
|
||||||
|
primary intention for this command is to be able to re-use much of
|
||||||
|
existing setup and init scripts in Linux distributions.
|
||||||
|
.Pp
|
||||||
|
When entering an allowed runlevel, Finit calls
|
||||||
|
.Cm init-script start ,
|
||||||
|
when entering a disallowed runlevel, Finit calls
|
||||||
|
.Cm init-script stop ,
|
||||||
|
and if the Finit .conf, where the
|
||||||
|
.Cm sysv
|
||||||
|
stanza is declared, is modified, Finit calls
|
||||||
|
.Cm init-script restart
|
||||||
|
on
|
||||||
|
.Cm initctl reload .
|
||||||
|
Similar to how
|
||||||
|
.Cm service
|
||||||
|
stanzas work.
|
||||||
|
.Pp
|
||||||
|
Forking services started with
|
||||||
|
.Cm sysv
|
||||||
|
scripts can be monitored by Finit by declaring the PID file to look for:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
sysv pid:!/path/to/pidfile.pid /path/to/script ...
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
The leading '!' is to prevent Finit from managing the PID file, which is
|
||||||
|
the default behavior for the
|
||||||
|
.Cm pid:
|
||||||
|
command modifier.
|
||||||
|
.It Cm service Oo LVLS Oc Ao COND Ac Ar /path/to/daemon ARGS Op -- Optional description
|
||||||
|
Service, or daemon, to be monitored and automatically restarted if it
|
||||||
|
exits prematurely. Finit tries to restart services that die, by
|
||||||
|
default 10 times, before giving up and marking them as
|
||||||
|
.Em crashed .
|
||||||
|
After which they have to be restarted manually using
|
||||||
|
.Cm initctl restart NAME .
|
||||||
|
The number of restarts, the delay between each restart, and more is
|
||||||
|
configurable, see the options below.
|
||||||
|
.Pp
|
||||||
|
.Bd -filled -offset indent
|
||||||
|
.Sy Tip:
|
||||||
|
to allow endless restarts, see below option
|
||||||
|
.Cm respawn
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
For daemons that support it, we recommend appending
|
||||||
|
.Cm --foreground , --no-background , -n , -F ,
|
||||||
|
or similar command line argument to prevent them from forking off a
|
||||||
|
sub-process in the background. This is the most reliable way to monitor
|
||||||
|
a service.
|
||||||
|
.Pp
|
||||||
|
However, not all daemons support running in the foreground, or they may
|
||||||
|
start logging to the foreground as well, these are called forking
|
||||||
|
services and are supported using the same syntax as forking
|
||||||
|
.Cm sysv
|
||||||
|
services, using the
|
||||||
|
.Cm pid:!/path/to/pidfile.pid
|
||||||
|
command modifier syntax. There is an alternative syntax that may be
|
||||||
|
more intuitive, where Finit can also guess the PID file based on the
|
||||||
|
daemon's command name:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
service type:forking ntpd -- NTP daemon
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Here we let BusyBox
|
||||||
|
.Nm ntpd
|
||||||
|
daemonize itself. Finit uses the basename of the binary to guess the
|
||||||
|
PID file to watch for the PID:
|
||||||
|
.Pa /var/run/ntpd.pid .
|
||||||
|
If Finit guesses wrong, you have to submit the full
|
||||||
|
.Cm pid:!/path/to/file.pid
|
||||||
|
option to your service stanza.
|
||||||
|
.Pp
|
||||||
|
.Sy Example: in the case of
|
||||||
|
.Cm ospfd
|
||||||
|
(below), we omit the
|
||||||
|
.Cm -d
|
||||||
|
flag (daemonize) to prevent it from forking to the background:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
service [2345] <pid/zebra> /sbin/ospfd -- OSPF daemon
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
.Cm [2345]
|
||||||
|
denote the runlevels
|
||||||
|
.Cm ospfd
|
||||||
|
is allowed to run in, they are optional and default to runlevel 2-5 if
|
||||||
|
omitted.
|
||||||
|
.Pp
|
||||||
|
.Cm <pid/zebra>
|
||||||
|
is the condition for starting
|
||||||
|
.Cm ospfd .
|
||||||
|
In this example Finit waits for another service,
|
||||||
|
.Cm zebra ,
|
||||||
|
to have created its PID file in
|
||||||
|
.Pa /var/run/quagga/zebra.pid
|
||||||
|
before starting
|
||||||
|
.Cm ospfd .
|
||||||
|
Finit watches *all* files in
|
||||||
|
.Pa /var/run ,
|
||||||
|
for each file named
|
||||||
|
.Cm *.pid ,
|
||||||
|
.Cm */pid ,
|
||||||
|
Finit opens it and find the matching
|
||||||
|
.Cm NAME:ID
|
||||||
|
using the PID.
|
||||||
|
.Pp
|
||||||
|
Some services do not maintain a PID file and rather than patching each
|
||||||
|
application Finit provides a workaround. A
|
||||||
|
.Cm pid
|
||||||
|
modifier keyword can be set to have Finit automatically create (when
|
||||||
|
starting) and later remove (when stopping) the PID file. The file is
|
||||||
|
created in the
|
||||||
|
.Pa /var/run
|
||||||
|
directory using the
|
||||||
|
.Xr basename 3
|
||||||
|
of the service. The full syntax of the
|
||||||
|
.Cm pid
|
||||||
|
modifier is:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
pid[:[!][/path/to/]filename[.pid]]
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
For example, by adding
|
||||||
|
.Cm pid:/run/foo.pid
|
||||||
|
to the service
|
||||||
|
.Cm /sbin/bar ,
|
||||||
|
that PID file will, not only be created and removed automatically, but
|
||||||
|
also be used by the Finit condition subsystem. So a service/run/task
|
||||||
|
can depend on the
|
||||||
|
.Cm <pid/bar>
|
||||||
|
condition.
|
||||||
|
.Pp
|
||||||
|
As an alternative "readiness" notification, Finit supports both systemd
|
||||||
|
and s6 style notification. This can be enabled by using the `notify`
|
||||||
|
option:
|
||||||
|
.Bl -tag -width 1n
|
||||||
|
.It Cm notify:systemd
|
||||||
|
tells Finit the service uses the
|
||||||
|
.Cm sd_notify()
|
||||||
|
API to signal PID 1 when it has completed its startup and is ready
|
||||||
|
to service events. This API expects
|
||||||
|
the environment variable
|
||||||
|
.Cm NOTIFY_SOCKET
|
||||||
|
to be set to the socket where the application can send
|
||||||
|
.Cm "READY=1\n"
|
||||||
|
when it is starting up or has processed a
|
||||||
|
.Cm SIGHUP .
|
||||||
|
For details, see:
|
||||||
|
.Pp
|
||||||
|
.Lk https://www.freedesktop.org/software/systemd/man/sd_notify.html
|
||||||
|
.It Cm notify:s6
|
||||||
|
puts Finit in s6 compatibility mode. Compared to the systemd
|
||||||
|
notification, s6 expect compliant daemons to send
|
||||||
|
.Cm "\\n"
|
||||||
|
and then close their socket. For details, see:
|
||||||
|
.Pp
|
||||||
|
.Lk https://skarnet.org/software/s6/notifywhenup.html
|
||||||
|
.Pp
|
||||||
|
Finit takes care of "hard-wiring" the READY state as long as the
|
||||||
|
application is running, events across any `SIGHUP`. Since s6 can give
|
||||||
|
its applications the descriptor number (must be >3) on then command
|
||||||
|
line, Finit provides the following syntax (
|
||||||
|
.Cm %n
|
||||||
|
is replaced by Finit with then descriptor number):
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
service notify:s6 mdevd -C -O 4 -D %n
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
When a service is ready, either by Finit detecting its PID file, or
|
||||||
|
their respective readiness mechanism has been triggered, Finit creates
|
||||||
|
then service's ready condition which other services can depend on:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
$ initctl -v cond get service/mdevd/ready
|
||||||
|
on
|
||||||
|
.Ed
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
If a service should not be automatically started, it can be configured
|
||||||
|
as manual with the
|
||||||
|
.Cm manual:yes
|
||||||
|
command modifier. The service can then be started at any time by
|
||||||
|
running
|
||||||
|
.Cm initctl start NAME
|
||||||
|
.Pp
|
||||||
|
The name of a service, shown by the
|
||||||
|
.Cm initctl
|
||||||
|
tool, defaults to the basename of the service executable. It can be
|
||||||
|
changed with the
|
||||||
|
.Cm name:foo
|
||||||
|
command modifier.
|
||||||
|
.Pp
|
||||||
|
As mentioned previously, services are automatically restarted should
|
||||||
|
they crash, this is configurable with the following options:
|
||||||
|
.Bl -tag -width 1n
|
||||||
|
.It Cm restart:NUM
|
||||||
|
number of times Finit tries to restart a crashing
|
||||||
|
service, default: 10. When this limit is reached the service is
|
||||||
|
marked
|
||||||
|
.Em crashed
|
||||||
|
and must be restarted manually with
|
||||||
|
.Xr initctl 8 .
|
||||||
|
.It Cm restart_sec:SEC
|
||||||
|
number of seconds before Finit tries to restart
|
||||||
|
a crashing service, default: 2 seconds for the first five retries,
|
||||||
|
then back-off to 5 seconds. The maximum of this configured value
|
||||||
|
and the above (2 and 5) will be used
|
||||||
|
.It Cm restart:always
|
||||||
|
no upper limit on the number of times Finit tries to restart a crashing
|
||||||
|
service. Same as
|
||||||
|
.Cm restart:-1
|
||||||
|
.It Cm norestart
|
||||||
|
dont restart on failures, same as
|
||||||
|
.Cm restart:0
|
||||||
|
.It Cm respawn
|
||||||
|
bypasses the
|
||||||
|
.Cm restart
|
||||||
|
mechanism completely, allows endless restarts. Useful in many
|
||||||
|
use-cases, but not what
|
||||||
|
.Cm service
|
||||||
|
was originally designed for so not the default behavior.
|
||||||
|
.It Cm oncrash:reboot
|
||||||
|
when all retries have failed, and the service
|
||||||
|
has
|
||||||
|
.Em crashed ,
|
||||||
|
if this option is set the system is rebooted.
|
||||||
|
.It Cm oncrash:script
|
||||||
|
Similar to
|
||||||
|
.Cm oncrash:reboot ,
|
||||||
|
but instead of rebooting this action calls the
|
||||||
|
.Cm post:script
|
||||||
|
(see below) to let the operator decide the best course of action. If
|
||||||
|
the post:script option is not set, this is a no-op.
|
||||||
|
.Pp
|
||||||
|
The post:script is called with the same environment variables
|
||||||
|
.Sy except
|
||||||
|
for the
|
||||||
|
.Cm EXIT_CODE
|
||||||
|
variable which is set to
|
||||||
|
.Cm "crashed" .
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
When stopping a service (run/task/sysv/service), either manually or when
|
||||||
|
moving to another runlevel, Finit starts by sending SIGTERM, to allow
|
||||||
|
the process to shut down gracefully. If the process has not been
|
||||||
|
collected within 3 seconds, Finit sends SIGKILL. To halt the process
|
||||||
|
using a different signal, use the command modifier
|
||||||
|
.Cm halt:SIGNAL ,
|
||||||
|
e.g.,
|
||||||
|
.Cm halt:SIGPWR .
|
||||||
|
To change the delay between your halt signal and KILL, use the command
|
||||||
|
modifier
|
||||||
|
.Cm kill:SEC ,
|
||||||
|
e.g.,
|
||||||
|
.Cm kill:10
|
||||||
|
to wait 10 seconds before sending SIGKILL.
|
||||||
|
.Pp
|
||||||
|
Services support the
|
||||||
|
.Cm pre:script
|
||||||
|
and
|
||||||
|
.Cm post:script
|
||||||
|
command actions as well. These run as the same
|
||||||
|
.Cm @USER:GROUP
|
||||||
|
as the service itself, with any
|
||||||
|
.Cm env:file
|
||||||
|
sourced. The scripts must use an absolute path, but are executed from
|
||||||
|
the
|
||||||
|
.Cm $HOME
|
||||||
|
of the given user. The scripts are not called with any argument
|
||||||
|
(currently), but both get the
|
||||||
|
.Cm SERVICE_IDENT=foo
|
||||||
|
environment variable set. Here
|
||||||
|
.Cm foo
|
||||||
|
denotes the identity of the service, which if there are multiple
|
||||||
|
services named
|
||||||
|
.Cm foo ,
|
||||||
|
may be
|
||||||
|
.Cm foo:1 ,
|
||||||
|
or any unique identifier specified in the .conf file. The
|
||||||
|
.Cm post:script
|
||||||
|
is called with an additional set of environment variables:
|
||||||
|
.Bl -tag -offset indent -width 1n
|
||||||
|
.It Cm EXIT_CODE=[exited,signal,crashed]
|
||||||
|
set to one of
|
||||||
|
.Cm exited ,
|
||||||
|
.Cm signal ,
|
||||||
|
or
|
||||||
|
.Cm crashed
|
||||||
|
(see above).
|
||||||
|
.It Cm EXIT_STATUS=[num,SIGNAME]
|
||||||
|
set to one of exit status code from the program, if it exited normally,
|
||||||
|
or the signal name (HUP, TERM, etc.) if it exited due to signal
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
The scripts have a default execution time of 3 seconds before they are
|
||||||
|
SIGKILLed, this can be adjusted using the
|
||||||
|
.Cm kill:SEC
|
||||||
|
modifier syntax.
|
||||||
|
.It Cm runparts Aq DIR
|
||||||
|
Call
|
||||||
|
.Xr run-parts 8
|
||||||
|
on
|
||||||
|
.Cm DIR
|
||||||
|
to run start scripts. All executable files, or scripts, in the
|
||||||
|
directory are called, in alphabetic order. The scripts in this
|
||||||
|
directory are executed at the very end of bootstrap, runlevel S.
|
||||||
|
.Pp
|
||||||
|
It can be beneficial to use
|
||||||
|
.Cm S01name ,
|
||||||
|
.Cm S02othername ,
|
||||||
|
etc. if there is a dependency order between the scripts. Symlinks to
|
||||||
|
existing daemons can talso be used, but make sure they daemonize by
|
||||||
|
default.
|
||||||
|
.Pp
|
||||||
|
Similar to the
|
||||||
|
.Pa /etc/rc.local
|
||||||
|
shell script, make sure that all your services and programs either
|
||||||
|
terminate or start in the background or you will block Finit.
|
||||||
|
.Sy Note:
|
||||||
|
only read and executed in runlevel S (bootstrap).
|
||||||
|
.It Cm include Aq CONF
|
||||||
|
Include another configuration file. Absolute path required.
|
||||||
|
.It Cm log size:BYTES count:NUM
|
||||||
|
Log rotation for run/task/services using the
|
||||||
|
.Cm log
|
||||||
|
command modifier with redirection to a log file. Global setting,
|
||||||
|
applies to all services.
|
||||||
|
.Pp
|
||||||
|
The size can be given as bytes, without a specifier, or in `k`, `M`,
|
||||||
|
or `G`, e.g.
|
||||||
|
.Cm size:10M ,
|
||||||
|
or
|
||||||
|
.Cm size:3G .
|
||||||
|
A value of
|
||||||
|
.Cm size:0
|
||||||
|
disables log rotation. The default is
|
||||||
|
.Cm size:200k .
|
||||||
|
.Pp
|
||||||
|
The count value is recommended to be between 1-5, with a default 5.
|
||||||
|
Setting count to 0 means the logfile will be truncated when the MAX
|
||||||
|
size limit is reached.
|
||||||
|
.It Cm tty Oo LVLS Oc Ao COND Ac Ar DEV Oo BAUD Oc Oo noclear Oc Oo nowait Oc Oo nologin Oc Oo TERM Oc
|
||||||
|
This form of the
|
||||||
|
.Cm tty
|
||||||
|
stanza uses the built-in getty on the given TTY device
|
||||||
|
.Ar DEV ,
|
||||||
|
in the given runlevels.
|
||||||
|
.Ar DEV may be the special keyword
|
||||||
|
.Cm @console ,
|
||||||
|
or `console`, which is expanded from `/sys/class/tty/console/active`,
|
||||||
|
useful on embedded systems.
|
||||||
|
.Pp
|
||||||
|
The default baud rate is 0, i.e., keep kernel default.
|
||||||
|
.Pp
|
||||||
|
The `tty` stanza inherits runlevel, condition (and other feature)
|
||||||
|
parsing from the `service` stanza. So TTYs can run in one or many
|
||||||
|
runlevels and depend on any condition supported by Finit. This is
|
||||||
|
useful e.g. to depend on `<pid/elogind>` before starting a TTY.
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
tty [12345] /dev/ttyAMA0 115200 noclear vt220
|
||||||
|
.Ed
|
||||||
|
.It Cm tty Oo LVLS Oc Ao COND Ac Ar CMD DEV Oo noclear Oc Oo nowait Oc
|
||||||
|
This form of the
|
||||||
|
.Cm tty
|
||||||
|
stanza is for using an external getty, like agetty or the BusyBox getty.
|
||||||
|
.Pp
|
||||||
|
By default, these first two syntax variants
|
||||||
|
.Em clear
|
||||||
|
the TTY and
|
||||||
|
.Em wait
|
||||||
|
for the user to press enter before starting getty.
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
tty [12345] /sbin/getty -L 115200 /dev/ttyAMA0 vt100
|
||||||
|
tty [12345] /sbin/agetty -L ttyAMA0 115200 vt100 nowait
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Cm noclear
|
||||||
|
option disables clearing the TTY after each session. Clearing the TTY
|
||||||
|
when a user logs out is usually preferable.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Cm nowait
|
||||||
|
option disables the
|
||||||
|
.Cm Please press Enter to activate console
|
||||||
|
message before actually starting the getty program. On small and
|
||||||
|
embedded systems running multiple unused getty wastes both memory and
|
||||||
|
CPU cycles, so `wait` is the preferred default.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Cm nologin
|
||||||
|
option disables getty and
|
||||||
|
.Pa /bin/login ,
|
||||||
|
and gives the user a root (login) shell on the given TTY
|
||||||
|
.Cm DEV
|
||||||
|
immediately. Needless to say, this is a rather insecure option, but can
|
||||||
|
be very useful for developer builds, during board bringup, or similar.
|
||||||
|
.Pp
|
||||||
|
Notice the ordering, the
|
||||||
|
.Cm TERM
|
||||||
|
option to the built-in getty must be the last argument.
|
||||||
|
.Pp
|
||||||
|
Embedded systems may want to enable automatic `DEV` by supplying the
|
||||||
|
special
|
||||||
|
.Cm @console
|
||||||
|
device. This works regardless weather the system uses
|
||||||
|
.Cm ttyS0 , ttyAMA0 , ttyMXC0 ,
|
||||||
|
or anything else. Finit figures it out by querying sysfs:
|
||||||
|
.Pa /sys/class/tty/console/active .
|
||||||
|
The speed can be omitted to keep the kernel default.
|
||||||
|
.Pp
|
||||||
|
Most systems get by fine by just using `console`, which will evaluate
|
||||||
|
to
|
||||||
|
.Pa /dev/console .
|
||||||
|
If you have to use
|
||||||
|
.Cm @console
|
||||||
|
to get any output, you may have some issue with your kernel config.
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
tty [12345] @console noclear vt220
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
On really bare bones systems, or for board bringup, Finit can give you a
|
||||||
|
shell prompt as soon as bootstrap is done, without opening any device
|
||||||
|
node:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
tty [12345789] notty
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
This should of course not be enabled on production systems. Because it
|
||||||
|
may give a user root access without having to log in. However, for
|
||||||
|
board bringup and system debugging it can come in handy.
|
||||||
|
.Pp
|
||||||
|
One can also use the
|
||||||
|
.Cm service
|
||||||
|
stanza to start a stand-alone shell:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
service [12345] /bin/sh -l
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
.It Cm tty Oo LVLS Oc Ao COND Ac Oo notty Oc Oo rescue Oc
|
||||||
|
The third
|
||||||
|
.Cm tty
|
||||||
|
form is for board bringup and the
|
||||||
|
.Cm rescue
|
||||||
|
boot mode. No device node is required in this variant, the same output
|
||||||
|
that the kernel uses is reused for stdio. If the
|
||||||
|
.Cm rescue
|
||||||
|
option is omitted, a shell is started. The flags
|
||||||
|
.Cm nologin , noclear ,
|
||||||
|
and
|
||||||
|
.Cm nowait
|
||||||
|
are implied. If the
|
||||||
|
.Cm rescue
|
||||||
|
option is set the bundled
|
||||||
|
.Pa /libexec/finit/sulogin
|
||||||
|
is started to present a bare-bones root login prompt. If the root
|
||||||
|
(uid:0, gid:0) user does not have a password set, no rescue is possible.
|
||||||
|
.El
|
||||||
|
.Sh COMMAND MODIFIERS
|
||||||
|
The run/task/tty/service/sysv stanzas take modifiers, or options, to
|
||||||
|
control their behavior. This section lists them with their limitations.
|
||||||
|
All modifiers must be placed between the stanza and its command.
|
||||||
|
.Bl -tag -width 1n
|
||||||
|
.It Cm @user:group
|
||||||
|
Every
|
||||||
|
.Cm run , task ,
|
||||||
|
or
|
||||||
|
.Cm service
|
||||||
|
can also list the privileges the
|
||||||
|
.Cm /path/to/cmd
|
||||||
|
should be executed with. Prefix the command with
|
||||||
|
.Cm @USR[:GRP] ,
|
||||||
|
group is optional, like this:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
run [2345] @joe:users logger "Hello world"
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
For multiple instances of the same command, e.g. a DHCP client or
|
||||||
|
multiple web servers, add
|
||||||
|
.Cm :ID
|
||||||
|
somewhere between the
|
||||||
|
.Cm run , task , service
|
||||||
|
keyword and the command, like this:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
service :80 [2345] httpd -f -h /http -p 80 -- Web server
|
||||||
|
service :8080[2345] httpd -f -h /http -p 8080 -- Old web server
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Without the
|
||||||
|
.Cm :ID
|
||||||
|
to the service the latter will overwrite the former and only the old web
|
||||||
|
server would be started and supervised.
|
||||||
|
.It Cm log:/path/to/file
|
||||||
|
Redirect stdout/stderr of a command to the given log file. See the
|
||||||
|
global log directive, above, for details on log rotation.
|
||||||
|
.It Cm log:console
|
||||||
|
Redirect stdout/stderr of a command to
|
||||||
|
.Pa /dev/console ,
|
||||||
|
only use this for debugging or bringup.
|
||||||
|
.It Cm log:null
|
||||||
|
Redirect stdout/stderr of a command to
|
||||||
|
.Pa /dev/null .
|
||||||
|
.It Cm log:prio:facility.level,tag:ident
|
||||||
|
Redirect stdout/stderr of a command to syslog using the given priority
|
||||||
|
and tag identity.
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
|
||||||
|
.Ed
|
||||||
|
.It Cm log
|
||||||
|
Default
|
||||||
|
.Cm prio
|
||||||
|
is
|
||||||
|
.Cm daemon.info
|
||||||
|
and the default
|
||||||
|
.Cm tag
|
||||||
|
identity is the basename of the service or run/task command.
|
||||||
|
.El
|
||||||
|
.Sh RESCUE MODE
|
||||||
|
Finit supports a rescue mode which is activated by the
|
||||||
|
.Cm rescue
|
||||||
|
option on the kernel command line. The rescue mode comes in two
|
||||||
|
flavors:
|
||||||
|
.Em traditional
|
||||||
|
and
|
||||||
|
.Em fallback .
|
||||||
|
.Ss Traditional
|
||||||
|
This is what most users expect. A very early maintenance login prompt,
|
||||||
|
served by the bundled
|
||||||
|
.Pa /libexec/finit/sulogin
|
||||||
|
program, or the standard
|
||||||
|
.Cm sulogin
|
||||||
|
from util-linux or BusyBox is searched for in the UNIX default
|
||||||
|
.Cm $PATH .
|
||||||
|
If a successful login is made, or the user exits (Ctrl-D), the rescue
|
||||||
|
mode is ended and the system boots up normally.
|
||||||
|
.Pp
|
||||||
|
.Sy Note:
|
||||||
|
if the user (UID 0 and GID 0) does not have a password, or
|
||||||
|
.Em the account is locked ,
|
||||||
|
the user is presented with a password-less prompt:
|
||||||
|
.Cm "Press enter to enter maintenance mode." ,
|
||||||
|
which opens up a root shell.
|
||||||
|
.Ss Fallback
|
||||||
|
If no
|
||||||
|
.Cm sulogin
|
||||||
|
program is found, Finit tries to bring up as much of its own
|
||||||
|
functionality as possible, yet limiting many aspects, meaning; no
|
||||||
|
network, no`fsck` of file systems in
|
||||||
|
.Pa /etc/fstab ,
|
||||||
|
no
|
||||||
|
.Pa /etc/rc.local ,
|
||||||
|
no
|
||||||
|
.Cm runparts ,
|
||||||
|
and most plugins are skipped (except those that provide functionality
|
||||||
|
for the condition subsystem).
|
||||||
|
.Pp
|
||||||
|
Instead of reading
|
||||||
|
.Pa /etc/finit.conf
|
||||||
|
et al, system configuration is read from
|
||||||
|
.Pa /lib/finit/rescue.conf ,
|
||||||
|
which can be freely modified by the system administrator.
|
||||||
|
.Pp
|
||||||
|
The bundled default `rescue.conf` contains nothing more than:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
runlevel 1
|
||||||
|
tty [12345] rescue
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Cm tty
|
||||||
|
has the
|
||||||
|
.Cm rescue
|
||||||
|
option set, which works similar to the board bring-up tty option
|
||||||
|
.Cm notty .
|
||||||
|
The major difference being that `sulogin` is started to query for
|
||||||
|
root/admin password. If
|
||||||
|
.Cm sulogin
|
||||||
|
is not found,
|
||||||
|
.Cm rescue
|
||||||
|
behaves like
|
||||||
|
.Cm notty
|
||||||
|
and gives a plain root shell prompt.
|
||||||
|
.Pp
|
||||||
|
If Finit cannot find
|
||||||
|
.Pa /lib/finit/rescue.conf
|
||||||
|
it defaults to:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
tty [12345] rescue
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
There is no way to exit the
|
||||||
|
.Em fallback
|
||||||
|
rescue mode.
|
||||||
|
.Sh SERVICE ENVIRONMENT
|
||||||
|
Finit supports sourcing environment variables from
|
||||||
|
.Pa /etc/default/* ,
|
||||||
|
or similar. This is a common pattern from SysV init scripts, where the
|
||||||
|
start/stop script is a generic script for the given service,
|
||||||
|
.Cm foo ,
|
||||||
|
and the options for the service are sourced from the file
|
||||||
|
.Pa /etc/default/foo .
|
||||||
|
Like this:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
/etc/default/foo:
|
||||||
|
|
||||||
|
FOO_OPTIONS=--extra-arg="bar" -s -x
|
||||||
|
|
||||||
|
/etc/finit.conf:
|
||||||
|
|
||||||
|
service [2345] env:-/etc/default/foo foo -n $FOO_OPTIONS -- Example foo daemon
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Here the service
|
||||||
|
.Cm foo
|
||||||
|
is started with
|
||||||
|
.Op Fl -n ,
|
||||||
|
to make sure it runs in the foreground, and the with the options found
|
||||||
|
in the environment file. With the
|
||||||
|
.Cm ps
|
||||||
|
command we can see that the process is started with:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
foo -n --extra-arg=bar -s -x
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
.Sy Note:
|
||||||
|
the leading `-` determines if Finit should treat a missing environment
|
||||||
|
file as blocking the start of the service or not. When `-` is used, a
|
||||||
|
missing environment file does
|
||||||
|
.Em not
|
||||||
|
block the start.
|
||||||
|
.Sh SERVICE WRAPPER SCRIPTS
|
||||||
|
If your service requires to run additional commands, executed before the
|
||||||
|
service is actually started, like the systemd `ExecStartPre`, you can
|
||||||
|
use a wrapper shell script to start your service.
|
||||||
|
.Pp
|
||||||
|
The Finit service
|
||||||
|
.Cm .conf
|
||||||
|
file can be put into
|
||||||
|
.Pa /etc/finit.d/available ,
|
||||||
|
so you can control the service using
|
||||||
|
.Cm initctl .
|
||||||
|
Then use the path to the wrapper script in the Finit
|
||||||
|
.Cm .conf
|
||||||
|
service stanza. The following example employs a wrapper script in
|
||||||
|
.Pa /etc/start.d .
|
||||||
|
.Bd -unfilled
|
||||||
|
/etc/finit.d/available/program.conf:
|
||||||
|
|
||||||
|
service [235] <!> /etc/start.d/program -- Example Program
|
||||||
|
|
||||||
|
/etc/start.d/program:
|
||||||
|
|
||||||
|
#!/bin/sh
|
||||||
|
# Prepare the command line options
|
||||||
|
OPTIONS="-u $(cat /etc/username)"
|
||||||
|
|
||||||
|
# Execute the program
|
||||||
|
exec /usr/bin/program $OPTIONS
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
.Sy Note:
|
||||||
|
the example sets
|
||||||
|
.Cm <!>
|
||||||
|
to denote that it doesn't support SIGHUP. That way Finit will
|
||||||
|
stop/start the service instead of sending SIGHUP at restart/reload
|
||||||
|
events.
|
||||||
|
.Sh TEMPLATING
|
||||||
|
Finit comes with rudimentary support for templating, similar to that of
|
||||||
|
systemd. Best illustrated with an example:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
$ initctl show avahi-autoipd@
|
||||||
|
service :%i avahi-autoipd --syslog %i -- ZeroConf for %i
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
To enable ZeroConf for, e.g.,
|
||||||
|
.Cm eth0 ,
|
||||||
|
use
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
$ initctl enable avahi-autoipd@eth0.conf
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
The enabled symlink will be set up to
|
||||||
|
.Cm avahi-autoipd@.conf
|
||||||
|
and every instance of
|
||||||
|
.Cm %i
|
||||||
|
will in the instantiated directive be replaced with
|
||||||
|
.Cm eth0 .
|
||||||
|
Inspect the result with:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
$ initctl status avahi-autoipd:eth0
|
||||||
|
.Ed
|
||||||
|
.Sh CGROUPS
|
||||||
|
There are three major cgroup configuration directives:
|
||||||
|
.Pp
|
||||||
|
.Bl -enum -offset indent -compact
|
||||||
|
.It
|
||||||
|
Global top-level group: init, system, user, or a custom group
|
||||||
|
.It
|
||||||
|
Selecting a top-level group for a set of run/task/services
|
||||||
|
.It
|
||||||
|
Per run/task/service limits
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
Top-level group configuration.
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
# Top-level cgroups and their default settings. All groups mandatory
|
||||||
|
# but more can be added, max 8 groups in total currently. The cgroup
|
||||||
|
# 'root' is also available, reserved for RT processes. Settings are
|
||||||
|
# as-is, only one shorthand 'mem.' exists, other than that it's the
|
||||||
|
# cgroup v2 controller default names.
|
||||||
|
cgroup init cpu.weight:100
|
||||||
|
cgroup user cpu.weight:100
|
||||||
|
cgroup system cpu.weight:9800
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Adding an extra cgroup
|
||||||
|
.Cm maint/
|
||||||
|
will require you to adjust the weight of the above three. We leave
|
||||||
|
.Cm init/
|
||||||
|
and
|
||||||
|
.Cm user/
|
||||||
|
as-is reducing weight of
|
||||||
|
.Cm system/
|
||||||
|
to 9700.
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
cgroup system cpu.weight:9700
|
||||||
|
|
||||||
|
# Example extra cgroup 'maint'
|
||||||
|
cgroup maint cpu.weight:100
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
By default, the
|
||||||
|
.Cm system/
|
||||||
|
cgroup is selected for almost everything. The
|
||||||
|
.Cm init/
|
||||||
|
cgroup is reserved for PID 1 itself and its closest relatives. The
|
||||||
|
.Cm user/
|
||||||
|
cgroup is for local TTY logins spawned by getty.
|
||||||
|
.Pp
|
||||||
|
To select a different top-level cgroup, e.g.
|
||||||
|
.Cm maint/ ,
|
||||||
|
one can either define it for a group of run/task/service directives in a
|
||||||
|
.Cm .conf
|
||||||
|
or per each stanza:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
cgroup.maint
|
||||||
|
service [...] <...> /path/to/foo args -- description
|
||||||
|
service [...] <...> /path/to/bar args -- description
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
or
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
service [...] <...> cgroup.maint /path/to/foo args -- description
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
The latter form also allows per-stanza limits on the form:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
service [...] <...> cgroup.maint:cpu.max:10000,mem.max:655360 /path/to/foo args -- description
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Notice the comma separation and the
|
||||||
|
.Cm mem.
|
||||||
|
exception to the rule: every cgroup setting maps directly to cgroup v2
|
||||||
|
syntax. I.e.,
|
||||||
|
.Cm cpu.max
|
||||||
|
maps to the file
|
||||||
|
.Pm /sys/fs/cgroup/maint/foo/cpu.max .
|
||||||
|
There is no filtering, except for expanding the shorthand
|
||||||
|
.Cm mem.
|
||||||
|
to
|
||||||
|
.Cm memory. ,
|
||||||
|
if the file is not available, either the cgroup controller is not
|
||||||
|
available in your Linux kernel, or the name is misspelled.
|
||||||
|
.Pp
|
||||||
|
Linux cgroups and details surrounding values are not explained in the
|
||||||
|
Finit documentation. The Linux admin-guide cover this well:
|
||||||
|
.Lk https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html
|
||||||
|
.Sh LIMITATIONS
|
||||||
|
As of Finit v4 there are no limitations to where
|
||||||
|
.Cm .conf
|
||||||
|
settings can be placed. Except for the system/global
|
||||||
|
.Cm rlimit
|
||||||
|
and
|
||||||
|
.Cm cgroup
|
||||||
|
top-level group declarations, which can only be set from
|
||||||
|
.Pa /etc/finit.conf ,
|
||||||
|
since it is the first
|
||||||
|
.Cm .conf
|
||||||
|
file Finit reads.
|
||||||
|
.Pp
|
||||||
|
Originally,
|
||||||
|
.Pp /etc/finit.conf
|
||||||
|
was the only way to set up a Finit system. Today it is mainly used for
|
||||||
|
bootstrap settings like system hostname, early module loading for
|
||||||
|
watchdogd, network bringup and system shutdown. These can now also be
|
||||||
|
set in any
|
||||||
|
.Cm .conf
|
||||||
|
file in
|
||||||
|
.Pa /etc/finit.d .
|
||||||
|
.Pp
|
||||||
|
There is, however, nothing preventing you from having all configuration
|
||||||
|
settings in
|
||||||
|
.Pa /etc/finit.conf .
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr finit 8 ,
|
||||||
|
.Xr initctl 8
|
||||||
|
.Sh AUTHORS
|
||||||
|
.Nm finit
|
||||||
|
was conceived and reverse engineered by Claudio Matsuoka. Since v1.0,
|
||||||
|
maintained by Joachim Wiberg, with contributions by many others.
|
||||||
+272
@@ -0,0 +1,272 @@
|
|||||||
|
.\" Hey, EMACS: -*- nroff -*-
|
||||||
|
.\" First parameter, NAME, should be all caps
|
||||||
|
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||||
|
.\" other parameters are allowed: see man(7), man(1)
|
||||||
|
.Dd June 6, 2021
|
||||||
|
.\" Please adjust this date whenever revising the manpage.
|
||||||
|
.Dt INITCTL 8 SMM
|
||||||
|
.Os Linux
|
||||||
|
.Sh NAME
|
||||||
|
.Nm initctl
|
||||||
|
.Nd Control tool for Finit
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm /sbin/initctl
|
||||||
|
.Op Fl bcfhjlpqtvV
|
||||||
|
.Op COMMAND
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
is the official tool for interacting with
|
||||||
|
.Xr finit 8 .
|
||||||
|
It comes with functions for showing status, querying health of services,
|
||||||
|
as well as editing, enabling and disabling services.
|
||||||
|
.Sh OPTIONS
|
||||||
|
This program follows the usual UNIX command line syntax, with long
|
||||||
|
options starting with two dashes (`-'). The options are as follows:
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl b, -batch
|
||||||
|
Batch mode, no screen size probing. Useful for scripting.
|
||||||
|
.It Fl c, -create
|
||||||
|
Create missing paths (and files) as needed. Useful with the
|
||||||
|
.Cm edit
|
||||||
|
command.
|
||||||
|
.It Fl f, -force
|
||||||
|
Ignore missing files and arguments, never prompt.
|
||||||
|
.It Fl h, -help
|
||||||
|
Show built-in help text.
|
||||||
|
.It Fl j, -json
|
||||||
|
JSON output in
|
||||||
|
.Ar status
|
||||||
|
and
|
||||||
|
.Ar cond
|
||||||
|
commands.
|
||||||
|
.It Fl n, -noerr
|
||||||
|
When scripting
|
||||||
|
.Nm
|
||||||
|
to stop, start, restart, or signal a task or service, this option can be
|
||||||
|
used to ignore error 69 (no such task or service) and instead return 0
|
||||||
|
(OK).
|
||||||
|
.It Fl 1, -once
|
||||||
|
Only one lap in commands like top.
|
||||||
|
.It Fl p, -plain
|
||||||
|
Use plain table headings, no ANSI control characters.
|
||||||
|
.It Fl q, -quiet
|
||||||
|
Silent, only return status of command.
|
||||||
|
.It Fl t, -no-heading
|
||||||
|
Skip table headings.
|
||||||
|
.It Fl v, -verbose
|
||||||
|
Verbose output, where applicable.
|
||||||
|
.It Fl V, -version
|
||||||
|
Show program version.
|
||||||
|
.El
|
||||||
|
.Sh COMMANDS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Nm Ar debug
|
||||||
|
Toggle
|
||||||
|
.Nm finit
|
||||||
|
(daemon) debug to
|
||||||
|
.Pa /dev/console
|
||||||
|
.It Nm Ar help
|
||||||
|
Show built-in help text.
|
||||||
|
.It Nm Ar version
|
||||||
|
Show program version.
|
||||||
|
.It Nm Ar ls | list
|
||||||
|
List all
|
||||||
|
.Cm *.conf
|
||||||
|
files in
|
||||||
|
.Pa /etc/finit.d
|
||||||
|
.It Nm Ar create Ar CONF
|
||||||
|
Create
|
||||||
|
.Cm .conf
|
||||||
|
in
|
||||||
|
.Pa /etc/finit.d/available .
|
||||||
|
.Pp
|
||||||
|
Piping the contents into
|
||||||
|
.Nm
|
||||||
|
works as one would expect:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
echo "task name:foo /tmp/foo.sh -- Foo logger" | initctl create foo
|
||||||
|
initctl enable foo
|
||||||
|
initctl reload
|
||||||
|
.Ed
|
||||||
|
.It Nm Ar delete Ar CONF
|
||||||
|
Delete
|
||||||
|
.Cm .conf
|
||||||
|
in
|
||||||
|
.Pa /etc/finit.d/available
|
||||||
|
.It Nm Ar show Ar CONF
|
||||||
|
Show
|
||||||
|
.Cm .conf
|
||||||
|
in
|
||||||
|
.Pa /etc/finit.d/available
|
||||||
|
.It Nm Ar edit Ar CONF
|
||||||
|
Edit
|
||||||
|
.Cm .conf
|
||||||
|
in
|
||||||
|
.Pa /etc/finit.d/available
|
||||||
|
.It Nm Ar touch Ar CONF
|
||||||
|
Change (mark as modified)
|
||||||
|
.Cm .conf
|
||||||
|
in
|
||||||
|
.Pa /etc/finit.d/available ,
|
||||||
|
like
|
||||||
|
.Ar edit
|
||||||
|
this tells
|
||||||
|
.Nm finit
|
||||||
|
that a configuration has been changed and is a candidate to be restarted
|
||||||
|
(or SIGHUP'ed) on
|
||||||
|
.Cm initctl reload
|
||||||
|
.It Nm Ar enable Ar CONF
|
||||||
|
Enable
|
||||||
|
.Cm .conf
|
||||||
|
in
|
||||||
|
.Pa /etc/finit.d/available ,
|
||||||
|
i.e., add symlink in
|
||||||
|
.Pa /etc/finit.d/enabled
|
||||||
|
.It Nm Ar disable Ar CONF
|
||||||
|
Disable
|
||||||
|
.Cm .conf
|
||||||
|
in
|
||||||
|
.Pa /etc/finit.d/enabled ,
|
||||||
|
i.e., removes symlink.
|
||||||
|
.It Nm Ar reload
|
||||||
|
Reload
|
||||||
|
.Cm *.conf in
|
||||||
|
.Pa /etc/finit.d ,
|
||||||
|
i.e., activates changes.
|
||||||
|
.It Nm Ar cond set Ar COND Op COND ...
|
||||||
|
Set (assert) user-defined condition,
|
||||||
|
.Cm +usr/COND
|
||||||
|
.It Nm Ar cond get Ar COND
|
||||||
|
Get (quietly) the status of any condition. Defaults to user-defined
|
||||||
|
condions, but if a slash is detected, e.g.,
|
||||||
|
.Cm pid/foo
|
||||||
|
or
|
||||||
|
.Cm net/eth0/exist ,
|
||||||
|
then any condition can be read.
|
||||||
|
.Pp
|
||||||
|
The command is geared for scripting, check the exit code to get the
|
||||||
|
status of the condition: 0 - on, 1 - off, 255 - flux. For a more
|
||||||
|
verbose output, use the
|
||||||
|
.Fl v
|
||||||
|
option.
|
||||||
|
.It Nm Ar cond clr | clear Ar COND Op COND ...
|
||||||
|
Clear (deassert) user-defined condition,
|
||||||
|
.Cm -usr/COND
|
||||||
|
.It Nm Ar cond status
|
||||||
|
Show condition status, default
|
||||||
|
.Cm cond
|
||||||
|
command. Also supports the
|
||||||
|
.Fl j
|
||||||
|
option for detailed JSON output.
|
||||||
|
.It Nm Ar cond dump Op Cm TYPE
|
||||||
|
Dump all, or a given type of, conditions and their status. Also
|
||||||
|
supports the
|
||||||
|
.Fl j
|
||||||
|
option for detailed JSON output.
|
||||||
|
.It Nm Ar ident Op Cm NAME
|
||||||
|
Display indentities of all run/task/services, or only instances
|
||||||
|
matching
|
||||||
|
.Cm NAME .
|
||||||
|
A partial string, e.g.,
|
||||||
|
.Cm NAM ,
|
||||||
|
will not match anything.
|
||||||
|
.It Nm Ar log Op Cm NAME
|
||||||
|
Show ten last Finit, or
|
||||||
|
.Cm NAME ,
|
||||||
|
messages from syslog.
|
||||||
|
.It Nm Ar start Cm NAME[:ID]
|
||||||
|
Start service by name, with optional ID, e.g.,
|
||||||
|
.Cm initctl start tty:1
|
||||||
|
.It Nm Ar stop Cm NAME[:ID]
|
||||||
|
Stop/Pause a running service by name.
|
||||||
|
.It Nm Ar reload Cm NAME[:ID]
|
||||||
|
Reload service as if its configuration had changed. Internally,
|
||||||
|
.Nm finit
|
||||||
|
marks the named service as "dirty" and turns the state machine,
|
||||||
|
resulting in a SIGHUP or restart of (at least) the named service.
|
||||||
|
Any dependant services are also restarted.
|
||||||
|
.Pp
|
||||||
|
.Sy Note:
|
||||||
|
no .conf file is reloaded with this variant of the command. Essentially
|
||||||
|
it is the same as calling
|
||||||
|
.Cm restart .
|
||||||
|
Except for two things:
|
||||||
|
.Bl -enum -offset indent -compact
|
||||||
|
.It
|
||||||
|
if the service supports HUP, it's signaled instead of stop-started, and
|
||||||
|
.It
|
||||||
|
it allows restarting run/task in the same runlevel -- which is otherwise
|
||||||
|
restricted.
|
||||||
|
.El
|
||||||
|
.It Nm Ar signal Cm NAME:[ID] S
|
||||||
|
Send signal S to service, by name.
|
||||||
|
.Cm S
|
||||||
|
may be a complete signal name such as SIGHUP, or short name such as HUP, or the signal number such as 1 (SIGHUP).
|
||||||
|
.It Nm Ar restart Cm NAME[:ID]
|
||||||
|
Restart (stop/start) service by name.
|
||||||
|
.It Nm Ar status Cm NAME[:ID]
|
||||||
|
Show service status, by name. If only
|
||||||
|
.Cm NAME
|
||||||
|
is given and multiple instances exits, a summary of all matching
|
||||||
|
instances are shown. Only an exact match displays detailed status
|
||||||
|
for a given instance.
|
||||||
|
.Pp
|
||||||
|
With the
|
||||||
|
.Fl q
|
||||||
|
option this command is silent, provided the
|
||||||
|
.Ar NAME[:ID]
|
||||||
|
selection matches a single run/task/service. The exit code of
|
||||||
|
.Nm
|
||||||
|
is non-zero if there is a problem. Zero is returned if a run/task has
|
||||||
|
run (at least) once in the current runlevel, and when a service is running
|
||||||
|
(as expected). See the
|
||||||
|
.Fl j
|
||||||
|
option for detailed JSON output suitable for machine parsing.
|
||||||
|
.Pp
|
||||||
|
.Sy Tip:
|
||||||
|
.Xr jq 1
|
||||||
|
is a useful scripting tool in combination with JSON output.
|
||||||
|
.It Nm Ar status
|
||||||
|
Show status of all services, default command. Also supports the
|
||||||
|
.Fl j
|
||||||
|
option for detailed JSON output.
|
||||||
|
.It Nm Ar cgroup
|
||||||
|
List cgroup config overview.
|
||||||
|
.It Nm Ar ps
|
||||||
|
List processes based on cgroups.
|
||||||
|
.It Nm Ar top
|
||||||
|
Show top-like listing based on cgroups.
|
||||||
|
.It Nm Ar plugins
|
||||||
|
List installed plugins.
|
||||||
|
.It Nm Ar runlevel Op Ar 0-9
|
||||||
|
Show or set runlevel: 0 halt, 6 reboot.
|
||||||
|
.It Nm Ar reboot
|
||||||
|
Reboot system, default if
|
||||||
|
.Cm reboot
|
||||||
|
is symlinked to
|
||||||
|
.Nm .
|
||||||
|
.It Nm Ar halt
|
||||||
|
Halt system, default if
|
||||||
|
.Cm halt
|
||||||
|
is symlinked to
|
||||||
|
.Nm .
|
||||||
|
.It Nm Ar poweroff
|
||||||
|
Power-off system, default if
|
||||||
|
.Cm poweroff
|
||||||
|
is symlinked to
|
||||||
|
.Nm .
|
||||||
|
.It Nm Ar suspend
|
||||||
|
Suspend system, default if
|
||||||
|
.Cm suspend
|
||||||
|
is symlinked to
|
||||||
|
.Nm .
|
||||||
|
.It Nm Ar utmp show
|
||||||
|
Raw dump of UTMP/WTMP db.
|
||||||
|
.El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr finit.conf 5
|
||||||
|
.Xr finit 8
|
||||||
|
.Sh AUTHORS
|
||||||
|
.Nm finit
|
||||||
|
was conceived and reverse engineered by Claudio Matsuoka. Since v1.0,
|
||||||
|
maintained by Joachim Wiberg, with contributions by many others.
|
||||||
+42
-10
@@ -1,13 +1,13 @@
|
|||||||
pkglibdir = $(plugin_path)
|
pkglibdir = $(plugin_path)
|
||||||
AM_LDFLAGS = -module -avoid-version -shared
|
AM_LDFLAGS = -module -avoid-version -shared
|
||||||
AM_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
AM_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||||
AM_CPPFLAGS = -I$(top_srcdir)/src -U_FORTIFY_SOURCE
|
AM_CPPFLAGS = -I$(top_srcdir)/src
|
||||||
AM_CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
|
AM_CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
|
||||||
AM_CPPFLAGS += $(lite_CFLAGS)
|
AM_CPPFLAGS += -D__FINIT__ $(lite_CFLAGS) $(uev_CFLAGS)
|
||||||
|
|
||||||
if STATIC
|
if STATIC
|
||||||
noinst_LTLIBRARIES = libplug.la
|
noinst_LTLIBRARIES = libplug.la
|
||||||
libplug_la_SOURCES = bootmisc.c modprobe.c rtc.c pidfile.c procps.c tty.c urandom.c usr.c
|
libplug_la_SOURCES = bootmisc.c pidfile.c procps.c sys.c usr.c
|
||||||
|
|
||||||
if BUILD_ALSA_UTILS_PLUGIN
|
if BUILD_ALSA_UTILS_PLUGIN
|
||||||
libplug_la_SOURCES += alsa-utils.c
|
libplug_la_SOURCES += alsa-utils.c
|
||||||
@@ -17,14 +17,14 @@ if BUILD_DBUS_PLUGIN
|
|||||||
libplug_la_SOURCES += dbus.c
|
libplug_la_SOURCES += dbus.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if BUILD_HOTPLUG_PLUGIN
|
|
||||||
libplug_la_SOURCES += hotplug.c
|
|
||||||
endif
|
|
||||||
|
|
||||||
if BUILD_MODULES_LOAD_PLUGIN
|
if BUILD_MODULES_LOAD_PLUGIN
|
||||||
libplug_la_SOURCES += modules-load.c
|
libplug_la_SOURCES += modules-load.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if BUILD_MODPROBE_PLUGIN
|
||||||
|
libplug_la_SOURCES += modprobe.c
|
||||||
|
endif
|
||||||
|
|
||||||
if BUILD_NETLINK_PLUGIN
|
if BUILD_NETLINK_PLUGIN
|
||||||
libplug_la_SOURCES += netlink.c
|
libplug_la_SOURCES += netlink.c
|
||||||
endif
|
endif
|
||||||
@@ -33,8 +33,24 @@ if BUILD_RESOLVCONF_PLUGIN
|
|||||||
libplug_la_SOURCES += resolvconf.c
|
libplug_la_SOURCES += resolvconf.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if BUILD_RTC_PLUGIN
|
||||||
|
libplug_la_SOURCES += rtc.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
if BUILD_TTY_PLUGIN
|
||||||
|
libplug_la_SOURCES += tty.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
if BUILD_URANDOM_PLUGIN
|
||||||
|
libplug_la_SOURCES += urandom.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
if BUILD_X11_COMMON_PLUGIN
|
||||||
|
libplug_la_SOURCES += x11-common.c
|
||||||
|
endif
|
||||||
|
|
||||||
else
|
else
|
||||||
pkglib_LTLIBRARIES = bootmisc.la modprobe.la rtc.la pidfile.la procps.la tty.la urandom.la usr.la
|
pkglib_LTLIBRARIES = bootmisc.la pidfile.la procps.la sys.la usr.la
|
||||||
|
|
||||||
if BUILD_ALSA_UTILS_PLUGIN
|
if BUILD_ALSA_UTILS_PLUGIN
|
||||||
pkglib_LTLIBRARIES += alsa-utils.la
|
pkglib_LTLIBRARIES += alsa-utils.la
|
||||||
@@ -44,14 +60,18 @@ if BUILD_DBUS_PLUGIN
|
|||||||
pkglib_LTLIBRARIES += dbus.la
|
pkglib_LTLIBRARIES += dbus.la
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if BUILD_HOTPLUG_PLUGIN
|
if BUILD_HOOK_SCRIPTS_PLUGIN
|
||||||
pkglib_LTLIBRARIES += hotplug.la
|
pkglib_LTLIBRARIES += hook-scripts.la
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if BUILD_MODULES_LOAD_PLUGIN
|
if BUILD_MODULES_LOAD_PLUGIN
|
||||||
pkglib_LTLIBRARIES += modules-load.la
|
pkglib_LTLIBRARIES += modules-load.la
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if BUILD_MODPROBE_PLUGIN
|
||||||
|
pkglib_LTLIBRARIES += modprobe.la
|
||||||
|
endif
|
||||||
|
|
||||||
if BUILD_NETLINK_PLUGIN
|
if BUILD_NETLINK_PLUGIN
|
||||||
pkglib_LTLIBRARIES += netlink.la
|
pkglib_LTLIBRARIES += netlink.la
|
||||||
endif
|
endif
|
||||||
@@ -60,6 +80,18 @@ if BUILD_RESOLVCONF_PLUGIN
|
|||||||
pkglib_LTLIBRARIES += resolvconf.la
|
pkglib_LTLIBRARIES += resolvconf.la
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if BUILD_RTC_PLUGIN
|
||||||
|
pkglib_LTLIBRARIES += rtc.la
|
||||||
|
endif
|
||||||
|
|
||||||
|
if BUILD_TTY_PLUGIN
|
||||||
|
pkglib_LTLIBRARIES += tty.la
|
||||||
|
endif
|
||||||
|
|
||||||
|
if BUILD_URANDOM_PLUGIN
|
||||||
|
pkglib_LTLIBRARIES += urandom.la
|
||||||
|
endif
|
||||||
|
|
||||||
if BUILD_X11_COMMON_PLUGIN
|
if BUILD_X11_COMMON_PLUGIN
|
||||||
pkglib_LTLIBRARIES += x11-common.la
|
pkglib_LTLIBRARIES += x11-common.la
|
||||||
endif
|
endif
|
||||||
|
|||||||
+19
-4
@@ -1,6 +1,6 @@
|
|||||||
/* Save and restore ALSA sound settings using alsactl
|
/* Save and restore ALSA sound settings using alsactl
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -21,7 +21,12 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
@@ -30,16 +35,26 @@
|
|||||||
|
|
||||||
static void save(void *arg)
|
static void save(void *arg)
|
||||||
{
|
{
|
||||||
|
if (rescue) {
|
||||||
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (whichp(ALSACTL)) {
|
if (whichp(ALSACTL)) {
|
||||||
_d("Saving sound settings ...");
|
dbg("Saving sound settings ...");
|
||||||
run_interactive(ALSACTL " -g store", "Saving sound settings");
|
run_interactive(ALSACTL " -g store", "Saving sound settings");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void restore(void *arg)
|
static void restore(void *arg)
|
||||||
{
|
{
|
||||||
|
if (rescue) {
|
||||||
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (whichp(ALSACTL)) {
|
if (whichp(ALSACTL)) {
|
||||||
_d("Restoring sound settings ...");
|
dbg("Restoring sound settings ...");
|
||||||
run_interactive(ALSACTL " -g restore", "Restoring sound settings");
|
run_interactive(ALSACTL " -g restore", "Restoring sound settings");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+71
-84
@@ -1,6 +1,6 @@
|
|||||||
/* Setup necessary system files for, e.g. UTMP (tracking logins)
|
/* Setup necessary system files for, e.g. UTMP (tracking logins)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -21,24 +21,35 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h" /* Generated by configure script */
|
||||||
|
|
||||||
#include <ftw.h>
|
#include <ftw.h>
|
||||||
|
#ifdef HAVE_MNTENT_H
|
||||||
#include <mntent.h>
|
#include <mntent.h>
|
||||||
|
#endif
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
#include "tmpfiles.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "utmp-api.h"
|
#include "utmp-api.h"
|
||||||
|
|
||||||
static int is_tmpfs(char *path)
|
static int is_tmpfs(char *path)
|
||||||
{
|
{
|
||||||
|
struct mntent mount;
|
||||||
|
struct mntent *mnt;
|
||||||
|
char buf[256];
|
||||||
int tmpfs = 0;
|
int tmpfs = 0;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
char *dir;
|
char *dir;
|
||||||
struct mntent *mnt;
|
|
||||||
|
|
||||||
/* If path is a symlink, check what it resolves to */
|
/* If path is a symlink, check what it resolves to */
|
||||||
dir = realpath(path, NULL);
|
dir = realpath(path, NULL);
|
||||||
@@ -51,7 +62,7 @@ static int is_tmpfs(char *path)
|
|||||||
return 0; /* Dunno, maybe not */
|
return 0; /* Dunno, maybe not */
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((mnt = getmntent(fp))) {
|
while ((mnt = getmntent_r(fp, &mount, buf, sizeof(buf)))) {
|
||||||
if (!strcmp(dir, mnt->mnt_dir))
|
if (!strcmp(dir, mnt->mnt_dir))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -65,19 +76,25 @@ static int is_tmpfs(char *path)
|
|||||||
return tmpfs;
|
return tmpfs;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_clean(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftw)
|
static int bootclean(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftw)
|
||||||
{
|
{
|
||||||
if (ftw->level == 0)
|
if (ftw->level == 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
_d("Removing %s ...", fpath);
|
dbg("Removing %s ...", fpath);
|
||||||
(void)remove(fpath);
|
(void)remove(fpath);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We can safely skip tmpfs, nothing to clean from previous boot there */
|
/*
|
||||||
static void bootclean(void)
|
* Cleanup stale files from previous boot, if any still linger on.
|
||||||
|
* Some systems, e.g. Alpine Linux, still have a persistent /run and
|
||||||
|
* /tmp, i.e. not tmpfs.
|
||||||
|
*
|
||||||
|
* We can safely skip tmpfs, nothing to clean there.
|
||||||
|
*/
|
||||||
|
static void clean(void *arg)
|
||||||
{
|
{
|
||||||
char *dir[] = {
|
char *dir[] = {
|
||||||
"/tmp/",
|
"/tmp/",
|
||||||
@@ -90,7 +107,46 @@ static void bootclean(void)
|
|||||||
if (is_tmpfs(dir[i]))
|
if (is_tmpfs(dir[i]))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
nftw(dir[i], do_clean, 20, FTW_DEPTH);
|
nftw(dir[i], bootclean, 20, FTW_DEPTH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Kernel defines the following compulsory and recommended links
|
||||||
|
* https://github.com/torvalds/linux/blob/v5.18/Documentation/admin-guide/devices.rst#compulsory-links
|
||||||
|
*/
|
||||||
|
static void kernel_links(void)
|
||||||
|
{
|
||||||
|
struct {
|
||||||
|
char *tgt, *lnk;
|
||||||
|
int optional;
|
||||||
|
} k[] = {
|
||||||
|
{ "/proc/self/fd", "/dev/fd", 0 },
|
||||||
|
{ "fd/0", "/dev/stdin", 0 },
|
||||||
|
{ "fd/1", "/dev/stdout", 0 },
|
||||||
|
{ "fd/2", "/dev/stderr", 0 },
|
||||||
|
{ "socksys", "/dev/nfsd", 0 },
|
||||||
|
{ "null", "/dev/X0R", 0 },
|
||||||
|
{ "/proc/kcore", "/dev/core", 1 },
|
||||||
|
{ "ram0", "/dev/ramdisk", 1 },
|
||||||
|
{ "qft0", "/dev/ftape", 1 },
|
||||||
|
{ "video0", "/dev/bttv0", 1 },
|
||||||
|
{ "radio0", "/dev/radio", 1 },
|
||||||
|
};
|
||||||
|
char *fn, buf[80];
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < NELEMS(k); i++) {
|
||||||
|
fn = k[i].tgt;
|
||||||
|
|
||||||
|
if (k[i].optional) {
|
||||||
|
if (fn[0] != '/') {
|
||||||
|
snprintf(buf, sizeof(buf), "/dev/%s", k[i].tgt);
|
||||||
|
fn = buf;
|
||||||
|
}
|
||||||
|
if (!fexist(fn))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ln(k[i].tgt, k[i].lnk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,93 +157,24 @@ static void setup(void *arg)
|
|||||||
{
|
{
|
||||||
mode_t prev;
|
mode_t prev;
|
||||||
|
|
||||||
/* Cleanup stale files, if any still linger on. */
|
|
||||||
bootclean();
|
|
||||||
|
|
||||||
prev = umask(0);
|
prev = umask(0);
|
||||||
|
|
||||||
_d("Setting up FHS structure in /var ...");
|
/* Kernel symlinks, e.g. /proc/self/fd -> /dev/fd */
|
||||||
makedir("/var/cache", 0755);
|
kernel_links();
|
||||||
makedir("/var/db", 0755); /* _PATH_VARDB on some systems */
|
|
||||||
makedir("/var/games", 0755);
|
|
||||||
makedir("/var/lib", 0755);
|
|
||||||
makedir("/var/lib/misc", 0755); /* _PATH_VARDB on some systems */
|
|
||||||
makedir("/var/lib/alarm", 0755);
|
|
||||||
makedir("/var/lib/urandom",0755);
|
|
||||||
if (fisdir("/run")) {
|
|
||||||
_d("System with new /run tmpfs ...");
|
|
||||||
makedir("/run/lock", 1777);
|
|
||||||
symlink("/run/lock", "/var/lock");
|
|
||||||
symlink("/dev/shm", "/run/shm");
|
|
||||||
|
|
||||||
/* compat only, should really be set up by OS/dist */
|
/* Create all system tmpfiles.d(5) */
|
||||||
symlink("/run", "/var/run");
|
tmpfilesd();
|
||||||
} else {
|
|
||||||
makedir("/var/lock", 1777);
|
|
||||||
makedir("/var/run", 0755);
|
|
||||||
}
|
|
||||||
makedir("/var/log", 0755);
|
|
||||||
makedir("/var/mail", 0755);
|
|
||||||
makedir("/var/opt", 0755);
|
|
||||||
makedir("/var/spool", 0755);
|
|
||||||
makedir("/var/spool/cron", 0755);
|
|
||||||
makedir("/var/tmp", 0755);
|
|
||||||
makedir("/var/empty", 0755);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* UTMP actually needs multiple db files
|
|
||||||
*/
|
|
||||||
if (has_utmp()) {
|
|
||||||
int gid;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If /etc/group or "utmp" group is missing, default to
|
|
||||||
* "root", or "wheel", group.
|
|
||||||
*/
|
|
||||||
_d("Setting up necessary UTMP files ...");
|
|
||||||
gid = getgroup("utmp");
|
|
||||||
if (gid < 0)
|
|
||||||
gid = 0;
|
|
||||||
|
|
||||||
create("/var/run/utmp", 0644, 0, gid); /* Currently logged in */
|
|
||||||
create("/var/log/wtmp", 0644, 0, gid); /* Login history */
|
|
||||||
create("/var/log/btmp", 0600, 0, gid); /* Failed logins */
|
|
||||||
create("/var/log/lastlog", 0644, 0, gid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set BOOT_TIME UTMP entry */
|
/* Set BOOT_TIME UTMP entry */
|
||||||
utmp_set_boot();
|
utmp_set_boot();
|
||||||
|
|
||||||
#ifdef TOUCH_ETC_NETWORK_RUN_IFSTATE
|
|
||||||
touch("/etc/network/run/ifstate");
|
|
||||||
#else
|
|
||||||
erase("/etc/network/run/ifstate");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_d("Setting up misc files ...");
|
|
||||||
makedir("/var/run/network",0755); /* Needed by Debian/Ubuntu ifupdown */
|
|
||||||
makedir("/var/run/lldpd", 0755); /* Needed by lldpd */
|
|
||||||
makedir("/var/run/pluto", 0755); /* Needed by Openswan */
|
|
||||||
mksubsys("/var/run/quagga", 0755, "quagga", "quagga");
|
|
||||||
mksubsys("/var/log/quagga", 0755, "quagga", "quagga");
|
|
||||||
mksubsys("/var/run/frr", 0755, "frr", "frr");
|
|
||||||
mksubsys("/var/log/frr", 0755, "frr", "frr");
|
|
||||||
makedir("/var/run/sshd", 01755); /* OpenSSH */
|
|
||||||
|
|
||||||
if (!fexist("/etc/mtab"))
|
|
||||||
symlink("../proc/self/mounts", "/etc/mtab");
|
|
||||||
|
|
||||||
/* Void Linux has a uuidd that runs as uuid:uuid and needs /run/uuid */
|
|
||||||
mksubsys("/var/run/uuidd", 0755, "uuidd", "uuidd");
|
|
||||||
|
|
||||||
umask(prev);
|
umask(prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
.name = __FILE__,
|
.name = __FILE__,
|
||||||
.hook[HOOK_BASEFS_UP] = {
|
.hook[HOOK_MOUNT_POST] = { .cb = clean },
|
||||||
.cb = setup
|
.hook[HOOK_BASEFS_UP] = { .cb = setup },
|
||||||
},
|
|
||||||
.depends = { "pidfile" },
|
.depends = { "pidfile" },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+115
-24
@@ -1,6 +1,6 @@
|
|||||||
/* Setup and start system message bus, D-Bus
|
/* Setup and start system message bus, D-Bus
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -22,7 +22,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@@ -31,49 +35,136 @@
|
|||||||
#include "service.h"
|
#include "service.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
|
||||||
#define DAEMON "dbus-daemon"
|
#define DBUS_DAEMON "dbus-daemon"
|
||||||
#define ARGS "--nofork --system --syslog-only"
|
#define DBUS_ARGS "--nofork --system --syslog-only"
|
||||||
#define DESC "D-Bus message bus daemon"
|
#define DBUS_DESC "D-Bus message bus daemon"
|
||||||
|
|
||||||
#define DAEMONUSER "messagebus"
|
#ifndef DBUS_DAEMONUSER
|
||||||
|
#define DBUS_DAEMONUSER "messagebus"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DBUS_DAEMONGROUP
|
||||||
|
#define DBUS_DAEMONGROUP "messagebus"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dumnpster diving for the D-Bus main configuration file
|
||||||
|
* where <pidfile> is defined.
|
||||||
|
*/
|
||||||
|
static char *dbus_pidfn(void)
|
||||||
|
{
|
||||||
|
char *alt[] = {
|
||||||
|
"/usr/share/dbus-1/system.conf",
|
||||||
|
"/etc/dbus-1/system.conf",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; alt[i]; i++) {
|
||||||
|
char *fn = alt[i];
|
||||||
|
char buf[256];
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopen(fn, "r");
|
||||||
|
if (!fp)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
fn = NULL;
|
||||||
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
char *pos;
|
||||||
|
|
||||||
|
pos = strstr(buf, "<pidfile>");
|
||||||
|
if (!pos)
|
||||||
|
continue;
|
||||||
|
fn = pos + strlen("<pidfile>");
|
||||||
|
pos = strstr(fn, "</pidfile>");
|
||||||
|
if (!pos) {
|
||||||
|
fn = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
if (fn)
|
||||||
|
return strdup(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
{
|
{
|
||||||
|
char *group = DBUS_DAEMONGROUP;
|
||||||
|
char *user = DBUS_DAEMONUSER;
|
||||||
char line[256];
|
char line[256];
|
||||||
|
char *pidfn;
|
||||||
mode_t prev;
|
mode_t prev;
|
||||||
char *cmd;
|
char *cmd;
|
||||||
|
|
||||||
cmd = which(DAEMON);
|
if (rescue) {
|
||||||
if (!cmd) {
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
_d("Skipping plugin, %s is not installed.", DAEMON);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
prev =umask(0);
|
cmd = which(DBUS_DAEMON);
|
||||||
|
if (!cmd) {
|
||||||
|
dbg("Skipping plugin, %s is not installed.", DBUS_DAEMON);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mksubsys("/var/run/dbus", 0755, DAEMONUSER, DAEMONUSER);
|
if (getuser(user, NULL) == -1) {
|
||||||
|
if (getuser("dbus", NULL) == -1)
|
||||||
|
user = "root"; /* fallback */
|
||||||
|
else
|
||||||
|
user = "dbus"; /* e.g., Buildroot */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getgroup(group) == -1) {
|
||||||
|
if (getgroup("dbus") == -1)
|
||||||
|
group = "root"; /* fallback */
|
||||||
|
else
|
||||||
|
group = "dbus"; /* e.g., Buildroot */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clean up from any previous pre-bootstrap run */
|
||||||
|
pidfn = dbus_pidfn();
|
||||||
|
if (pidfn)
|
||||||
|
remove(pidfn);
|
||||||
|
|
||||||
|
dbg("Creating D-Bus Required Directories ...");
|
||||||
|
prev = umask(0);
|
||||||
|
mksubsys("/var/run/dbus", 0755, user, group);
|
||||||
|
mksubsys("/var/run/lock/subsys", 0755, user, group);
|
||||||
|
mksubsys("/var/lib/dbus", 0755, user, group);
|
||||||
|
mksubsys("/tmp/dbus", 0755, user, group);
|
||||||
|
umask(prev);
|
||||||
|
|
||||||
|
/* Generate machine id for dbus */
|
||||||
if (whichp("dbus-uuidgen"))
|
if (whichp("dbus-uuidgen"))
|
||||||
run_interactive("dbus-uuidgen --ensure", "Creating machine UUID for D-Bus");
|
run_interactive("dbus-uuidgen --ensure", "Creating machine UUID for D-Bus");
|
||||||
|
|
||||||
/* Clean up from any previous pre-bootstrap run */
|
/*
|
||||||
remove("/var/run/dbus/pid");
|
* Register service with Finit
|
||||||
|
* Note: dbus drops privs after starting up.
|
||||||
|
*/
|
||||||
|
if (pidfn) {
|
||||||
|
snprintf(line, sizeof(line), "[S123456789] cgroup.system name:dbus pid:!%s %s %s -- %s",
|
||||||
|
pidfn, cmd, DBUS_ARGS, DBUS_DESC);
|
||||||
|
free(pidfn);
|
||||||
|
} else
|
||||||
|
snprintf(line, sizeof(line), "[S123456789] cgroup.system name:dbus %s %s -- %s",
|
||||||
|
cmd, DBUS_ARGS, DBUS_DESC);
|
||||||
|
|
||||||
/* Register service with Finit */
|
|
||||||
snprintf(line, sizeof(line), "[S12345] @%s:%s %s %s -- %s",
|
|
||||||
DAEMONUSER, DAEMONUSER, cmd, ARGS, DESC);
|
|
||||||
if (service_register(SVC_TYPE_SERVICE, line, global_rlimit, NULL))
|
if (service_register(SVC_TYPE_SERVICE, line, global_rlimit, NULL))
|
||||||
_pe("Failed registering %s", DAEMON);
|
err(1, "Failed registering %s", DBUS_DAEMON);
|
||||||
free(cmd);
|
|
||||||
|
|
||||||
umask(prev);
|
free(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
.name = __FILE__,
|
.name = __FILE__,
|
||||||
.hook[HOOK_NETWORK_UP] = {
|
.hook[HOOK_SVC_PLUGIN] = { .cb = setup },
|
||||||
.cb = setup
|
|
||||||
},
|
|
||||||
.depends = { "bootmisc", },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
/* Trigger scripts to run from finit's hooks
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Tobias Waldekranz <tobias@waldekranz.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "finit.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
#include "plugin.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
extern void plugin_script_run(hook_point_t no);
|
||||||
|
|
||||||
|
static void hscript_run_parts(hook_point_t no)
|
||||||
|
{
|
||||||
|
plugin_script_run(no);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hscript_banner(void *arg)
|
||||||
|
{
|
||||||
|
hscript_run_parts(HOOK_BANNER);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hscript_rootfs_up(void *arg)
|
||||||
|
{
|
||||||
|
hscript_run_parts(HOOK_ROOTFS_UP);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hscript_mount_error(void *arg)
|
||||||
|
{
|
||||||
|
hscript_run_parts(HOOK_MOUNT_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hscript_mount_post(void *arg)
|
||||||
|
{
|
||||||
|
hscript_run_parts(HOOK_MOUNT_POST);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hscript_basefs_up(void *arg)
|
||||||
|
{
|
||||||
|
hscript_run_parts(HOOK_BASEFS_UP);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hscript_network_up(void *arg)
|
||||||
|
{
|
||||||
|
hscript_run_parts(HOOK_NETWORK_UP);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hscript_svc_up(void *arg)
|
||||||
|
{
|
||||||
|
hscript_run_parts(HOOK_SVC_UP);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hscript_system_up(void *arg)
|
||||||
|
{
|
||||||
|
hscript_run_parts(HOOK_SYSTEM_UP);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hscript_shutdown(void *arg)
|
||||||
|
{
|
||||||
|
hscript_run_parts(HOOK_SHUTDOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static plugin_t plugin = {
|
||||||
|
.name = __FILE__,
|
||||||
|
.hook[HOOK_BANNER] = { .cb = hscript_banner },
|
||||||
|
.hook[HOOK_ROOTFS_UP] = { .cb = hscript_rootfs_up },
|
||||||
|
.hook[HOOK_MOUNT_ERROR] = { .cb = hscript_mount_error },
|
||||||
|
.hook[HOOK_MOUNT_POST] = { .cb = hscript_mount_post },
|
||||||
|
.hook[HOOK_BASEFS_UP] = { .cb = hscript_basefs_up },
|
||||||
|
.hook[HOOK_NETWORK_UP] = { .cb = hscript_network_up },
|
||||||
|
.hook[HOOK_SVC_UP] = { .cb = hscript_svc_up },
|
||||||
|
.hook[HOOK_SYSTEM_UP] = { .cb = hscript_system_up },
|
||||||
|
.hook[HOOK_SHUTDOWN] = { .cb = hscript_shutdown },
|
||||||
|
/*
|
||||||
|
* We have exited here, so these are handled a bit differently by Finit,
|
||||||
|
* when hook scripts are enabled, just to provide the user with the same
|
||||||
|
* interface:
|
||||||
|
*
|
||||||
|
* .hook[HOOK_SVC_DN] = { .cb = hscript_svc_down },
|
||||||
|
* .hook[HOOK_SYS_DN] = { .cb = hscript_system_down },
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
|
||||||
|
PLUGIN_INIT(plugin_init)
|
||||||
|
{
|
||||||
|
plugin_register(&plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
PLUGIN_EXIT(plugin_exit)
|
||||||
|
{
|
||||||
|
plugin_unregister(&plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Variables:
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
/* Heuristically find and initialize a suitable hotplug daemon
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "conf.h"
|
|
||||||
#include "finit.h"
|
|
||||||
#include "helpers.h"
|
|
||||||
#include "plugin.h"
|
|
||||||
#include "service.h"
|
|
||||||
|
|
||||||
static void setup(void *arg)
|
|
||||||
{
|
|
||||||
char cmd[256];
|
|
||||||
char *path;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Populate /dev and prepare for runtime events from kernel.
|
|
||||||
* Prefer udev if mdev is also available on the system.
|
|
||||||
*/
|
|
||||||
path = which("udevd");
|
|
||||||
if (!path)
|
|
||||||
path = which("/lib/systemd/systemd-udevd");
|
|
||||||
if (path) {
|
|
||||||
/* Register udevd as a monitored service */
|
|
||||||
snprintf(cmd, sizeof(cmd), "[S12345789] pid:udevd name:udevd log %s "
|
|
||||||
"-- Device event managing daemon", path);
|
|
||||||
if (service_register(SVC_TYPE_SERVICE, cmd, global_rlimit, NULL)) {
|
|
||||||
_pe("Failed registering %s", path);
|
|
||||||
} else {
|
|
||||||
snprintf(cmd, sizeof(cmd), ":1 [S] <pid/udevd> log "
|
|
||||||
"udevadm trigger -c add -t devices "
|
|
||||||
"-- Requesting device events");
|
|
||||||
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
|
||||||
|
|
||||||
snprintf(cmd, sizeof(cmd), ":2 [S] <pid/udevd> log "
|
|
||||||
"udevadm trigger -c add -t subsystems "
|
|
||||||
"-- Requesting subsystem events");
|
|
||||||
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(path);
|
|
||||||
|
|
||||||
/* Debian has this little script to copy generated
|
|
||||||
* rules while the system was read-only. TODO: When
|
|
||||||
* this functionality was hardcoded in finit.c, this
|
|
||||||
* call was made in crank_worker(). Now that
|
|
||||||
* filesystems are mounted earlier we should be able
|
|
||||||
* to make this call directly after the triggers have
|
|
||||||
* run, but this has not been tested AT ALL. */
|
|
||||||
if (fexist("/lib/udev/udev-finish"))
|
|
||||||
run_interactive("/lib/udev/udev-finish", "Finalizing udev");
|
|
||||||
} else {
|
|
||||||
path = which("mdev");
|
|
||||||
if (path) {
|
|
||||||
/* Embedded Linux systems usually have BusyBox mdev */
|
|
||||||
if (debug)
|
|
||||||
touch("/dev/mdev.log");
|
|
||||||
|
|
||||||
snprintf(cmd, sizeof(cmd), "%s -s", path);
|
|
||||||
free(path);
|
|
||||||
|
|
||||||
run_interactive(cmd, "Populating device tree");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static plugin_t plugin = {
|
|
||||||
.name = __FILE__,
|
|
||||||
.hook[HOOK_BASEFS_UP] = {
|
|
||||||
.cb = setup
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
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:
|
|
||||||
*/
|
|
||||||
+79
-15
@@ -1,6 +1,6 @@
|
|||||||
/* Coldplug modules using modalias magic
|
/* Coldplug modules using modalias magic
|
||||||
*
|
*
|
||||||
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2021-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -40,11 +40,15 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/time.h> /* gettimeofday() */
|
#include <sys/time.h> /* gettimeofday() */
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "util.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
|
||||||
struct module {
|
struct module {
|
||||||
@@ -67,14 +71,14 @@ static int modprobe(char *alias)
|
|||||||
pid = fork();
|
pid = fork();
|
||||||
switch (pid) {
|
switch (pid) {
|
||||||
case -1:
|
case -1:
|
||||||
_pe("Failed forking modprobe child");
|
err(1, "Failed forking modprobe child");
|
||||||
return 1;
|
return 1;
|
||||||
case 0:
|
case 0:
|
||||||
execvp(args[0], args);
|
execvp(args[0], args);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (!complete(args[0], pid))
|
if (!complete(args[0], pid))
|
||||||
_d("Successful modprobe of %s", alias);
|
dbg("Successful modprobe of %s", alias);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +106,7 @@ static void alias_remove(struct module *m)
|
|||||||
TAILQ_REMOVE(&modules, m, link);
|
TAILQ_REMOVE(&modules, m, link);
|
||||||
free(m->alias);
|
free(m->alias);
|
||||||
free(m);
|
free(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int alias_exist(char *alias)
|
static int alias_exist(char *alias)
|
||||||
{
|
{
|
||||||
@@ -116,27 +120,87 @@ static int alias_exist(char *alias)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int scan_alias(const char *path, const struct stat *st, int flag, struct FTW *unused)
|
static void alias_add_uniq(char *alias)
|
||||||
|
{
|
||||||
|
if (alias_exist(alias))
|
||||||
|
return;
|
||||||
|
|
||||||
|
alias_add(alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
static FILE *maybe_fopen_alias(const char *file, const char *path)
|
||||||
|
{
|
||||||
|
const char *basename;
|
||||||
|
|
||||||
|
basename = rindex(path, '/');
|
||||||
|
if (!basename)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
basename++;
|
||||||
|
if (strcmp(file, basename))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return fopen(path, "r");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int scan_modalias(const char *path)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
|
||||||
char buf[256];
|
char buf[256];
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
if (fnmatch("*/modalias", path, 0))
|
fp = maybe_fopen_alias("modalias", path);
|
||||||
return 0;
|
|
||||||
|
|
||||||
fp = fopen(path, "r");
|
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return 0;
|
return 1;
|
||||||
|
|
||||||
if (fgets(buf, sizeof(buf), fp)) {
|
if (fgets(buf, sizeof(buf), fp)) {
|
||||||
chomp(buf);
|
chomp(buf);
|
||||||
if (!alias_exist(buf))
|
alias_add_uniq(buf);
|
||||||
alias_add(buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int scan_uevent(const char *path)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = maybe_fopen_alias("uevent", path);
|
||||||
|
if (!fp)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
if (strstr(buf, "MODALIAS=") != buf)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
chomp(buf);
|
||||||
|
|
||||||
|
alias_add_uniq(buf + strlen("MODALIAS="));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int scan_alias(const char *path, const struct stat *st,
|
||||||
|
int flag, struct FTW *unused)
|
||||||
|
{
|
||||||
|
/* Sanity check: is this a regular file we can read? */
|
||||||
|
if (!(S_ISREG(st->st_mode) && (st->st_mode & S_IRUSR)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!scan_uevent(path))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
scan_modalias(path);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void coldplug(void *arg)
|
static void coldplug(void *arg)
|
||||||
{
|
{
|
||||||
struct module *m, *tmp;
|
struct module *m, *tmp;
|
||||||
|
|||||||
+169
-44
@@ -21,10 +21,37 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <lite/lite.h>
|
/*
|
||||||
|
* This plugin scans files in /etc/modules-load.d/, for each line in the
|
||||||
|
* file it assumes the name of a kernel module, with optional arguments.
|
||||||
|
* Each module is loaded when entering runlevel 2, 3, 4, or 5, using the
|
||||||
|
* modprobe tool.
|
||||||
|
*
|
||||||
|
* Loading is done by inserting a `task` stanza in Finit, ensuring all
|
||||||
|
* modules are loaded in parallel, with other modules and programs.
|
||||||
|
* Each `task` stanza is by default given the name:modprobe.module and
|
||||||
|
* indexed with `:ID`, starting with 1.
|
||||||
|
*
|
||||||
|
* Indexing can be disabled per file in /etc/modules-load.d/, anywwhere
|
||||||
|
* in a file, by putting the keyword `noindex` on a line of its own. A
|
||||||
|
* noindex command can appear anywhere in the file, and up to the point
|
||||||
|
* it is read, tasks will be indexed with an incrementing `:ID`. When
|
||||||
|
* `noindex` is read indexing is disabled and all subseequent tasks will
|
||||||
|
* not have any `:ID` at all.
|
||||||
|
*
|
||||||
|
* Please note, the :ID is there for your benefit, it ensures that tasks
|
||||||
|
* in Finit are unique. If you have two tasks with the same name and ID
|
||||||
|
* (or no ID), the last one read replaces any preceeding one!
|
||||||
|
*/
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
@@ -35,60 +62,158 @@
|
|||||||
#ifndef MODULES_LOAD_PATH
|
#ifndef MODULES_LOAD_PATH
|
||||||
#define MODULES_LOAD_PATH "/etc/modules-load.d"
|
#define MODULES_LOAD_PATH "/etc/modules-load.d"
|
||||||
#endif
|
#endif
|
||||||
|
#define MODPROBE_PATH "/sbin/modprobe"
|
||||||
#define SERVICE_LINE \
|
#define SERVICE_LINE \
|
||||||
":%d name:modprobe.%s [2345] /sbin/modprobe %s %s -- Kernel module: %s"
|
"cgroup.init name:modprobe.%s :%d [%s] %s %s %s --"
|
||||||
|
#define SERVICE_LINE_NOINDEX \
|
||||||
|
"cgroup.init name:modprobe.%s [%s] %s %s %s --"
|
||||||
|
|
||||||
|
static int modules_load(const char *file, int index)
|
||||||
|
{
|
||||||
|
char module_path[PATH_MAX];
|
||||||
|
char *modprobe_path;
|
||||||
|
int num = 0;
|
||||||
|
char *line;
|
||||||
|
char *lvl;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
strlcpy(module_path, MODULES_LOAD_PATH "/", sizeof(module_path));
|
||||||
|
strlcat(module_path, file, sizeof(module_path));
|
||||||
|
|
||||||
|
fp = fopen(module_path, "r");
|
||||||
|
if (!fp) {
|
||||||
|
warnx("failed opening %s for reading, skipping ...", module_path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
modprobe_path = strdup(MODPROBE_PATH);
|
||||||
|
if (!modprobe_path) {
|
||||||
|
fail:
|
||||||
|
warnx("failed allocating memory in modules-load plugin.");
|
||||||
|
fclose(fp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
lvl = strdup("S");
|
||||||
|
if (!lvl) {
|
||||||
|
free(modprobe_path);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((line = fparseln(fp, NULL, NULL, NULL, 0))) {
|
||||||
|
char cmd[CMD_SIZE * 2], *mod, *args, *set;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* fparseln() skips regular UNIX comments only.
|
||||||
|
* This is for modules-load.d(5) compat.
|
||||||
|
*/
|
||||||
|
if (line[0] == ';')
|
||||||
|
goto next;
|
||||||
|
|
||||||
|
/* trim whitespace */
|
||||||
|
mod = strip_line(line);
|
||||||
|
if (!mod[0])
|
||||||
|
goto next;
|
||||||
|
|
||||||
|
/* Finit extension 'set foo bar' */
|
||||||
|
if ((set = fgetval(mod, "set", "= \t"))) {
|
||||||
|
char *val = mod;
|
||||||
|
|
||||||
|
if (!strcmp(set, "noindex")) {
|
||||||
|
index = 0;
|
||||||
|
free(set);
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((val = fgetval(set, "index", "= \t"))) {
|
||||||
|
index = atoi(val);
|
||||||
|
free(set);
|
||||||
|
free(val);
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((val = fgetval(set, "runlevel", "= \t"))) {
|
||||||
|
free(lvl);
|
||||||
|
lvl = val;
|
||||||
|
free(set);
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((val = fgetval(set, "modprobe", "= \t"))) {
|
||||||
|
if (access(val, X_OK)) {
|
||||||
|
warn("%s: cannot use %s", module_path, val);
|
||||||
|
free(set);
|
||||||
|
free(val);
|
||||||
|
free(line);
|
||||||
|
goto skip;
|
||||||
|
} else {
|
||||||
|
free(modprobe_path);
|
||||||
|
modprobe_path = val;
|
||||||
|
}
|
||||||
|
free(set);
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* unknown 'set' command, ignore. */
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
|
mod = strtok_r(mod, " ", &args);
|
||||||
|
if (!mod)
|
||||||
|
goto next;
|
||||||
|
|
||||||
|
if (!index)
|
||||||
|
snprintf(cmd, sizeof(cmd), SERVICE_LINE_NOINDEX, mod, lvl, modprobe_path, mod, args);
|
||||||
|
else
|
||||||
|
snprintf(cmd, sizeof(cmd), SERVICE_LINE, mod, index++, lvl, modprobe_path, mod, args);
|
||||||
|
|
||||||
|
dbg("task %s", cmd);
|
||||||
|
service_register(SVC_TYPE_TASK, cmd, global_rlimit, NULL);
|
||||||
|
num++;
|
||||||
|
next:
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
skip:
|
||||||
|
free(modprobe_path);
|
||||||
|
free(lvl);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XXX: check here for .conf only? */
|
||||||
|
static int module_filter(const struct dirent *d)
|
||||||
|
{
|
||||||
|
if (d->d_type == DT_DIR)
|
||||||
|
return 0;
|
||||||
|
if (d->d_name[0] == '.')
|
||||||
|
return 0; /* skip dot files */
|
||||||
|
if (d->d_name[strlen(d->d_name) - 1] == '~')
|
||||||
|
return 0; /* skip backup files */
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void load(void *arg)
|
static void load(void *arg)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
struct dirent **dentry;
|
||||||
DIR *dirp;
|
|
||||||
struct dirent *direntp;
|
|
||||||
char line[256];
|
|
||||||
int index = 1;
|
int index = 1;
|
||||||
|
int i, num;
|
||||||
|
|
||||||
_d("Scanning " MODULES_LOAD_PATH " for config files ...");
|
dbg("Scanning " MODULES_LOAD_PATH " for config files ...");
|
||||||
|
num = scandir(MODULES_LOAD_PATH, &dentry, module_filter, alphasort);
|
||||||
dirp = opendir(MODULES_LOAD_PATH);
|
if (num > 0) {
|
||||||
if (!dirp) return;
|
for (i = 0; i < num; i++) {
|
||||||
|
index += modules_load(dentry[i]->d_name, index);
|
||||||
while ((direntp = readdir(dirp)))
|
free(dentry[i]);
|
||||||
{
|
|
||||||
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++;
|
|
||||||
}
|
}
|
||||||
|
free(dentry);
|
||||||
fclose(fp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
closedir(dirp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
.name = __FILE__,
|
.name = __FILE__,
|
||||||
.hook[HOOK_BASEFS_UP] = {
|
.hook[HOOK_SVC_PLUGIN] = { .cb = load },
|
||||||
.cb = load
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
|
|||||||
+245
-57
@@ -1,7 +1,8 @@
|
|||||||
|
|
||||||
/* Netlink plugin for IFUP/IFDN and GW events
|
/* Netlink plugin for IFUP/IFDN and GW events
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009-2011 Mårten Wikström <marten.wikstrom@keystream.se>
|
* Copyright (C) 2009-2011 Mårten Wikström <marten.wikstrom@keystream.se>
|
||||||
* Copyright (C) 2009-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (C) 2009-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
@@ -30,34 +31,38 @@
|
|||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
#include "service.h"
|
||||||
|
|
||||||
static int nlmsg_validate(struct nlmsghdr *nh, size_t len)
|
#define NL_BUFSZ 4096
|
||||||
{
|
|
||||||
if (!NLMSG_OK(nh, len))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (nh->nlmsg_type == NLMSG_DONE) {
|
struct nl_request {
|
||||||
_d("Done with netlink messages.");
|
struct nlmsghdr nh;
|
||||||
return 1;
|
union {
|
||||||
}
|
struct rtmsg rtm;
|
||||||
|
struct ifinfomsg ifi;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
if (nh->nlmsg_type == NLMSG_ERROR) {
|
static int nl_defidx;
|
||||||
_d("Netlink reports error.");
|
static int nl_ifdown;
|
||||||
return 1;
|
static char *nl_buf;
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
|
static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
|
||||||
{
|
{
|
||||||
|
char daddr[INET_ADDRSTRLEN];
|
||||||
|
char gaddr[INET_ADDRSTRLEN];
|
||||||
|
struct in_addr ind, ing;
|
||||||
struct rtmsg *r;
|
struct rtmsg *r;
|
||||||
struct rtattr *a;
|
struct rtattr *a;
|
||||||
|
int plen = 0;
|
||||||
|
int dst = 0;
|
||||||
|
int idx = 0;
|
||||||
|
int gw = 0;
|
||||||
int la;
|
int la;
|
||||||
int gw = 0, dst = 0, mask = 0, idx = 0;
|
|
||||||
|
|
||||||
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg))) {
|
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg))) {
|
||||||
_e("Packet too small or truncated!");
|
errx(1, "Packet too small or truncated!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +70,7 @@ static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
a = RTM_RTA(r);
|
a = RTM_RTA(r);
|
||||||
la = RTM_PAYLOAD(nlmsg);
|
la = RTM_PAYLOAD(nlmsg);
|
||||||
if (la >= len) {
|
if (la >= len) {
|
||||||
_e("Packet too large!");
|
errx(1, "Packet too large!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,29 +80,38 @@ static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
switch (a->rta_type) {
|
switch (a->rta_type) {
|
||||||
case RTA_GATEWAY:
|
case RTA_GATEWAY:
|
||||||
gw = *((int *)data);
|
gw = *((int *)data);
|
||||||
//_d("GW: 0x%04x", gw);
|
//dbg("GW: 0x%04x", gw);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTA_DST:
|
case RTA_DST:
|
||||||
dst = *((int *)data);
|
dst = *((int *)data);
|
||||||
mask = r->rtm_dst_len;
|
plen = r->rtm_dst_len;
|
||||||
//_d("MASK: 0x%04x", mask);
|
//dbg("Prefix LEN: 0x%04x", plen);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTA_OIF:
|
case RTA_OIF:
|
||||||
idx = *((int *)data);
|
idx = *((int *)data);
|
||||||
//_d("IDX: 0x%04x", idx);
|
//dbg("IDX: 0x%04x", idx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
a = RTA_NEXT(a, la);
|
a = RTA_NEXT(a, la);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!dst && !mask) && (gw || idx)) {
|
ind.s_addr = dst;
|
||||||
if (nlmsg->nlmsg_type == RTM_DELROUTE)
|
ing.s_addr = gw;
|
||||||
|
inet_ntop(AF_INET, &ind, daddr, sizeof(daddr));
|
||||||
|
inet_ntop(AF_INET, &ing, gaddr, sizeof(gaddr));
|
||||||
|
dbg("Got gw %s dst/len %s/%d ifindex %d", gaddr, daddr, plen, idx);
|
||||||
|
|
||||||
|
if ((!dst && !plen) && (gw || idx)) {
|
||||||
|
if (nlmsg->nlmsg_type == RTM_DELROUTE) {
|
||||||
cond_clear("net/route/default");
|
cond_clear("net/route/default");
|
||||||
else
|
nl_defidx = 0;
|
||||||
|
} else {
|
||||||
cond_set("net/route/default");
|
cond_set("net/route/default");
|
||||||
|
nl_defidx = idx;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,14 +131,14 @@ static int validate_ifname(const char *ifname)
|
|||||||
if (!ifname || !ifname[0])
|
if (!ifname || !ifname[0])
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (strlen(ifname) >= IFNAMSIZ)
|
if (strnlen(ifname, IFNAMSIZ) == IFNAMSIZ)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (strstr(ifname, ".."))
|
if (!strcmp(ifname, ".") || !strcmp(ifname, ".."))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
while (*ifname) {
|
while (*ifname) {
|
||||||
if (*ifname == '/' || isspace(*ifname))
|
if (*ifname == '/' || *ifname == ':' || isspace(*ifname))
|
||||||
return 1;
|
return 1;
|
||||||
ifname++;
|
ifname++;
|
||||||
}
|
}
|
||||||
@@ -132,15 +146,28 @@ static int validate_ifname(const char *ifname)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if this interface was associated with the default route
|
||||||
|
* previously, or if it's been removed. If so, trigger a recheck
|
||||||
|
* of the system default route.
|
||||||
|
*/
|
||||||
|
static void nl_check_default(char *ifname)
|
||||||
|
{
|
||||||
|
int idx = (int)if_nametoindex(ifname);
|
||||||
|
|
||||||
|
if ((nl_defidx > 0 && nl_defidx == idx) || (idx == 0 && errno == ENODEV))
|
||||||
|
nl_ifdown = 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
||||||
{
|
{
|
||||||
int la;
|
|
||||||
char ifname[IFNAMSIZ + 1];
|
char ifname[IFNAMSIZ + 1];
|
||||||
struct rtattr *a;
|
|
||||||
struct ifinfomsg *i;
|
struct ifinfomsg *i;
|
||||||
|
struct rtattr *a;
|
||||||
|
int la;
|
||||||
|
|
||||||
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) {
|
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) {
|
||||||
_e("Packet too small or truncated!");
|
errx(1, "Packet too small or truncated!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,7 +175,7 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
a = (struct rtattr *)((char *)i + NLMSG_ALIGN(sizeof(struct ifinfomsg)));
|
a = (struct rtattr *)((char *)i + NLMSG_ALIGN(sizeof(struct ifinfomsg)));
|
||||||
la = NLMSG_PAYLOAD(nlmsg, sizeof(struct ifinfomsg));
|
la = NLMSG_PAYLOAD(nlmsg, sizeof(struct ifinfomsg));
|
||||||
if (la >= len) {
|
if (la >= len) {
|
||||||
_e("Packet too large!");
|
errx(1, "Packet too large!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,7 +185,7 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
|
|
||||||
strlcpy(ifname, RTA_DATA(a), sizeof(ifname));
|
strlcpy(ifname, RTA_DATA(a), sizeof(ifname));
|
||||||
if (validate_ifname(ifname)) {
|
if (validate_ifname(ifname)) {
|
||||||
_d("Invalid interface name '%s', skipping ...", ifname);
|
dbg("Invalid interface name '%s', skipping ...", ifname);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,55 +195,208 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
* New interface has appeared, or interface flags has changed.
|
* New interface has appeared, or interface flags has changed.
|
||||||
* Check ifi_flags here to see if the interface is UP/DOWN
|
* Check ifi_flags here to see if the interface is UP/DOWN
|
||||||
*/
|
*/
|
||||||
_d("%s: New link, flags 0x%x, change 0x%x", ifname, i->ifi_flags, i->ifi_change);
|
dbg("%s: New link, flags 0x%x, change 0x%x", ifname, i->ifi_flags, i->ifi_change);
|
||||||
net_cond_set(ifname, "exist", 1);
|
net_cond_set(ifname, "exist", 1);
|
||||||
net_cond_set(ifname, "up", i->ifi_flags & IFF_UP);
|
net_cond_set(ifname, "up", i->ifi_flags & IFF_UP);
|
||||||
net_cond_set(ifname, "running", i->ifi_flags & IFF_RUNNING);
|
net_cond_set(ifname, "running", i->ifi_flags & IFF_RUNNING);
|
||||||
|
if (!(i->ifi_flags & IFF_UP) || !(i->ifi_flags & IFF_RUNNING))
|
||||||
|
nl_check_default(ifname);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTM_DELLINK:
|
case RTM_DELLINK:
|
||||||
/* NOTE: Interface has disappeared, not link down ... */
|
/* NOTE: Interface has disappeared, not link down ... */
|
||||||
_d("%s: Delete link", ifname);
|
dbg("%s: Delete link", ifname);
|
||||||
net_cond_set(ifname, "exist", 0);
|
net_cond_set(ifname, "exist", 0);
|
||||||
net_cond_set(ifname, "up", 0);
|
net_cond_set(ifname, "up", 0);
|
||||||
net_cond_set(ifname, "running", 0);
|
net_cond_set(ifname, "running", 0);
|
||||||
|
nl_check_default(ifname);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTM_NEWADDR:
|
case RTM_NEWADDR:
|
||||||
_d("%s: New Address", ifname);
|
dbg("%s: New Address", ifname);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTM_DELADDR:
|
case RTM_DELADDR:
|
||||||
_d("%s: Deconfig Address", ifname);
|
dbg("%s: Deconfig Address", ifname);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_d("%s: Msg 0x%x", ifname, nlmsg->nlmsg_type);
|
dbg("%s: Msg 0x%x", ifname, nlmsg->nlmsg_type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nl_callback(void *arg, int sd, int events)
|
static int nl_parse(int sd)
|
||||||
{
|
{
|
||||||
static char buf[4096];
|
while (1) {
|
||||||
struct nlmsghdr *nh;
|
struct nlmsghdr *nh;
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
|
size_t l;
|
||||||
|
|
||||||
memset(buf, 0, sizeof(buf));
|
while ((len = recv(sd, nl_buf, NL_BUFSZ, 0)) < 0) {
|
||||||
len = recv(sd, buf, sizeof(buf), 0);
|
switch (errno) {
|
||||||
if (len < 0) {
|
case EAGAIN: /* Nothing more right now. */
|
||||||
if (errno != EINTR) /* Signal */
|
return 0;
|
||||||
_pe("recv()");
|
|
||||||
|
case EINTR: /* Signal */
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case ENOBUFS: /* netlink(7) */
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
err(1, "recv()");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dbg("recv %zd bytes", len);
|
||||||
|
l = (size_t)len;
|
||||||
|
for (nh = (struct nlmsghdr *)nl_buf; NLMSG_OK(nh, l); nh = NLMSG_NEXT(nh, l)) {
|
||||||
|
struct nlmsgerr *nle;
|
||||||
|
|
||||||
|
switch (nh->nlmsg_type) {
|
||||||
|
case NLMSG_DONE:
|
||||||
|
// dbg("Done with netlink messages.");
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case NLMSG_ERROR:
|
||||||
|
// dbg("Kernel netlink comm. error.");
|
||||||
|
nle = NLMSG_DATA(nh);
|
||||||
|
if (nle) {
|
||||||
|
errno = -nle->error;
|
||||||
|
err(1, "Kernel netlink error %d", errno);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
case RTM_NEWROUTE:
|
||||||
|
case RTM_DELROUTE:
|
||||||
|
// dbg("Netlink route ...");
|
||||||
|
nl_route(nh, len);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RTM_NEWLINK:
|
||||||
|
case RTM_DELLINK:
|
||||||
|
// dbg("Netlink link ...");
|
||||||
|
nl_link(nh, len);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
warnx("unhandled netlink message, type %d", nh->nlmsg_type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nl_request(int sd, unsigned int seq, int type)
|
||||||
|
{
|
||||||
|
struct nl_request *nlr = (struct nl_request *)nl_buf;
|
||||||
|
|
||||||
|
memset(nlr, 0, sizeof(struct nl_request));
|
||||||
|
nlr->nh.nlmsg_type = type;
|
||||||
|
nlr->nh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
|
||||||
|
nlr->nh.nlmsg_seq = seq;
|
||||||
|
nlr->nh.nlmsg_pid = 1;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case RTM_GETROUTE:
|
||||||
|
// dbg("RTM_GETROUTE");
|
||||||
|
nlr->rtm.rtm_family = AF_INET;
|
||||||
|
nlr->rtm.rtm_table = RT_TABLE_MAIN;
|
||||||
|
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RTM_GETLINK:
|
||||||
|
// dbg("RTM_GETLINK");
|
||||||
|
nlr->ifi.ifi_family = AF_UNSPEC;
|
||||||
|
nlr->ifi.ifi_change = 0xFFFFFFFF;
|
||||||
|
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
warnx("Cannot resync, unhandled message type %d", type);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (send(sd, nlr, nlr->nh.nlmsg_len, 0) < 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return nl_parse(sd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nl_resync_routes(int sd, unsigned int seq)
|
||||||
|
{
|
||||||
|
if (nl_request(sd, seq, RTM_GETROUTE))
|
||||||
|
err(1, "Failed netlink route request");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nl_resync_ifaces(int sd, unsigned int seq)
|
||||||
|
{
|
||||||
|
if (nl_request(sd, seq, RTM_GETLINK))
|
||||||
|
err(1, "Failed netlink link request");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We've potentially lost netlink events, let's resync with kernel.
|
||||||
|
*/
|
||||||
|
static void nl_resync(int all)
|
||||||
|
{
|
||||||
|
unsigned int seq = 0;
|
||||||
|
int sd;
|
||||||
|
|
||||||
|
sd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
|
||||||
|
if (sd < 0) {
|
||||||
|
err(1, "netlink socket");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (nh = (struct nlmsghdr *)buf; !nlmsg_validate(nh, len); nh = NLMSG_NEXT(nh, len)) {
|
if (all) {
|
||||||
//_d("Well formed netlink message received. type %d ...", nh->nlmsg_type);
|
dbg("============================ RESYNC =================================");
|
||||||
if (nh->nlmsg_type == RTM_NEWROUTE || nh->nlmsg_type == RTM_DELROUTE)
|
/* this doesn't update conditions, and thus does not stop services */
|
||||||
nl_route(nh, len);
|
cond_deassert("net/");
|
||||||
else
|
|
||||||
nl_link(nh, len);
|
nl_resync_ifaces(sd, seq++);
|
||||||
|
nl_resync_routes(sd, seq++);
|
||||||
|
|
||||||
|
/* delayed update after we've corrected things */
|
||||||
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
dbg("=========================== RESYNCED ================================");
|
||||||
|
} else
|
||||||
|
nl_resync_routes(sd, seq++);
|
||||||
|
|
||||||
|
close(sd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nl_callback(void *arg, int sd, int events)
|
||||||
|
{
|
||||||
|
if (nl_parse(sd) < 0) {
|
||||||
|
if (errno == ENOBUFS) { /* netlink(7) */
|
||||||
|
warnx("busy system, resynchronizing with kernel.");
|
||||||
|
nl_resync(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Linux doesn't send route changes when interfaces go down, so
|
||||||
|
* we need to check ourselves, e.g. for loss of default route.
|
||||||
|
*/
|
||||||
|
if (nl_ifdown) {
|
||||||
|
dbg("interface down, checking default route.");
|
||||||
|
if (nl_defidx > 0) {
|
||||||
|
nl_defidx = 0;
|
||||||
|
nl_resync(0);
|
||||||
|
if (nl_defidx <= 0) {
|
||||||
|
cond_clear("net/route/default");
|
||||||
|
nl_defidx = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nl_ifdown = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,22 +416,29 @@ static plugin_t plugin = {
|
|||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
{
|
{
|
||||||
int sd;
|
|
||||||
struct sockaddr_nl sa;
|
struct sockaddr_nl sa;
|
||||||
|
int sd;
|
||||||
|
|
||||||
sd = socket(AF_NETLINK, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, NETLINK_ROUTE);
|
sd = socket(AF_NETLINK, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, NETLINK_ROUTE);
|
||||||
if (sd < 0) {
|
if (sd < 0) {
|
||||||
_pe("socket()");
|
err(1, "socket()");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&sa, 0, sizeof(sa));
|
memset(&sa, 0, sizeof(sa));
|
||||||
sa.nl_family = AF_NETLINK;
|
sa.nl_family = AF_NETLINK;
|
||||||
sa.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_LINK; // | RTMGRP_NOTIFY | RTMGRP_IPV4_IFADDR;
|
sa.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_LINK;
|
||||||
sa.nl_pid = getpid();
|
sa.nl_pid = getpid();
|
||||||
|
|
||||||
if (bind(sd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
if (bind(sd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
||||||
_pe("bind()");
|
err(1, "bind()");
|
||||||
|
close(sd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nl_buf = malloc(NL_BUFSZ);
|
||||||
|
if (!nl_buf) {
|
||||||
|
err(1, "malloc()");
|
||||||
close(sd);
|
close(sd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -263,6 +450,7 @@ PLUGIN_INIT(plugin_init)
|
|||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(plugin_exit)
|
||||||
{
|
{
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
|
close(plugin.io.fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+63
-25
@@ -1,7 +1,7 @@
|
|||||||
/* Simple pidfile event monitor for the Finit condition engine
|
/* Simple pidfile event monitor for the Finit condition engine
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
|
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
|
||||||
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -52,7 +52,7 @@ static int pidfile_add_path(struct iwatch *iw, char *path)
|
|||||||
ptr = slash++;
|
ptr = slash++;
|
||||||
slash = strchr(ptr, '/');
|
slash = strchr(ptr, '/');
|
||||||
if (slash) {
|
if (slash) {
|
||||||
_d("Path too deep, skipping.");
|
dbg("Path too deep, skipping.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,36 +71,63 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
|
|||||||
if (fnmatch("*\\.pid", fn, 0) && fnmatch("*/pid", fn, 0))
|
if (fnmatch("*\\.pid", fn, 0) && fnmatch("*/pid", fn, 0))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_d("path: %s, mask: %08x", fn, mask);
|
dbg("path: %s, mask: %08x", fn, mask);
|
||||||
|
|
||||||
svc = svc_find_by_pidfile(fn);
|
svc = svc_find_by_pidfile(fn);
|
||||||
if (!svc) {
|
if (!svc) {
|
||||||
_d("No matching svc for %s", fn);
|
dbg("No matching svc for %s", fn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("Found svc %s for %s with pid %d", svc->name, fn, svc->pid);
|
dbg("Found svc %s for %s with pid %d", svc->name, fn, svc->pid);
|
||||||
|
|
||||||
mkcond(svc, cond, sizeof(cond));
|
mkcond(svc, cond, sizeof(cond));
|
||||||
|
|
||||||
if (mask & (IN_CLOSE_WRITE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) {
|
if (mask & (IN_CLOSE_WRITE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) {
|
||||||
svc_started(svc);
|
/*
|
||||||
if (!svc_has_pidfile(svc))
|
* only mark native services as started, the s6 and
|
||||||
|
* systemd style services rely on their respective
|
||||||
|
* readiness notification. Issue #343
|
||||||
|
*/
|
||||||
|
if (!svc->notify)
|
||||||
|
svc_started(svc);
|
||||||
|
|
||||||
|
if (!svc_has_pidfile(svc)) {
|
||||||
|
dbg("Setting %s PID file to %s", svc->name, fn);
|
||||||
pid_file_set(svc, fn, 1);
|
pid_file_set(svc, fn, 1);
|
||||||
|
}
|
||||||
|
|
||||||
if (svc_is_forking(svc)) {
|
if (svc_is_forking(svc)) {
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
pid = pid_file_read(pid_file(svc));
|
pid = pid_file_read(fn);
|
||||||
|
if (pid == -1) {
|
||||||
|
/* handle case when service dies immediately */
|
||||||
|
if (!fexist(fn))
|
||||||
|
cond_clear(cond);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Service is not crashing, let's tell state machine! */
|
||||||
|
service_forked(svc);
|
||||||
|
|
||||||
if (pid != svc->pid) {
|
if (pid != svc->pid) {
|
||||||
_d("Forking service %s changed PID from %d to %d",
|
dbg("Forking service %s (cmd %s) changed PID from %d to %d",
|
||||||
svc->cmd, svc->pid, pid);
|
svc_ident(svc, NULL, 0), svc->cmd, svc->pid, pid);
|
||||||
svc->pid = pid;
|
svc->pid = pid;
|
||||||
|
|
||||||
|
/* Complement log in service.c for non-forking services */
|
||||||
|
logit(LOG_CONSOLE | LOG_NOTICE, "Started %s[%d]", svc_ident(svc, NULL, 0), pid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cond_set(cond);
|
cond_set(cond);
|
||||||
} else if (mask & IN_DELETE)
|
if (!svc->notify)
|
||||||
|
service_ready(svc);
|
||||||
|
} else if (mask & IN_DELETE) {
|
||||||
cond_clear(cond);
|
cond_clear(cond);
|
||||||
|
if (!svc->notify)
|
||||||
|
service_ready(svc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* synthesize events in case of new run dirs */
|
/* synthesize events in case of new run dirs */
|
||||||
@@ -122,7 +149,7 @@ static void pidfile_scandir(struct iwatch *iw, char *dir, int len)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
for (i = 0; i < gl.gl_pathc; i++) {
|
for (i = 0; i < gl.gl_pathc; i++) {
|
||||||
_d("scan found %s", gl.gl_pathv[i]);
|
dbg("scan found %s", gl.gl_pathv[i]);
|
||||||
pidfile_update_conds(dir, gl.gl_pathv[i], IN_CREATE);
|
pidfile_update_conds(dir, gl.gl_pathv[i], IN_CREATE);
|
||||||
}
|
}
|
||||||
globfree(&gl);
|
globfree(&gl);
|
||||||
@@ -137,7 +164,7 @@ static void pidfile_handle_dir(struct iwatch *iw, char *dir, char *name, int mas
|
|||||||
struct iwatch_path *iwp;
|
struct iwatch_path *iwp;
|
||||||
|
|
||||||
paste(path, sizeof(path), dir, name);
|
paste(path, sizeof(path), dir, name);
|
||||||
_d("path: %s", path);
|
dbg("path: %s", path);
|
||||||
|
|
||||||
iwp = iwatch_find_by_path(iw, path);
|
iwp = iwatch_find_by_path(iw, path);
|
||||||
|
|
||||||
@@ -161,7 +188,7 @@ static void pidfile_callback(void *arg, int fd, int events)
|
|||||||
|
|
||||||
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
||||||
if (sz <= 0) {
|
if (sz <= 0) {
|
||||||
_pe("invalid inotify event");
|
err(1, "invalid inotify event");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ev_buf[sz] = 0;
|
ev_buf[sz] = 0;
|
||||||
@@ -213,6 +240,9 @@ static void pidfile_reconf(void *arg)
|
|||||||
if (svc_is_changed(svc) || svc_is_starting(svc))
|
if (svc_is_changed(svc) || svc_is_starting(svc))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (!svc->notify)
|
||||||
|
service_ready(svc);
|
||||||
|
|
||||||
mkcond(svc, cond, sizeof(cond));
|
mkcond(svc, cond, sizeof(cond));
|
||||||
if (cond_get(cond) == COND_ON)
|
if (cond_get(cond) == COND_ON)
|
||||||
continue;
|
continue;
|
||||||
@@ -221,9 +251,9 @@ static void pidfile_reconf(void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This will call service_step(), which in turn will schedule itself
|
* This calls service_step(), which in turn schedules itself as
|
||||||
* as long as stepped services change state. Services going from
|
* long as stepped services change state. Services going from
|
||||||
* WAITING to RUNNING will reassert their conditions in that loop,
|
* PAUSED to RUNNING reassert their conditions in that loop,
|
||||||
* which in turn may unlock other services, and so on.
|
* which in turn may unlock other services, and so on.
|
||||||
*/
|
*/
|
||||||
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_RUNTASK);
|
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_RUNTASK);
|
||||||
@@ -231,8 +261,14 @@ static void pidfile_reconf(void *arg)
|
|||||||
|
|
||||||
static void pidfile_init(void *arg)
|
static void pidfile_init(void *arg)
|
||||||
{
|
{
|
||||||
|
char piddir[MAX_ARG_LEN];
|
||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
|
if (mkpath(pid_runpath(_PATH_CONDPID, piddir, sizeof(piddir)), 0755) && errno != EEXIST) {
|
||||||
|
err(1, "Failed creating %s condition directory, %s", COND_PID, _PATH_CONDPID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The bootmisc plugin is responsible for setting up /var/run.
|
* The bootmisc plugin is responsible for setting up /var/run.
|
||||||
* and/or /run, with proper symlinks etc. We depend on bootmisc
|
* and/or /run, with proper symlinks etc. We depend on bootmisc
|
||||||
@@ -240,16 +276,18 @@ static void pidfile_init(void *arg)
|
|||||||
*/
|
*/
|
||||||
path = realpath(_PATH_VARRUN, NULL);
|
path = realpath(_PATH_VARRUN, NULL);
|
||||||
if (!path) {
|
if (!path) {
|
||||||
_d("Failed querying realpath(%s): %s", _PATH_VARRUN, strerror(errno));
|
dbg("Failed querying realpath(%s): %s", _PATH_VARRUN, strerror(errno));
|
||||||
path = realpath("/run", NULL);
|
path = realpath("/run", NULL);
|
||||||
if (!path) {
|
if (!path) {
|
||||||
_e("System does not have %s or /run, aborting.", _PATH_VARRUN);
|
errx(1, "System does not have %s or /run, aborting.", _PATH_VARRUN);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pidfile_add_path(&iw_pidfile, path))
|
if (pidfile_add_path(&iw_pidfile, path))
|
||||||
iwatch_exit(&iw_pidfile);
|
iwatch_exit(&iw_pidfile);
|
||||||
|
|
||||||
|
free(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -262,15 +300,15 @@ static void pidfile_init(void *arg)
|
|||||||
*
|
*
|
||||||
* service <net/iface/lo> /sbin/dropbear ...
|
* service <net/iface/lo> /sbin/dropbear ...
|
||||||
*
|
*
|
||||||
* Which provides the <pid/dropbear> condition, will not be set by
|
* This service provides the <pid/dropbear> condition, which will not be
|
||||||
* pidfile.so during `initctl reload` because dropbear is still
|
* set by pidfile.so during `initctl reload` because dropbear is still
|
||||||
* SIGSTP:ed waiting for <net/iface/lo>.
|
* SIGSTP:ed (in state PAUSED) waiting for <net/iface/lo>.
|
||||||
*/
|
*/
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
.name = __FILE__,
|
.name = __FILE__,
|
||||||
.hook[HOOK_BASEFS_UP] = { .cb = pidfile_init },
|
.hook[HOOK_BASEFS_UP] = { .cb = pidfile_init },
|
||||||
.hook[HOOK_SVC_RECONF] = { .cb = pidfile_reconf },
|
.hook[HOOK_SVC_RECONF] = { .cb = pidfile_reconf },
|
||||||
.depends = { "netlink" },
|
.depends = { "netlink" }, /* bootmisc depends on us */
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
@@ -290,8 +328,8 @@ PLUGIN_INIT(plugin_init)
|
|||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(plugin_exit)
|
||||||
{
|
{
|
||||||
iwatch_exit(&iw_pidfile);
|
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
|
iwatch_exit(&iw_pidfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+20
-6
@@ -1,6 +1,6 @@
|
|||||||
/* Set kernel variables from /etc/sysctl.conf et al
|
/* Set kernel variables from /etc/sysctl.conf et al
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2016-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -22,14 +22,24 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <glob.h>
|
#include <glob.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "finit.h"
|
||||||
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
|
||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
{
|
{
|
||||||
size_t i;
|
|
||||||
glob_t gl;
|
glob_t gl;
|
||||||
char buf[160];
|
|
||||||
|
if (rescue) {
|
||||||
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
glob("/run/sysctl.d/*.conf", 0, NULL, &gl);
|
glob("/run/sysctl.d/*.conf", 0, NULL, &gl);
|
||||||
glob("/etc/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
glob("/etc/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||||
@@ -39,9 +49,13 @@ static void setup(void *arg)
|
|||||||
glob("/mnt/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
glob("/mnt/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||||
glob("/etc/sysctl.conf", GLOB_APPEND, NULL, &gl);
|
glob("/etc/sysctl.conf", GLOB_APPEND, NULL, &gl);
|
||||||
if (gl.gl_pathc > 0) {
|
if (gl.gl_pathc > 0) {
|
||||||
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < gl.gl_pathc; i++) {
|
for (i = 0; i < gl.gl_pathc; i++) {
|
||||||
snprintf(buf, sizeof(buf), "/sbin/sysctl -e -p %s >/dev/null", gl.gl_pathv[i]);
|
char cmd[160];
|
||||||
run(buf);
|
|
||||||
|
snprintf(cmd, sizeof(cmd), "/sbin/sysctl -e -p %s >/dev/null", gl.gl_pathv[i]);
|
||||||
|
run(cmd, "sysctl");
|
||||||
}
|
}
|
||||||
globfree(&gl);
|
globfree(&gl);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* Setup necessary files for resolvconf
|
/* Setup necessary files for resolvconf
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -21,7 +21,11 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
@@ -33,7 +37,7 @@
|
|||||||
*/
|
*/
|
||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
{
|
{
|
||||||
_d("Setting up the resolver ...");
|
dbg("Setting up the resolver ...");
|
||||||
mkpath("/etc/resolvconf", 0755);
|
mkpath("/etc/resolvconf", 0755);
|
||||||
mkpath("/etc/resolvconf/run", 0755);
|
mkpath("/etc/resolvconf/run", 0755);
|
||||||
mkpath("/var/run/resolvconf", 0755);
|
mkpath("/var/run/resolvconf", 0755);
|
||||||
@@ -41,7 +45,7 @@ static void setup(void *arg)
|
|||||||
|
|
||||||
touch("/etc/resolvconf/run/enable-updates");
|
touch("/etc/resolvconf/run/enable-updates");
|
||||||
chdir("/etc/resolvconf/run/interface");
|
chdir("/etc/resolvconf/run/interface");
|
||||||
run_parts("/etc/resolvconf/update.d", "-i");
|
run_parts("/etc/resolvconf/update.d", "-i", NULL, 0);
|
||||||
chdir("/");
|
chdir("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+51
-10
@@ -1,6 +1,6 @@
|
|||||||
/* Save and restore RTC using hwclock
|
/* Save and restore RTC using hwclock
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -21,17 +21,29 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <linux/rtc.h>
|
#include <linux/rtc.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
|
||||||
/* Kernel RTC driver validates against this date for sanity check */
|
/* Kernel RTC driver validates against this date for sanity check */
|
||||||
#define RTC_TIMESTAMP_BEGIN_2000 946684800LL /* 2000-01-01 00:00:00 */
|
#define RTC_TIMESTAMP_BEGIN_2000 "2000-01-01 00:00:00"
|
||||||
|
#ifdef RTC_TIMESTAMP_CUSTOM
|
||||||
|
static char *rtc_timestamp = RTC_TIMESTAMP_CUSTOM;
|
||||||
|
#else
|
||||||
|
static char *rtc_timestamp = RTC_TIMESTAMP_BEGIN_2000;
|
||||||
|
#endif
|
||||||
|
static time_t rtc_date_fallback = 946684800LL;
|
||||||
|
|
||||||
static void tz_set(char *tz, size_t len)
|
static void tz_set(char *tz, size_t len)
|
||||||
{
|
{
|
||||||
@@ -84,16 +96,21 @@ static void rtc_save(void *arg)
|
|||||||
int fd, rc = 0;
|
int fd, rc = 0;
|
||||||
char tz[128];
|
char tz[128];
|
||||||
|
|
||||||
|
if (rescue) {
|
||||||
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
fd = rtc_open();
|
fd = rtc_open();
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
tz_set(tz, sizeof(tz));
|
tz_set(tz, sizeof(tz));
|
||||||
rc = gettimeofday(&tv, NULL);
|
rc = gettimeofday(&tv, NULL);
|
||||||
if (rc < 0 || tv.tv_sec < RTC_TIMESTAMP_BEGIN_2000) {
|
if (rc < 0 || tv.tv_sec < rtc_date_fallback) {
|
||||||
print_desc(NULL, "System clock invalid, not saving to RTC");
|
print_desc(NULL, "System clock invalid, not saving to RTC");
|
||||||
invalid:
|
invalid:
|
||||||
logit(LOG_ERR, "System clock invalid, before 2000-01-01 00:00, not saving to RTC");
|
logit(LOG_ERR, "System clock invalid, before %s, not saving to RTC", rtc_timestamp);
|
||||||
rc = 2;
|
rc = 2;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -121,9 +138,16 @@ static void rtc_restore(void *arg)
|
|||||||
int fd, rc = 0;
|
int fd, rc = 0;
|
||||||
char tz[128];
|
char tz[128];
|
||||||
|
|
||||||
fd = rtc_open();
|
if (rescue) {
|
||||||
if (fd < 0)
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = rtc_open();
|
||||||
|
if (fd < 0) {
|
||||||
|
logit(LOG_NOTICE, "System has no RTC (missing driver?), skipping restore.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
tz_set(tz, sizeof(tz));
|
tz_set(tz, sizeof(tz));
|
||||||
if (ioctl(fd, RTC_RD_TIME, &tm) < 0) {
|
if (ioctl(fd, RTC_RD_TIME, &tm) < 0) {
|
||||||
@@ -137,19 +161,29 @@ static void rtc_restore(void *arg)
|
|||||||
invalid:
|
invalid:
|
||||||
logit(LOG_ERR, "Failed restoring system clock from RTC.");
|
logit(LOG_ERR, "Failed restoring system clock from RTC.");
|
||||||
if (EINVAL == errno)
|
if (EINVAL == errno)
|
||||||
logit(LOG_ERR, "RTC time is too old (before 2000-01-01 00:00)");
|
logit(LOG_ERR, "RTC time is too old (before %s)", rtc_timestamp);
|
||||||
else if (ENOENT == errno)
|
else if (ENOENT == errno)
|
||||||
logit(LOG_ERR, "RTC has no previously saved (valid) time.");
|
logit(LOG_ERR, "RTC has no previously saved (valid) time.");
|
||||||
else
|
else
|
||||||
logit(LOG_ERR, "RTC error code %d: %s", errno, strerror(errno));
|
logit(LOG_ERR, "RTC error code %d: %s", errno, strerror(errno));
|
||||||
|
|
||||||
|
/* Been here already? */
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* Attempt to set RTC to a sane value ... */
|
||||||
|
tv.tv_sec = rtc_date_fallback;
|
||||||
|
if (!gmtime_r(&tv.tv_sec, &tm))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
logit(LOG_NOTICE, "Resetting RTC to kernel default, %s.", rtc_timestamp);
|
||||||
rc = 2;
|
rc = 2;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
print_desc(NULL, "Restoring system clock (UTC) from RTC");
|
print_desc(NULL, "Restoring system clock (UTC) from RTC");
|
||||||
tm.tm_isdst = -1; /* Use tzdata to figure it out, please. */
|
tm.tm_isdst = -1; /* Use tzdata to figure it out, please. */
|
||||||
tv.tv_sec = mktime(&tm);
|
tv.tv_sec = mktime(&tm);
|
||||||
if (tv.tv_sec < RTC_TIMESTAMP_BEGIN_2000) {
|
if (tv.tv_sec == (time_t)-1 || tv.tv_sec < rtc_date_fallback) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
goto invalid;
|
goto invalid;
|
||||||
}
|
}
|
||||||
@@ -175,6 +209,13 @@ static plugin_t plugin = {
|
|||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
{
|
{
|
||||||
|
struct tm tm = { 0 };
|
||||||
|
|
||||||
|
if (!strptime(rtc_timestamp, "%Y-%m-%d %H:%M", &tm))
|
||||||
|
rtc_date_fallback = mktime(&tm);
|
||||||
|
else
|
||||||
|
rtc_timestamp = RTC_TIMESTAMP_BEGIN_2000;
|
||||||
|
|
||||||
plugin_register(&plugin);
|
plugin_register(&plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+213
@@ -0,0 +1,213 @@
|
|||||||
|
/* System condition event monitor for the Finit condition engine
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <fnmatch.h>
|
||||||
|
#include <glob.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <paths.h>
|
||||||
|
|
||||||
|
#include "finit.h"
|
||||||
|
#include "cond.h"
|
||||||
|
#include "pid.h"
|
||||||
|
#include "plugin.h"
|
||||||
|
#include "iwatch.h"
|
||||||
|
|
||||||
|
static struct iwatch iw_sys;
|
||||||
|
|
||||||
|
|
||||||
|
static int sys_add_path(struct iwatch *iw, char *path)
|
||||||
|
{
|
||||||
|
return iwatch_add(iw, path, IN_ONLYDIR | IN_CLOSE_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* unlink conditions with no active task/service, otherwise they may
|
||||||
|
* trigger inadvertently when calling `initctl reload` to activate
|
||||||
|
* a new configuration.
|
||||||
|
*/
|
||||||
|
static void sys_update_conds(char *dir, char *name, uint32_t mask)
|
||||||
|
{
|
||||||
|
char path[256];
|
||||||
|
char *cond;
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
ptr = strrchr(name, '/');
|
||||||
|
if (ptr)
|
||||||
|
snprintf(path, sizeof(path), "%s/%s", dir, ++ptr);
|
||||||
|
else
|
||||||
|
snprintf(path, sizeof(path), "%s/%s", dir, name);
|
||||||
|
|
||||||
|
cond = strstr(path, COND_BASE);
|
||||||
|
if (!cond)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cond += strlen(COND_BASE) + 1;
|
||||||
|
dbg("cond: %s set: %d", cond, (mask & IN_CREATE) ? 1 : 0);
|
||||||
|
if (!cond_update(cond))
|
||||||
|
unlink(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* synthesize events in case of new run dirs */
|
||||||
|
static void sys_scandir(struct iwatch *iw, char *dir, int len)
|
||||||
|
{
|
||||||
|
glob_t gl;
|
||||||
|
size_t i;
|
||||||
|
char path[len + 6];
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "%s/*", dir);
|
||||||
|
rc = glob(path, GLOB_NOSORT, NULL, &gl);
|
||||||
|
if (rc && rc != GLOB_NOMATCH)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < gl.gl_pathc; i++) {
|
||||||
|
dbg("scan found %s", gl.gl_pathv[i]);
|
||||||
|
sys_update_conds(dir, gl.gl_pathv[i], IN_CREATE);
|
||||||
|
}
|
||||||
|
globfree(&gl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* create/remove sub-directory in monitored directory
|
||||||
|
*/
|
||||||
|
static void sys_handle_dir(struct iwatch *iw, char *dir, char *name, int mask)
|
||||||
|
{
|
||||||
|
char path[strlen(dir) + strlen(name) + 2];
|
||||||
|
struct iwatch_path *iwp;
|
||||||
|
|
||||||
|
paste(path, sizeof(path), dir, name);
|
||||||
|
dbg("path: %s", path);
|
||||||
|
|
||||||
|
iwp = iwatch_find_by_path(iw, path);
|
||||||
|
|
||||||
|
if (mask & IN_CREATE) {
|
||||||
|
if (!iwp) {
|
||||||
|
if (!sys_add_path(iw, path))
|
||||||
|
sys_scandir(iw, path, sizeof(path));
|
||||||
|
}
|
||||||
|
} else if (mask & IN_DELETE) {
|
||||||
|
if (iwp)
|
||||||
|
iwatch_del(&iw_sys, iwp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sys_callback(void *arg, int fd, int events)
|
||||||
|
{
|
||||||
|
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
||||||
|
struct inotify_event *ev;
|
||||||
|
ssize_t sz;
|
||||||
|
size_t off;
|
||||||
|
|
||||||
|
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
||||||
|
if (sz <= 0) {
|
||||||
|
err(1, "invalid inotify event");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ev_buf[sz] = 0;
|
||||||
|
|
||||||
|
for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) {
|
||||||
|
struct iwatch_path *iwp;
|
||||||
|
|
||||||
|
if (off + sizeof(*ev) > (size_t)sz)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ev = (struct inotify_event *)&ev_buf[off];
|
||||||
|
if (off + sizeof(*ev) + ev->len > (size_t)sz)
|
||||||
|
break;
|
||||||
|
|
||||||
|
dbg("name %s, event: 0x%08x", ev->name, ev->mask);
|
||||||
|
if (!ev->mask)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Find base path for this event */
|
||||||
|
iwp = iwatch_find_by_wd(&iw_sys, ev->wd);
|
||||||
|
if (!iwp)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ev->mask & IN_ISDIR) {
|
||||||
|
sys_handle_dir(&iw_sys, iwp->path, ev->name, ev->mask);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ev->mask & (IN_CREATE | IN_DELETE))
|
||||||
|
sys_update_conds(iwp->path, ev->name, ev->mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sys_init(void *arg)
|
||||||
|
{
|
||||||
|
char sysdir[MAX_ARG_LEN];
|
||||||
|
char *path;
|
||||||
|
|
||||||
|
mkpath(_PATH_COND, 0755);
|
||||||
|
if (mkpath(pid_runpath(_PATH_CONDSYS, sysdir, sizeof(sysdir)), 0755) && errno != EEXIST) {
|
||||||
|
err(1, "Failed creating %s condition directory, %s", COND_SYS, _PATH_CONDSYS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
path = realpath(_PATH_CONDSYS, NULL);
|
||||||
|
if (!path) {
|
||||||
|
err(1, "Cannot figure out real path to %s, aborting", _PATH_CONDSYS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iwatch_add(&iw_sys, path, IN_ONLYDIR))
|
||||||
|
iwatch_exit(&iw_sys);
|
||||||
|
|
||||||
|
free(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static plugin_t plugin = {
|
||||||
|
.name = __FILE__,
|
||||||
|
.hook[HOOK_BASEFS_UP] = { .cb = sys_init },
|
||||||
|
.depends = { "bootmisc", },
|
||||||
|
};
|
||||||
|
|
||||||
|
PLUGIN_INIT(plugin_init)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = iwatch_init(&iw_sys);
|
||||||
|
if (fd < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
plugin.io.fd = fd;
|
||||||
|
plugin.io.cb = sys_callback;
|
||||||
|
plugin.io.flags = PLUGIN_IO_READ;
|
||||||
|
|
||||||
|
plugin_register(&plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
PLUGIN_EXIT(plugin_exit)
|
||||||
|
{
|
||||||
|
plugin_unregister(&plugin);
|
||||||
|
iwatch_exit(&iw_sys);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Variables:
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
+26
-17
@@ -1,7 +1,7 @@
|
|||||||
/* Optional TTY Watcher, used to catch new TTYs that are discovered, e.g., USB
|
/* Optional TTY Watcher, used to catch new TTYs that are discovered, e.g., USB
|
||||||
*
|
*
|
||||||
* Copyright (c) 2013 Mattias Walström <lazzer@gmail.com>
|
* Copyright (c) 2013 Mattias Walström <lazzer@gmail.com>
|
||||||
* Copyright (c) 2013-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2013-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -27,18 +27,23 @@
|
|||||||
#include <unistd.h> /* read() */
|
#include <unistd.h> /* read() */
|
||||||
#include <sys/inotify.h>
|
#include <sys/inotify.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
#include "service.h"
|
||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
|
|
||||||
static void watcher(void *arg, int fd, int events);
|
static void tty_watcher(void *arg, int fd, int events);
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
.io = {
|
.io = {
|
||||||
.cb = watcher,
|
.cb = tty_watcher,
|
||||||
.flags = PLUGIN_IO_READ,
|
.flags = PLUGIN_IO_READ,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -50,25 +55,30 @@ static void setup(void)
|
|||||||
|
|
||||||
plugin.io.fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
plugin.io.fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
||||||
if (-1 == plugin.io.fd || inotify_add_watch(plugin.io.fd, "/dev", IN_CREATE | IN_DELETE) < 0)
|
if (-1 == plugin.io.fd || inotify_add_watch(plugin.io.fd, "/dev", IN_CREATE | IN_DELETE) < 0)
|
||||||
_pe("Failed starting TTY watcher");
|
err(1, "Failed starting TTY watcher");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_tty(char *tty, size_t len, int creat)
|
static void do_tty(char *tty, size_t len, int creat)
|
||||||
{
|
{
|
||||||
char name[len + 6];
|
char name[len + 6];
|
||||||
struct tty *entry;
|
svc_t *svc;
|
||||||
|
|
||||||
snprintf(name, sizeof(name), "/dev/%s", tty);
|
snprintf(name, sizeof(name), "/dev/%s", tty);
|
||||||
entry = tty_find(name);
|
svc = svc_find_by_tty(name);
|
||||||
if (entry && tty_enabled(entry)) {
|
if (svc) {
|
||||||
if (creat)
|
if (svc_is_blocked(svc) && creat) {
|
||||||
tty_start(entry);
|
dbg("%s: blocked, re-enabling", svc_ident(svc, NULL, 0));
|
||||||
else if (entry->pid)
|
svc_start(svc);
|
||||||
tty_stop(entry);
|
} else if (svc->pid) {
|
||||||
|
dbg("%s: missing ...", svc_ident(svc, NULL, 0));
|
||||||
|
svc_missing(svc);
|
||||||
|
}
|
||||||
|
|
||||||
|
service_step_all(SVC_TYPE_TTY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void watcher(void *arg, int fd, int events)
|
static void tty_watcher(void *arg, int fd, int events)
|
||||||
{
|
{
|
||||||
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
||||||
struct inotify_event *ev;
|
struct inotify_event *ev;
|
||||||
@@ -77,7 +87,7 @@ static void watcher(void *arg, int fd, int events)
|
|||||||
|
|
||||||
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
||||||
if (sz <= 0) {
|
if (sz <= 0) {
|
||||||
_pe("invalid inotify event");
|
err(1, "invalid inotify event");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ev_buf[sz] = 0;
|
ev_buf[sz] = 0;
|
||||||
@@ -93,7 +103,7 @@ static void watcher(void *arg, int fd, int events)
|
|||||||
if (!ev->mask)
|
if (!ev->mask)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_d("tty %s, event: 0x%08x", ev->name, ev->mask);
|
dbg("tty %s, event: 0x%08x", ev->name, ev->mask);
|
||||||
do_tty(ev->name, ev->len, ev->mask & IN_CREATE);
|
do_tty(ev->name, ev->len, ev->mask & IN_CREATE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -106,10 +116,9 @@ PLUGIN_INIT(plugin_init)
|
|||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(plugin_exit)
|
||||||
{
|
{
|
||||||
|
plugin_unregister(&plugin);
|
||||||
if (plugin.io.fd)
|
if (plugin.io.fd)
|
||||||
close(plugin.io.fd);
|
close(plugin.io.fd);
|
||||||
|
|
||||||
plugin_unregister(&plugin);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+83
-6
@@ -1,6 +1,6 @@
|
|||||||
/* Setup random seed
|
/* Setup and save random seed at boot/shutdown
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -22,19 +22,39 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/time.h> /* gettimeofday() */
|
#include <sys/time.h> /* gettimeofday() */
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
#include <linux/random.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
|
||||||
|
#ifndef RANDOM_BYTES
|
||||||
|
#define RANDOM_BYTES (32*1024)
|
||||||
|
#endif
|
||||||
|
|
||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
{
|
{
|
||||||
#ifdef RANDOMSEED
|
#ifdef RANDOMSEED
|
||||||
|
struct rand_pool_info *rpi;
|
||||||
|
ssize_t len = 0;
|
||||||
|
int rc = -1;
|
||||||
|
int fd, err;
|
||||||
|
|
||||||
|
if (rescue) {
|
||||||
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!fexist(RANDOMSEED)) {
|
if (!fexist(RANDOMSEED)) {
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
mode_t prev;
|
mode_t prev;
|
||||||
@@ -61,8 +81,60 @@ static void setup(void *arg)
|
|||||||
umask(prev);
|
umask(prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
print_desc("Initializing random number generator", NULL);
|
print_desc("Seeding random number generator", NULL);
|
||||||
print_result(512 != copyfile(RANDOMSEED, "/dev/urandom", 0, 0));
|
|
||||||
|
/*
|
||||||
|
* Simply copying our saved entropy to /dev/urandom doesn't
|
||||||
|
* increment the kernel "entropy count", instead we must use
|
||||||
|
* the ioctl below.
|
||||||
|
*/
|
||||||
|
fd = open(RANDOMSEED, O_RDONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
goto fallback;
|
||||||
|
|
||||||
|
rpi = malloc(sizeof(*rpi) + RANDOM_BYTES);
|
||||||
|
if (!rpi) {
|
||||||
|
close(fd);
|
||||||
|
goto fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
ssize_t num;
|
||||||
|
|
||||||
|
num = read(fd, &rpi->buf[len], RANDOM_BYTES - len);
|
||||||
|
if (num <= 0) {
|
||||||
|
if (num == -1 && errno == EINTR)
|
||||||
|
continue;
|
||||||
|
if (len > 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
free(rpi);
|
||||||
|
goto fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
len += num;
|
||||||
|
} while (len < RANDOM_BYTES);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
fd = open("/dev/urandom", O_WRONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
free(rpi);
|
||||||
|
goto fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
rpi->buf_size = len;
|
||||||
|
rpi->entropy_count = len * 8;
|
||||||
|
rc = ioctl(fd, RNDADDENTROPY, rpi);
|
||||||
|
err = errno;
|
||||||
|
close(fd);
|
||||||
|
free(rpi);
|
||||||
|
if (rc < 0)
|
||||||
|
logit(LOG_ERR, "Failed adding entropy to kernel random pool: %s", strerror(err));
|
||||||
|
print_result(rc < 0);
|
||||||
|
return;
|
||||||
|
fallback:
|
||||||
|
print_result(512 > copyfile(RANDOMSEED, "/dev/urandom", 0, 0));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,10 +143,15 @@ static void save(void *arg)
|
|||||||
#ifdef RANDOMSEED
|
#ifdef RANDOMSEED
|
||||||
mode_t prev;
|
mode_t prev;
|
||||||
|
|
||||||
|
if (rescue) {
|
||||||
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
prev = umask(077);
|
prev = umask(077);
|
||||||
|
|
||||||
print_desc("Saving random seed", NULL);
|
print_desc("Saving random seed", NULL);
|
||||||
print_result(512 != copyfile("/dev/urandom", RANDOMSEED, 512, 0));
|
print_result(RANDOM_BYTES != copyfile("/dev/urandom", RANDOMSEED, RANDOM_BYTES, 0));
|
||||||
|
|
||||||
umask(prev);
|
umask(prev);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+11
-7
@@ -1,6 +1,6 @@
|
|||||||
/* User-defined condtion event monitor for the Finit condition engine
|
/* User-defined condition event monitor for the Finit condition engine
|
||||||
*
|
*
|
||||||
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2021-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -52,7 +52,7 @@ static void usr_callback(void *arg, int fd, int events)
|
|||||||
|
|
||||||
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
||||||
if (sz <= 0) {
|
if (sz <= 0) {
|
||||||
_pe("invalid inotify event");
|
err(1, "invalid inotify event");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ev_buf[sz] = 0;
|
ev_buf[sz] = 0;
|
||||||
@@ -65,7 +65,7 @@ static void usr_callback(void *arg, int fd, int events)
|
|||||||
if (off + sizeof(*ev) + ev->len > (size_t)sz)
|
if (off + sizeof(*ev) + ev->len > (size_t)sz)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
_d("name %s, event: 0x%08x", ev->name, ev->mask);
|
dbg("name %s, event: 0x%08x", ev->name, ev->mask);
|
||||||
if (!ev->mask)
|
if (!ev->mask)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -84,24 +84,28 @@ static void usr_init(void *arg)
|
|||||||
char usrdir[MAX_ARG_LEN];
|
char usrdir[MAX_ARG_LEN];
|
||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
|
mkpath(_PATH_COND, 0755);
|
||||||
if (mkpath(pid_runpath(_PATH_CONDUSR, usrdir, sizeof(usrdir)), 0755) && errno != EEXIST) {
|
if (mkpath(pid_runpath(_PATH_CONDUSR, usrdir, sizeof(usrdir)), 0755) && errno != EEXIST) {
|
||||||
_pe("Failed creating %s condition directory, %s", COND_USR, _PATH_CONDUSR);
|
err(1, "Failed creating %s condition directory, %s", COND_USR, _PATH_CONDUSR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
path = realpath(_PATH_CONDUSR, NULL);
|
path = realpath(_PATH_CONDUSR, NULL);
|
||||||
if (!path) {
|
if (!path) {
|
||||||
_pe("Cannot figure out real path to %s, aborting", _PATH_CONDUSR);
|
err(1, "Cannot figure out real path to %s, aborting", _PATH_CONDUSR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iwatch_add(&iw_usr, path, IN_ONLYDIR))
|
if (iwatch_add(&iw_usr, path, IN_ONLYDIR))
|
||||||
iwatch_exit(&iw_usr);
|
iwatch_exit(&iw_usr);
|
||||||
|
|
||||||
|
free(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
.name = __FILE__,
|
.name = __FILE__,
|
||||||
.hook[HOOK_BASEFS_UP] = { .cb = usr_init },
|
.hook[HOOK_BASEFS_UP] = { .cb = usr_init },
|
||||||
|
.depends = { "bootmisc", },
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
@@ -121,8 +125,8 @@ PLUGIN_INIT(plugin_init)
|
|||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(plugin_exit)
|
||||||
{
|
{
|
||||||
iwatch_exit(&iw_usr);
|
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
|
iwatch_exit(&iw_usr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+12
-32
@@ -1,6 +1,6 @@
|
|||||||
/* Console setup (for X)
|
/* Console setup (for X)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2012-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -24,7 +24,11 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
@@ -32,42 +36,18 @@
|
|||||||
|
|
||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
{
|
{
|
||||||
const char *username = "nobody";
|
if (rescue) {
|
||||||
char line[LINE_SIZE];
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
mode_t prev;
|
return;
|
||||||
#ifdef PAM_CONSOLE
|
|
||||||
int fd;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
prev = umask(0);
|
|
||||||
|
|
||||||
makedir("/var/run/console", 01777);
|
|
||||||
snprintf(line, sizeof(line), "/var/run/console/%s", username);
|
|
||||||
touch(line);
|
|
||||||
|
|
||||||
#ifdef PAM_CONSOLE
|
|
||||||
if ((fd = open("/var/run/console/console.lock", O_CREAT|O_WRONLY|O_TRUNC, 0644)) >= 0) {
|
|
||||||
write(fd, username, strlen(username));
|
|
||||||
close(fd);
|
|
||||||
run("pam_console_apply");
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
makedir("/tmp/.X11-unix", 01777);
|
if (fexist("/var/run/console/console.lock") && which("pam_console_apply"))
|
||||||
makedir("/tmp/.ICE-unix", 01777);
|
run("pam_console_apply", "pam-console");
|
||||||
|
|
||||||
if (whichp("restorecon"))
|
|
||||||
run("restorecon /tmp/.ICE-unix /tmp/.X11-unix");
|
|
||||||
|
|
||||||
umask(prev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
.name = __FILE__,
|
.name = __FILE__,
|
||||||
.hook[HOOK_NETWORK_UP] = {
|
.hook[HOOK_SVC_PLUGIN] = { .cb = setup },
|
||||||
.cb = setup
|
|
||||||
},
|
|
||||||
.depends = { "bootmisc", }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
.deps/*
|
.deps/*
|
||||||
finit
|
finit
|
||||||
|
getty
|
||||||
initctl
|
initctl
|
||||||
|
keventd
|
||||||
logit
|
logit
|
||||||
reboot
|
reboot
|
||||||
|
sulogin
|
||||||
watchdogd
|
watchdogd
|
||||||
Makefile
|
Makefile
|
||||||
Makefile.in
|
Makefile.in
|
||||||
|
|||||||
+39
-19
@@ -1,4 +1,4 @@
|
|||||||
EXTRA_DIST = cgreaper.sh rescue.conf sample.conf
|
EXTRA_DIST = rescue.conf sample.conf
|
||||||
AM_CPPFLAGS = -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
|
AM_CPPFLAGS = -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
|
||||||
if STATIC
|
if STATIC
|
||||||
AM_CPPFLAGS += -DENABLE_STATIC
|
AM_CPPFLAGS += -DENABLE_STATIC
|
||||||
@@ -7,29 +7,47 @@ else
|
|||||||
AM_LDFLAGS = -export-dynamic
|
AM_LDFLAGS = -export-dynamic
|
||||||
endif
|
endif
|
||||||
|
|
||||||
sbin_PROGRAMS = finit initctl
|
sbin_PROGRAMS = finit initctl
|
||||||
pkglibexec_SCRIPTS = cgreaper.sh
|
pkglibexec_PROGRAMS = getty logit
|
||||||
|
if SULOGIN
|
||||||
|
pkglibexec_PROGRAMS += sulogin
|
||||||
|
endif
|
||||||
|
if KEVENTD
|
||||||
|
pkglibexec_PROGRAMS += keventd
|
||||||
|
endif
|
||||||
|
if WATCHDOGD
|
||||||
|
pkglibexec_PROGRAMS += watchdogd
|
||||||
|
endif
|
||||||
|
|
||||||
finit_pkglibdir = $(pkglibdir)
|
finit_pkglibdir = $(pkglibdir)
|
||||||
finit_pkglib_SCRIPTS = rescue.conf sample.conf
|
finit_pkglib_SCRIPTS = rescue.conf sample.conf
|
||||||
|
|
||||||
if WATCHDOGD
|
getty_SOURCES = finit.h getty.c helpers.h logrotate.c stty.c utmp-api.c utmp-api.h
|
||||||
pkglibexec_PROGRAMS = watchdogd
|
getty_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||||
endif
|
getty_CFLAGS += $(lite_CFLAGS)
|
||||||
|
getty_LDADD = $(lite_LIBS)
|
||||||
|
|
||||||
if LOGIT
|
keventd_SOURCES = keventd.c iwatch.c iwatch.h util.c util.h
|
||||||
pkglibexec_PROGRAMS = logit
|
keventd_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||||
logit_SOURCES = logit.c logrotate.c
|
keventd_CFLAGS += $(lite_CFLAGS)
|
||||||
logit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
keventd_LDADD = $(lite_LIBS)
|
||||||
logit_CFLAGS += $(lite_CFLAGS)
|
|
||||||
logit_LDADD = $(lite_LIBS)
|
sulogin_SOURCES = sulogin.c
|
||||||
endif
|
sulogin_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||||
|
sulogin_LDADD = -lcrypt
|
||||||
|
|
||||||
|
logit_SOURCES = logit.c logrotate.c
|
||||||
|
logit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||||
|
logit_CFLAGS += $(lite_CFLAGS)
|
||||||
|
logit_LDADD = $(lite_LIBS)
|
||||||
|
|
||||||
finit_SOURCES = api.c cgroup.c cgroup.h \
|
finit_SOURCES = api.c cgroup.c cgroup.h \
|
||||||
|
client.c client.h \
|
||||||
cond.c cond-w.c cond.h \
|
cond.c cond-w.c cond.h \
|
||||||
conf.c conf.h \
|
conf.c conf.h \
|
||||||
|
devmon.c devmon.h \
|
||||||
exec.c finit.c finit.h \
|
exec.c finit.c finit.h \
|
||||||
getty.c stty.c \
|
stty.c \
|
||||||
helpers.c helpers.h \
|
helpers.c helpers.h \
|
||||||
iwatch.c iwatch.h \
|
iwatch.c iwatch.h \
|
||||||
log.c log.h \
|
log.c log.h \
|
||||||
@@ -41,6 +59,7 @@ finit_SOURCES = api.c cgroup.c cgroup.h \
|
|||||||
sig.c sig.h \
|
sig.c sig.h \
|
||||||
sm.c sm.h \
|
sm.c sm.h \
|
||||||
svc.c svc.h \
|
svc.c svc.h \
|
||||||
|
tmpfiles.c tmpfiles.h \
|
||||||
tty.c tty.h \
|
tty.c tty.h \
|
||||||
util.c util.h \
|
util.c util.h \
|
||||||
utmp-api.c utmp-api.h
|
utmp-api.c utmp-api.h
|
||||||
@@ -48,8 +67,10 @@ if LOGROTATE
|
|||||||
finit_SOURCES += logrotate.c
|
finit_SOURCES += logrotate.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
pkginclude_HEADERS = cond.h finit.h helpers.h log.h plugin.h svc.h
|
pkginclude_HEADERS = cgroup.h cond.h conf.h finit.h helpers.h log.h \
|
||||||
|
plugin.h svc.h service.h
|
||||||
|
|
||||||
|
finit_CPPFLAGS = $(AM_CPPFLAGS) -D__FINIT__
|
||||||
finit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
finit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||||
finit_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
|
finit_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
|
||||||
finit_LDADD = $(lite_LIBS) $(uev_LIBS)
|
finit_LDADD = $(lite_LIBS) $(uev_LIBS)
|
||||||
@@ -61,10 +82,10 @@ endif
|
|||||||
|
|
||||||
initctl_SOURCES = initctl.c initctl.h cgutil.c cgutil.h \
|
initctl_SOURCES = initctl.c initctl.h cgutil.c cgutil.h \
|
||||||
client.c client.h cond.c cond.h reboot.c \
|
client.c client.h cond.c cond.h reboot.c \
|
||||||
serv.c serv.h svc.h util.c util.h
|
serv.c serv.h svc.h util.c util.h log.h
|
||||||
initctl_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
initctl_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||||
initctl_CFLAGS += $(lite_CFLAGS)
|
initctl_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
|
||||||
initctl_LDADD = $(lite_LIBS)
|
initctl_LDADD = $(lite_LIBS) $(uev_LIBS)
|
||||||
|
|
||||||
INIT_LNKS = init telinit
|
INIT_LNKS = init telinit
|
||||||
REBOOT_LNKS = reboot shutdown halt poweroff suspend
|
REBOOT_LNKS = reboot shutdown halt poweroff suspend
|
||||||
@@ -72,7 +93,6 @@ REBOOT_LNKS = reboot shutdown halt poweroff suspend
|
|||||||
if WATCHDOGD
|
if WATCHDOGD
|
||||||
watchdogd_SOURCES = watchdog.c watchdog.h
|
watchdogd_SOURCES = watchdog.c watchdog.h
|
||||||
watchdogd_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
watchdogd_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||||
#log.c log.h
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Hook in install to add finit and reboot symlink(s)
|
# Hook in install to add finit and reboot symlink(s)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* External client API, using UNIX domain socket.
|
/* External client API, using UNIX domain socket.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2015-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -21,6 +21,8 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h" /* Generated by configure script */
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -29,10 +31,13 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
#include <uev/uev.h>
|
#include <uev/uev.h>
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
@@ -40,47 +45,73 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
#include "private.h"
|
#include "private.h"
|
||||||
#include "sig.h"
|
#include "schedule.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
|
#include "sig.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
extern svc_t *wdog;
|
|
||||||
static uev_t api_watcher;
|
static uev_t api_watcher;
|
||||||
|
|
||||||
static int call(int (*action)(svc_t *), char *buf, size_t len)
|
static int call(int (*action)(svc_t *, void *), char *buf, size_t len)
|
||||||
{
|
{
|
||||||
return svc_parse_jobstr(buf, len, action, NULL);
|
return svc_parse_jobstr(buf, len, NULL, action, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int stop(svc_t *svc)
|
static int stop(svc_t *svc, void *user_data)
|
||||||
{
|
{
|
||||||
if (!svc)
|
if (!svc)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
service_timeout_cancel(svc);
|
||||||
svc_stop(svc);
|
svc_stop(svc);
|
||||||
service_step(svc);
|
service_step(svc);
|
||||||
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int start(svc_t *svc)
|
static int start(svc_t *svc, void *user_data)
|
||||||
{
|
{
|
||||||
if (!svc)
|
if (!svc)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
service_timeout_cancel(svc);
|
||||||
svc_start(svc);
|
svc_start(svc);
|
||||||
service_step(svc);
|
service_step(svc);
|
||||||
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTE: this does not wait for svc to be stopped first, that is the
|
||||||
|
* responsibility of initctl to do. Otherwise we'd block PID 1,
|
||||||
|
* or introduce some nasty race conditions.
|
||||||
|
*/
|
||||||
|
static int restart(svc_t *svc, void *user_data)
|
||||||
|
{
|
||||||
|
if (!svc)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!svc_is_running(svc))
|
||||||
|
return start(svc, user_data);
|
||||||
|
|
||||||
|
service_timeout_cancel(svc);
|
||||||
|
service_stop(svc);
|
||||||
|
service_step(svc);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int restart(svc_t *svc)
|
static int reload(svc_t *svc, void *user_data)
|
||||||
{
|
{
|
||||||
if (!svc)
|
if (!svc)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (svc_is_blocked(svc))
|
if (svc_is_blocked(svc))
|
||||||
svc_start(svc);
|
svc_start(svc);
|
||||||
|
else
|
||||||
|
service_timeout_cancel(svc);
|
||||||
|
|
||||||
svc_mark_dirty(svc);
|
svc_mark_dirty(svc);
|
||||||
service_step(svc);
|
service_step(svc);
|
||||||
@@ -88,12 +119,33 @@ static int restart(svc_t *svc)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_start (char *buf, size_t len) { return call(start, buf, len); }
|
|
||||||
static int do_stop (char *buf, size_t len) { return call(stop, buf, len); }
|
static int do_stop (char *buf, size_t len) { return call(stop, buf, len); }
|
||||||
|
static int do_start (char *buf, size_t len) { return call(start, buf, len); }
|
||||||
static int do_restart(char *buf, size_t len) { return call(restart, buf, len); }
|
static int do_restart(char *buf, size_t len) { return call(restart, buf, len); }
|
||||||
|
static int do_reload (char *buf, size_t len) { return call(reload, buf, len); }
|
||||||
|
|
||||||
|
static int do_signal_svc(svc_t *svc, void *user_data)
|
||||||
|
{
|
||||||
|
int signo;
|
||||||
|
|
||||||
|
if (!svc || !user_data || !svc_is_running(svc))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
signo = *(int *)user_data;
|
||||||
|
return !!kill(svc->pid, signo);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_signal(char *buf, size_t len, int sig)
|
||||||
|
{
|
||||||
|
/* Sanity check: do we know this signal? */
|
||||||
|
if (!*sig2str(sig))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return svc_parse_jobstr(buf, len, &sig, do_signal_svc, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static char query_buf[368];
|
static char query_buf[368];
|
||||||
static int missing(char *job, char *id)
|
static int missing(char *job, char *id, void *user_data)
|
||||||
{
|
{
|
||||||
char buf[20];
|
char buf[20];
|
||||||
|
|
||||||
@@ -110,8 +162,8 @@ static int missing(char *job, char *id)
|
|||||||
|
|
||||||
static int do_query(char *buf, size_t len)
|
static int do_query(char *buf, size_t len)
|
||||||
{
|
{
|
||||||
memset(query_buf, 0, sizeof(query_buf));
|
query_buf[0] = 0;
|
||||||
if (svc_parse_jobstr(buf, len, NULL, missing)) {
|
if (svc_parse_jobstr(buf, len, NULL, NULL, missing)) {
|
||||||
memcpy(buf, query_buf, len);
|
memcpy(buf, query_buf, len);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -155,70 +207,93 @@ static svc_t *do_find(char *buf, size_t len)
|
|||||||
if (!id)
|
if (!id)
|
||||||
return svc_named_iterator(&iter, 1, input);
|
return svc_named_iterator(&iter, 1, input);
|
||||||
|
|
||||||
return svc_find_by_nameid(input, id);
|
return svc_find(input, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static svc_t *do_find_byc(char *buf, size_t len)
|
static svc_t *do_find_byc(char *buf, size_t len)
|
||||||
{
|
{
|
||||||
svc_t *svc, *iter = NULL;
|
|
||||||
char *input;
|
char *input;
|
||||||
|
|
||||||
input = sanitize(buf, len);
|
input = sanitize(buf, len);
|
||||||
if (!input) {
|
if (!input) {
|
||||||
_d("Invalid input");
|
dbg("Invalid input");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
return svc_find_by_cond(input);
|
||||||
char cond[MAX_COND_LEN];
|
|
||||||
|
|
||||||
mkcond(svc, cond, sizeof(cond));
|
|
||||||
_d("Comparing input %s with cond %s", input, cond);
|
|
||||||
if (string_compare(cond, input))
|
|
||||||
return svc;
|
|
||||||
}
|
|
||||||
|
|
||||||
_d("None found");
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_reboot(int cmd, char *buf, size_t len)
|
static void bypass_shutdown(void *);
|
||||||
|
struct wq emergency = { .cb = bypass_shutdown };
|
||||||
|
|
||||||
|
static void bypass_shutdown(void *unused)
|
||||||
|
{
|
||||||
|
cprintf("TIMEOUT TIMEOUT SHUTTING DOWN NOW!!\n");
|
||||||
|
do_shutdown(halt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_reboot(int cmd, int timeout, char *buf, size_t len)
|
||||||
{
|
{
|
||||||
int rc = 1;
|
int rc = 1;
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case INIT_CMD_REBOOT:
|
case INIT_CMD_REBOOT:
|
||||||
_d("reboot");
|
halt = SHUT_REBOOT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INIT_CMD_HALT:
|
||||||
|
halt = SHUT_HALT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INIT_CMD_POWEROFF:
|
||||||
|
halt = SHUT_OFF;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INIT_CMD_SUSPEND:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout > 0) {
|
||||||
|
emergency.delay = timeout * 1000;
|
||||||
|
schedule_work(&emergency);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case INIT_CMD_REBOOT:
|
||||||
|
dbg("reboot");
|
||||||
halt = SHUT_REBOOT;
|
halt = SHUT_REBOOT;
|
||||||
service_runlevel(6);
|
service_runlevel(6);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_HALT:
|
case INIT_CMD_HALT:
|
||||||
_d("halt");
|
dbg("halt");
|
||||||
halt = SHUT_HALT;
|
halt = SHUT_HALT;
|
||||||
service_runlevel(0);
|
service_runlevel(0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_POWEROFF:
|
case INIT_CMD_POWEROFF:
|
||||||
_d("poweroff");
|
dbg("poweroff");
|
||||||
halt = SHUT_OFF;
|
halt = SHUT_OFF;
|
||||||
service_runlevel(0);
|
service_runlevel(0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_SUSPEND:
|
case INIT_CMD_SUSPEND:
|
||||||
_d("suspend");
|
dbg("suspend");
|
||||||
sync();
|
sync();
|
||||||
rc = reboot(RB_SW_SUSPEND);
|
rc = suspend();
|
||||||
if (rc) {
|
if (rc) {
|
||||||
if (errno == EINVAL)
|
if (errno == EINVAL)
|
||||||
snprintf(buf, len, "Kernel does not support suspend.");
|
snprintf(buf, len, "Kernel does not support suspend to RAM.");
|
||||||
else
|
else
|
||||||
snprintf(buf, len, "Failed: %s", strerror(errno));
|
snprintf(buf, len, "Failed: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
rc = 255;
|
/* Handled previously */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,19 +322,19 @@ static void send_svc(int sd, svc_t *svc)
|
|||||||
|
|
||||||
len = write(sd, svc, sizeof(*svc));
|
len = write(sd, svc, sizeof(*svc));
|
||||||
if (len != sizeof(*svc))
|
if (len != sizeof(*svc))
|
||||||
_d("Failed sending svc_t to client");
|
dbg("Failed sending svc_t to client");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void api_cb(uev_t *w, void *arg, int events)
|
static void api_cb(uev_t *w, void *arg, int events)
|
||||||
{
|
{
|
||||||
int sd, lvl;
|
|
||||||
svc_t *svc;
|
|
||||||
static svc_t *iter = NULL;
|
static svc_t *iter = NULL;
|
||||||
struct init_request rq;
|
struct init_request rq;
|
||||||
|
int sd, lvl;
|
||||||
|
svc_t *svc;
|
||||||
|
|
||||||
sd = accept(w->fd, NULL, NULL);
|
sd = accept(w->fd, NULL, NULL);
|
||||||
if (sd < 0) {
|
if (sd < 0) {
|
||||||
_pe("Failed serving API request");
|
err(1, "Failed serving API request");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,14 +351,37 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
if (EAGAIN == errno)
|
if (EAGAIN == errno)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
_e("Failed reading initctl request, error %d: %s", errno, strerror(errno));
|
/* we get here when client restarts itself */
|
||||||
|
if (ECONNRESET == errno)
|
||||||
|
break;
|
||||||
|
|
||||||
|
errx(1, "Failed reading initctl request, error %d: %s", errno, strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rq.magic != INIT_MAGIC || len != sizeof(rq)) {
|
if (rq.magic != INIT_MAGIC || len != sizeof(rq)) {
|
||||||
_e("Invalid initctl request");
|
errx(1, "Invalid initctl request");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (rq.cmd) {
|
||||||
|
case INIT_CMD_RUNLVL:
|
||||||
|
case INIT_CMD_RELOAD:
|
||||||
|
case INIT_CMD_START_SVC:
|
||||||
|
case INIT_CMD_RESTART_SVC:
|
||||||
|
case INIT_CMD_STOP_SVC:
|
||||||
|
case INIT_CMD_RELOAD_SVC:
|
||||||
|
case INIT_CMD_REBOOT:
|
||||||
|
case INIT_CMD_HALT:
|
||||||
|
case INIT_CMD_POWEROFF:
|
||||||
|
case INIT_CMD_SUSPEND:
|
||||||
|
if (IS_RESERVED_RUNLEVEL(runlevel)) {
|
||||||
|
warnx("Unsupported command in runlevel S and 6.");
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,7 +394,7 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
|
|
||||||
case '0'...'9':
|
case '0'...'9':
|
||||||
_d("Setting new runlevel %c", rq.runlevel);
|
dbg("Setting new runlevel %c", rq.runlevel);
|
||||||
lvl = rq.runlevel - '0';
|
lvl = rq.runlevel - '0';
|
||||||
if (lvl == 0)
|
if (lvl == 0)
|
||||||
halt = SHUT_OFF;
|
halt = SHUT_OFF;
|
||||||
@@ -306,41 +404,55 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_d("Unsupported runlevel: %d", rq.runlevel);
|
dbg("Unsupported runlevel: %d", rq.runlevel);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_DEBUG:
|
case INIT_CMD_DEBUG:
|
||||||
_d("debug");
|
dbg("debug");
|
||||||
log_debug();
|
log_debug();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_RELOAD: /* 'init q' and 'initctl reload' */
|
case INIT_CMD_RELOAD: /* 'init q' and 'initctl reload' */
|
||||||
_d("reload");
|
dbg("reload");
|
||||||
service_reload_dynamic();
|
service_reload_dynamic();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_START_SVC:
|
case INIT_CMD_START_SVC:
|
||||||
_d("start %s", rq.data);
|
dbg("start %s", rq.data);
|
||||||
strterm(rq.data, sizeof(rq.data));
|
strterm(rq.data, sizeof(rq.data));
|
||||||
result = do_start(rq.data, sizeof(rq.data));
|
result = do_start(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_STOP_SVC:
|
|
||||||
_d("stop %s", rq.data);
|
|
||||||
strterm(rq.data, sizeof(rq.data));
|
|
||||||
result = do_stop(rq.data, sizeof(rq.data));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case INIT_CMD_RESTART_SVC:
|
case INIT_CMD_RESTART_SVC:
|
||||||
_d("restart %s", rq.data);
|
dbg("restart %s", rq.data);
|
||||||
strterm(rq.data, sizeof(rq.data));
|
strterm(rq.data, sizeof(rq.data));
|
||||||
result = do_restart(rq.data, sizeof(rq.data));
|
result = do_restart(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case INIT_CMD_STOP_SVC:
|
||||||
|
dbg("stop %s", rq.data);
|
||||||
|
strterm(rq.data, sizeof(rq.data));
|
||||||
|
result = do_stop(rq.data, sizeof(rq.data));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INIT_CMD_RELOAD_SVC:
|
||||||
|
dbg("reload %s", rq.data);
|
||||||
|
strterm(rq.data, sizeof(rq.data));
|
||||||
|
result = do_reload(rq.data, sizeof(rq.data));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INIT_CMD_GET_PLUGINS:
|
||||||
|
result = plugin_list(rq.data, sizeof(rq.data));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INIT_CMD_PLUGIN_DEPS:
|
||||||
|
result = plugin_deps(rq.data, sizeof(rq.data));
|
||||||
|
break;
|
||||||
|
|
||||||
case INIT_CMD_GET_RUNLEVEL:
|
case INIT_CMD_GET_RUNLEVEL:
|
||||||
_d("get runlevel");
|
dbg("get runlevel");
|
||||||
rq.runlevel = runlevel;
|
rq.runlevel = runlevel;
|
||||||
rq.sleeptime = prevlevel;
|
rq.sleeptime = prevlevel;
|
||||||
break;
|
break;
|
||||||
@@ -349,41 +461,47 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
case INIT_CMD_HALT:
|
case INIT_CMD_HALT:
|
||||||
case INIT_CMD_POWEROFF:
|
case INIT_CMD_POWEROFF:
|
||||||
case INIT_CMD_SUSPEND:
|
case INIT_CMD_SUSPEND:
|
||||||
result = do_reboot(rq.cmd, rq.data, sizeof(rq.data));
|
result = do_reboot(rq.cmd, rq.sleeptime, rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_ACK:
|
case INIT_CMD_ACK:
|
||||||
_d("Client failed reading ACK");
|
dbg("Client failed reading ACK");
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
case INIT_CMD_WDOG_HELLO:
|
case INIT_CMD_WDOG_HELLO:
|
||||||
_d("wdog hello");
|
dbg("wdog hello");
|
||||||
if (rq.runlevel <= 0) {
|
if (rq.runlevel <= 0) {
|
||||||
result = 1;
|
result = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_e("Request to hand-over wdog ... to PID %d", rq.runlevel);
|
dbg("Request to hand-over wdog ... to PID %d", rq.runlevel);
|
||||||
if (!svc_find_by_pid(rq.runlevel)) {
|
svc = svc_find_by_pid(rq.runlevel);
|
||||||
|
if (!svc) {
|
||||||
logit(LOG_ERR, "Cannot find PID %d, not registered.", rq.runlevel);
|
logit(LOG_ERR, "Cannot find PID %d, not registered.", rq.runlevel);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disable and allow Finit to collect bundled watchdog */
|
if (wdog && wdog != svc) {
|
||||||
if (wdog) {
|
char name[32];
|
||||||
logit(LOG_NOTICE, "Stopping and removing %s (PID:%d)", wdog->cmd, wdog->pid);
|
|
||||||
stop(wdog);
|
svc_ident(svc, name, sizeof(name));
|
||||||
|
logit(LOG_NOTICE, "Handing over wdog ctrl from %s[%d] to %s[%d]",
|
||||||
|
svc_ident(wdog, NULL, 0), wdog->pid, name, svc->pid);
|
||||||
|
|
||||||
if (wdog->protect) {
|
if (wdog->protect) {
|
||||||
wdog->protect = 0;
|
logit(LOG_NOTICE, "Stopping and deleting built-in watchdog.");
|
||||||
wdog->runlevels = 0;
|
stop(wdog, NULL);
|
||||||
|
svc_del(wdog);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
wdog = svc;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_SVC_ITER:
|
case INIT_CMD_SVC_ITER:
|
||||||
// _d("svc iter, first: %d", rq.runlevel);
|
// dbg("svc iter, first: %d", rq.runlevel);
|
||||||
/*
|
/*
|
||||||
* XXX: This severly limits the number of
|
* XXX: This severely limits the number of
|
||||||
* simultaneous client connections, but will
|
* simultaneous client connections, but will
|
||||||
* have to do for now.
|
* have to do for now.
|
||||||
*/
|
*/
|
||||||
@@ -392,25 +510,46 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
case INIT_CMD_SVC_QUERY:
|
case INIT_CMD_SVC_QUERY:
|
||||||
_d("svc query: %s", rq.data);
|
dbg("svc query: %s", rq.data);
|
||||||
strterm(rq.data, sizeof(rq.data));
|
strterm(rq.data, sizeof(rq.data));
|
||||||
result = do_query(rq.data, sizeof(rq.data));
|
result = do_query(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_SVC_FIND:
|
case INIT_CMD_SVC_FIND:
|
||||||
_d("svc find: %s", rq.data);
|
dbg("svc find: %s", rq.data);
|
||||||
strterm(rq.data, sizeof(rq.data));
|
strterm(rq.data, sizeof(rq.data));
|
||||||
send_svc(sd, do_find(rq.data, sizeof(rq.data)));
|
send_svc(sd, do_find(rq.data, sizeof(rq.data)));
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
case INIT_CMD_SVC_FIND_BYC:
|
case INIT_CMD_SVC_FIND_BYC:
|
||||||
_d("svc find by cond: %s", rq.data);
|
dbg("svc find by cond: %s", rq.data);
|
||||||
strterm(rq.data, sizeof(rq.data));
|
strterm(rq.data, sizeof(rq.data));
|
||||||
send_svc(sd, do_find_byc(rq.data, sizeof(rq.data)));
|
send_svc(sd, do_find_byc(rq.data, sizeof(rq.data)));
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
|
case INIT_CMD_SIGNAL:
|
||||||
|
/* runlevel is reused for signal */
|
||||||
|
dbg("svc signal %d: %s", rq.runlevel, rq.data);
|
||||||
|
strterm(rq.data, sizeof(rq.data));
|
||||||
|
result = do_signal(rq.data, sizeof(rq.data), rq.runlevel);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INIT_CMD_NOTIFY_SOCKET:
|
||||||
|
svc = svc_find_by_pid(rq.runlevel);
|
||||||
|
if (!svc) {
|
||||||
|
errx(1, "Unknown PID, cannot register notify socket");
|
||||||
|
result = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uev_io_init(ctx, &svc->notify_watcher, service_notify_cb, svc, sd, UEV_READ)) {
|
||||||
|
err(1, "Falied initializing %s readiness notifier", svc_ident(svc, NULL, 0));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return; /* Don't close sd, used for notify */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_d("Unsupported cmd: %d", rq.cmd);
|
dbg("Unsupported cmd: %d", rq.cmd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,7 +559,7 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
rq.cmd = INIT_CMD_ACK;
|
rq.cmd = INIT_CMD_ACK;
|
||||||
len = write(sd, &rq, sizeof(rq));
|
len = write(sd, &rq, sizeof(rq));
|
||||||
if (len != sizeof(rq))
|
if (len != sizeof(rq))
|
||||||
_d("Failed sending ACK/NACK back to client");
|
dbg("Failed sending ACK/NACK back to client");
|
||||||
}
|
}
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
@@ -431,39 +570,46 @@ leave:
|
|||||||
error:
|
error:
|
||||||
api_exit();
|
api_exit();
|
||||||
if (api_init(w->ctx))
|
if (api_init(w->ctx))
|
||||||
_e("Unrecoverable error on API socket");
|
errx(1, "Unrecoverable error on API socket");
|
||||||
}
|
}
|
||||||
|
|
||||||
int api_init(uev_ctx_t *ctx)
|
int api_init(uev_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
int sd;
|
|
||||||
mode_t oldmask;
|
|
||||||
struct sockaddr_un sun = {
|
struct sockaddr_un sun = {
|
||||||
.sun_family = AF_UNIX,
|
.sun_family = AF_UNIX,
|
||||||
.sun_path = INIT_SOCKET,
|
.sun_path = INIT_SOCKET,
|
||||||
};
|
};
|
||||||
|
mode_t oldmask;
|
||||||
|
int uid, gid;
|
||||||
|
int sd;
|
||||||
|
|
||||||
_d("Setting up external API socket ...");
|
dbg("Setting up external API socket ...");
|
||||||
sd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
sd = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
|
||||||
if (-1 == sd) {
|
if (-1 == sd) {
|
||||||
_pe("Failed starting external API socket");
|
err(1, "Failed starting external API socket");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uid = geteuid();
|
||||||
|
gid = getgroup(DEFGROUP);
|
||||||
|
|
||||||
erase(INIT_SOCKET);
|
erase(INIT_SOCKET);
|
||||||
oldmask = umask(0077);
|
oldmask = umask(0117);
|
||||||
if (-1 == bind(sd, (struct sockaddr*)&sun, sizeof(sun)))
|
if (-1 == bind(sd, (struct sockaddr*)&sun, sizeof(sun)))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (-1 == listen(sd, 10))
|
if (-1 == listen(sd, 10))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
if (chown(INIT_SOCKET, uid, gid))
|
||||||
|
err(1, "Failed setting group %s on %s", DEFGROUP, INIT_SOCKET);
|
||||||
|
|
||||||
umask(oldmask);
|
umask(oldmask);
|
||||||
if (!uev_io_init(ctx, &api_watcher, api_cb, NULL, sd, UEV_READ))
|
if (!uev_io_init(ctx, &api_watcher, api_cb, NULL, sd, UEV_READ))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
_pe("Failed intializing API socket");
|
err(1, "Failed initializing API socket");
|
||||||
umask(oldmask);
|
umask(oldmask);
|
||||||
close(sd);
|
close(sd);
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
# Called by kernel when last child in cgroup exists
|
|
||||||
|
|
||||||
BASE=/sys/fs/cgroup/finit
|
|
||||||
PROC=$(basename "$1")
|
|
||||||
DIR="$BASE$1"
|
|
||||||
|
|
||||||
#/libexec/finit/logit -p daemon.info -t finit "$PROC stopped, cleaning up control group $DIR"
|
|
||||||
rmdir "$DIR"
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
+467
-128
@@ -1,6 +1,6 @@
|
|||||||
/* Finit control group support functions
|
/* Finit control group support functions
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2019-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -24,178 +24,517 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
# include <libite/queue.h> /* BSD sys/queue.h API */
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
# include <lite/queue.h> /* BSD sys/queue.h API */
|
||||||
|
#endif
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#include <sys/sysinfo.h> /* get_nprocs_conf() */
|
#include <sys/sysinfo.h> /* get_nprocs_conf() */
|
||||||
|
|
||||||
|
#include "cgroup.h"
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
|
#include "iwatch.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
static char controllers[256] = "none";
|
struct cg {
|
||||||
|
TAILQ_ENTRY(cg) link;
|
||||||
|
|
||||||
static void group_init(char *path, char *nproc, int share)
|
char *name; /* top-level group name */
|
||||||
|
char *cfg; /* kernel settings */
|
||||||
|
|
||||||
|
int active; /* for mark & sweep */
|
||||||
|
int is_protected; /* for init/, user/, & system/ */
|
||||||
|
};
|
||||||
|
|
||||||
|
static TAILQ_HEAD(, cg) cgroups = TAILQ_HEAD_INITIALIZER(cgroups);
|
||||||
|
|
||||||
|
static char controllers[256];
|
||||||
|
|
||||||
|
static struct iwatch iw_cgroup;
|
||||||
|
static uev_t cgw;
|
||||||
|
static int avail;
|
||||||
|
|
||||||
|
|
||||||
|
static void cgset(const char *path, char *ctrl, char *prop)
|
||||||
{
|
{
|
||||||
char file[strlen(path) + 64];
|
char *val;
|
||||||
|
|
||||||
paste(file, sizeof(file), path, "cgroup.clone_children");
|
dbg("path %s, ctrl %s, prop %s", path ?: "NIL", ctrl ?: "NIL", prop ?: "NIL");
|
||||||
echo(file, 0, "1");
|
if (!path || !ctrl) {
|
||||||
|
errx(1, "Missing path or controller, skipping!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
paste(file, sizeof(file), path, "cpuset.cpus");
|
if (!prop) {
|
||||||
echo(file, 0, nproc);
|
prop = strchr(ctrl, '.');
|
||||||
|
if (!prop) {
|
||||||
|
errx(1, "Invalid cgroup ctrl syntax: %s", ctrl);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
paste(file, sizeof(file), path, "cpuset.mems");
|
*prop++ = 0;
|
||||||
echo(file, 0, "0");
|
}
|
||||||
|
|
||||||
paste(file, sizeof(file), path, "cpu.shares");
|
val = strchr(prop, ':');
|
||||||
echo(file, 0, "%d", share);
|
if (!val) {
|
||||||
|
errx(1, "Missing cgroup ctrl value, prop %s", prop);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*val++ = 0;
|
||||||
|
|
||||||
paste(file, sizeof(file), path, "memory.use_hierarchy");
|
/* disallow sneaky relative paths */
|
||||||
echo(file, 0, "1");
|
if (strstr(ctrl, "..") || strstr(prop, "..")) {
|
||||||
|
errx(1, "Possible security violation; '..' not allowed in cgroup config!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg("%s/%s.%s <= %s", path, ctrl, prop, val);
|
||||||
|
if (fnwrite(val, "%s/%s.%s", path, ctrl, prop))
|
||||||
|
err(1, "Failed setting %s/%s.%s = %s", path, ctrl, prop, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Settings for a cgroup are on the form: cpu.weight:1234,mem.max:4321,...
|
||||||
|
* Finit supports the short-form 'mem.', replacing it with 'memory.' when
|
||||||
|
* writing the setting to the file system.
|
||||||
|
*/
|
||||||
|
static void group_init(char *path, int leaf, const char *cfg)
|
||||||
|
{
|
||||||
|
char *ptr, *s;
|
||||||
|
|
||||||
|
dbg("path %s, leaf %d, cfg %s", path, leaf, cfg ?: "NIL");
|
||||||
|
if (!fisdir(path)) {
|
||||||
|
if (mkdir(path, 0755)) {
|
||||||
|
err(1, "Failed creating cgroup %s", path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* enable detected controllers on domain groups */
|
||||||
|
if (!leaf && fnwrite(controllers, "%s/cgroup.subtree_control", path))
|
||||||
|
err(1, "Failed enabling %s for %s", controllers, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cfg || !cfg[0])
|
||||||
|
return;
|
||||||
|
|
||||||
|
s = strdupa(cfg);
|
||||||
|
if (!s) {
|
||||||
|
err(1, "Failed activating cgroup cfg for %s", path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg("%s <=> %s", path, s);
|
||||||
|
ptr = strtok(s, ",");
|
||||||
|
while (ptr) {
|
||||||
|
dbg("ptr: %s", ptr);
|
||||||
|
if (!strncmp("mem.", ptr, 4))
|
||||||
|
cgset(path, "memory", &ptr[4]);
|
||||||
|
else
|
||||||
|
cgset(path, ptr, NULL);
|
||||||
|
|
||||||
|
ptr = strtok(NULL, ",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cgroup_leaf_init(char *group, char *name, int pid, const char *cfg)
|
||||||
|
{
|
||||||
|
char path[256];
|
||||||
|
|
||||||
|
dbg("group %s, name %s, pid %d, cfg %s", group, name, pid, cfg ?: "NIL");
|
||||||
|
if (pid < 0 || pid == 1) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create and initialize new group */
|
||||||
|
snprintf(path, sizeof(path), "/sys/fs/cgroup/%s/%s", group, name);
|
||||||
|
group_init(path, 1, cfg);
|
||||||
|
|
||||||
|
/* move process to new group */
|
||||||
|
if (fnwrite(str("%d", pid), "%s/cgroup.procs", path))
|
||||||
|
err(1, "Failed moving pid %d to group %s", pid, path);
|
||||||
|
|
||||||
|
strlcat(path, "/cgroup.events", sizeof(path));
|
||||||
|
|
||||||
|
return iwatch_add(&iw_cgroup, path, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cgroup_user(char *name, int pid)
|
||||||
|
{
|
||||||
|
if (!avail)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return cgroup_leaf_init("user", name, pid, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cgroup_service(char *name, int pid, struct cgroup *cg)
|
||||||
|
{
|
||||||
|
char *group = "system";
|
||||||
|
|
||||||
|
if (!avail)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (cg && cg->name[0]) {
|
||||||
|
char path[256];
|
||||||
|
|
||||||
|
if (!strcmp(cg->name, "root"))
|
||||||
|
return fnwrite(str("%d", pid), FINIT_CGPATH "/cgroup.procs");
|
||||||
|
|
||||||
|
if (!strcmp(cg->name, "init"))
|
||||||
|
return fnwrite(str("%d", pid), FINIT_CGPATH "/init/cgroup.procs");
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "/sys/fs/cgroup/%s", cg->name);
|
||||||
|
if (fisdir(path))
|
||||||
|
group = cg->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cgroup_leaf_init(group, name, pid, cg ? cg->cfg : NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void append_ctrl(char *ctrl)
|
static void append_ctrl(char *ctrl)
|
||||||
{
|
{
|
||||||
char *wanted[] = {
|
if (controllers[0])
|
||||||
"cpu",
|
strlcat(controllers, " ", sizeof(controllers));
|
||||||
"cpuacct",
|
|
||||||
"cpuset",
|
|
||||||
"memory"
|
|
||||||
};
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for (i = 0; i < NELEMS(wanted); i++) {
|
strlcat(controllers, "+", sizeof(controllers));
|
||||||
if (strcmp(wanted[i], ctrl))
|
strlcat(controllers, ctrl, sizeof(controllers));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cgroup_handle_event(char *event, uint32_t mask)
|
||||||
|
{
|
||||||
|
char path[strlen(event) + 1];
|
||||||
|
char buf[80];
|
||||||
|
char *ptr;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
dbg("event: '%s', mask: %08x", event, mask);
|
||||||
|
if (!(mask & IN_MODIFY))
|
||||||
|
return;
|
||||||
|
|
||||||
|
fp = fopen(event, "r");
|
||||||
|
if (!fp) {
|
||||||
|
dbg("Failed opening %s, skipping ...", event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
if (strncmp(buf, "populated", 9))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (strcmp(controllers, "none"))
|
chomp(buf);
|
||||||
strlcat(controllers, ",", sizeof(controllers));
|
if (atoi(&buf[10]))
|
||||||
else
|
break;
|
||||||
strlcpy(controllers, "", sizeof(controllers));
|
|
||||||
|
|
||||||
strlcat(controllers, ctrl, sizeof(controllers));
|
strlcpy(path, event, sizeof(path));
|
||||||
|
ptr = strrchr(path, '/');
|
||||||
|
if (ptr) {
|
||||||
|
*ptr = 0;
|
||||||
|
if (!cgroup_del(path)) {
|
||||||
|
/*
|
||||||
|
* try with parent, top-level group, we
|
||||||
|
* may get events out-of-order *sigh*
|
||||||
|
*/
|
||||||
|
ptr = strrchr(path, '/');
|
||||||
|
if (!ptr)
|
||||||
|
break;
|
||||||
|
*ptr = 0;
|
||||||
|
cgroup_del(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cgroup_events_cb(uev_t *w, void *arg, int events)
|
||||||
|
{
|
||||||
|
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
||||||
|
struct inotify_event *ev;
|
||||||
|
ssize_t sz;
|
||||||
|
size_t off;
|
||||||
|
|
||||||
|
sz = read(w->fd, ev_buf, sizeof(ev_buf) - 1);
|
||||||
|
if (sz <= 0) {
|
||||||
|
err(1, "invalid inotify event");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ev_buf[sz] = 0;
|
||||||
|
|
||||||
|
for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) {
|
||||||
|
struct iwatch_path *iwp;
|
||||||
|
|
||||||
|
if (off + sizeof(*ev) > (size_t)sz)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ev = (struct inotify_event *)&ev_buf[off];
|
||||||
|
if (off + sizeof(*ev) + ev->len > (size_t)sz)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!ev->mask)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Find base path for this event */
|
||||||
|
iwp = iwatch_find_by_wd(&iw_cgroup, ev->wd);
|
||||||
|
if (!iwp || !iwp->path)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
cgroup_handle_event(iwp->path, ev->mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef AUTO_RELOAD
|
||||||
|
if (conf_any_change())
|
||||||
|
service_reload_dynamic();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct cg *cgroup_find(char *name)
|
||||||
|
{
|
||||||
|
struct cg *cg;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(cg, &cgroups, link) {
|
||||||
|
if (strcmp(cg->name, name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return cg;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Marks all unprotected cgroups for deletion (during reload)
|
||||||
|
*/
|
||||||
|
void cgroup_mark_all(void)
|
||||||
|
{
|
||||||
|
struct cg *cg;
|
||||||
|
|
||||||
|
if (!avail)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(cg, &cgroups, link) {
|
||||||
|
if (cg->is_protected)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
cg->active = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove (try to) all unused cgroups
|
||||||
|
*/
|
||||||
|
void cgroup_cleanup(void)
|
||||||
|
{
|
||||||
|
struct cg *cg, *tmp;
|
||||||
|
char path[256];
|
||||||
|
|
||||||
|
if (!avail)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TAILQ_FOREACH_SAFE(cg, &cgroups, link, tmp) {
|
||||||
|
if (cg->active)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), FINIT_CGPATH "/%s", cg->name);
|
||||||
|
cgroup_del(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add, or update, settings for top-level cgroup
|
||||||
|
*/
|
||||||
|
int cgroup_add(char *name, char *cfg, int is_protected)
|
||||||
|
{
|
||||||
|
struct cg *cg;
|
||||||
|
|
||||||
|
if (!avail)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
return -1;
|
||||||
|
if (!cfg)
|
||||||
|
cfg = "";
|
||||||
|
|
||||||
|
cg = cgroup_find(name);
|
||||||
|
if (!cg) {
|
||||||
|
cg = malloc(sizeof(struct cg));
|
||||||
|
if (!cg) {
|
||||||
|
err(1, "Failed allocating 'struct cg' for %s", name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
cg->name = strdup(name);
|
||||||
|
if (!cg->name) {
|
||||||
|
err(1, "Failed setting cgroup name %s", name);
|
||||||
|
free(cg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
TAILQ_INSERT_TAIL(&cgroups, cg, link);
|
||||||
|
} else
|
||||||
|
free(cg->cfg);
|
||||||
|
|
||||||
|
cg->cfg = strdup(cfg);
|
||||||
|
if (!cg->cfg) {
|
||||||
|
err(1, "Failed add/update of cgroup %s", name);
|
||||||
|
TAILQ_REMOVE(&cgroups, cg, link);
|
||||||
|
free(cg->name);
|
||||||
|
free(cg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
cg->is_protected = is_protected;
|
||||||
|
cg->active = 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove inactive top-level cgroup
|
||||||
|
*/
|
||||||
|
int cgroup_del(char *dir)
|
||||||
|
{
|
||||||
|
struct cg *cg;
|
||||||
|
char path[256];
|
||||||
|
|
||||||
|
if (!avail)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(cg, &cgroups, link) {
|
||||||
|
snprintf(path, sizeof(path), FINIT_CGPATH "/%s", cg->name);
|
||||||
|
if (strcmp(path, dir))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (cg->active)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rmdir(dir) && errno != ENOENT) {
|
||||||
|
dbg("Failed removing %s: %s", dir, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cg) {
|
||||||
|
TAILQ_REMOVE(&cgroups, cg, link);
|
||||||
|
free(cg->name);
|
||||||
|
free(cg->cfg);
|
||||||
|
free(cg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the top-level init cgroup is a leaf, that's ensured in cgroup_init() */
|
||||||
|
void cgroup_config(void)
|
||||||
|
{
|
||||||
|
struct cg *cg;
|
||||||
|
|
||||||
|
if (!avail)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(cg, &cgroups, link) {
|
||||||
|
char path[256];
|
||||||
|
int leaf = 0;
|
||||||
|
|
||||||
|
if (!cg->active)
|
||||||
|
continue;
|
||||||
|
if (!strcmp(cg->name, "init"))
|
||||||
|
leaf = 1; /* reserved */
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "%s/%s", FINIT_CGPATH, cg->name);
|
||||||
|
group_init(path, leaf, cg->cfg);
|
||||||
|
|
||||||
|
strlcat(path, "/cgroup.events", sizeof(path));
|
||||||
|
iwatch_add(&iw_cgroup, path, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called by Finit at early boot to mount initial cgroups
|
* Called by Finit at early boot to mount initial cgroups
|
||||||
*/
|
*/
|
||||||
void cgroup_init(void)
|
void cgroup_init(uev_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
int opts = MS_NODEV | MS_NOEXEC | MS_NOSUID;
|
int opts = MS_NODEV | MS_NOEXEC | MS_NOSUID;
|
||||||
char buf[80];
|
char buf[80];
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
int fd;
|
||||||
|
|
||||||
fp = fopen("/proc/cgroups", "r");
|
if (mount("none", FINIT_CGPATH, "cgroup2", opts, NULL)) {
|
||||||
|
if (errno == ENOENT)
|
||||||
|
logit(LOG_INFO, "Kernel does not support cgroups v2, disabling.");
|
||||||
|
else if (errno == EPERM) /* Probably inside an unpriviliged container */
|
||||||
|
logit(LOG_INFO, "Not allowed to mount cgroups v2, disabling.");
|
||||||
|
else
|
||||||
|
err(1, "Failed mounting cgroup v2");
|
||||||
|
avail = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
avail = 1;
|
||||||
|
|
||||||
|
/* Find available controllers */
|
||||||
|
fp = fopen(FINIT_CGPATH "/cgroup.controllers", "r");
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
_d("No cgroup support");
|
err(1, "Failed opening %s", FINIT_CGPATH "/cgroup.controllers");
|
||||||
|
abort:
|
||||||
|
umount(FINIT_CGPATH);
|
||||||
|
avail = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mount("none", "/sys/fs/cgroup", "tmpfs", opts, NULL)) {
|
if (fgets(buf, sizeof(buf), fp)) {
|
||||||
_d("Failed mounting cgroups");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Skip first line, header */
|
|
||||||
(void)fgets(buf, sizeof(buf), fp);
|
|
||||||
|
|
||||||
/* Create and mount traditional cgroups v1 hier */
|
|
||||||
while (fgets(buf, sizeof(buf), fp)) {
|
|
||||||
char *cgroup;
|
char *cgroup;
|
||||||
char rc[80];
|
|
||||||
|
|
||||||
cgroup = strtok(buf, "\t ");
|
cgroup = strtok(chomp(buf), "\t ");
|
||||||
if (!cgroup)
|
while (cgroup) {
|
||||||
continue;
|
append_ctrl(cgroup);
|
||||||
|
cgroup = strtok(NULL, "\t ");
|
||||||
snprintf(rc, sizeof(rc), "/sys/fs/cgroup/%s", cgroup);
|
}
|
||||||
#if 0
|
|
||||||
if (mkdir(rc, 0755) && EEXIST != errno)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (mount("cgroup", rc, "cgroup", opts, cgroup))
|
|
||||||
_d("Failed mounting %s cgroup on %s", cgroup, rc);
|
|
||||||
#else
|
|
||||||
symlink("finit", rc);
|
|
||||||
append_ctrl(cgroup);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Finit default cgroups for process monitoring */
|
|
||||||
if (mkdir(FINIT_CGPATH, 0755) && EEXIST != errno)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
strlcpy(controllers, "none,name=finit", sizeof(controllers));
|
|
||||||
#else
|
|
||||||
strlcat(controllers, ",name=finit", sizeof(controllers));
|
|
||||||
#endif
|
|
||||||
if (mount("none", FINIT_CGPATH, "cgroup", opts, controllers)) {
|
|
||||||
_pe("Failed mounting Finit cgroup hierarchy");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set up reaper and enable callbacks */
|
|
||||||
echo(FINIT_CGPATH "/release_agent", 0, FINIT_LIBPATH_ "/cgreaper.sh");
|
|
||||||
echo(FINIT_CGPATH "/notify_on_release", 0, "1");
|
|
||||||
|
|
||||||
/* Default groups, PID 1, services, and user/login processes */
|
|
||||||
if (mkdir(FINIT_CGPATH "/init", 0755) && EEXIST != errno)
|
|
||||||
goto fail;
|
|
||||||
if (mkdir(FINIT_CGPATH "/system", 0755) && EEXIST != errno)
|
|
||||||
goto fail;
|
|
||||||
if (mkdir(FINIT_CGPATH "/user", 0755) && EEXIST != errno)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set up basic limits for our groups. Finit optimized defaults
|
|
||||||
* for embedded and server systems include limiting the groups
|
|
||||||
* init and user to a single CPU with 10% share, the system
|
|
||||||
* group gets the rest. Override this from finit.conf
|
|
||||||
*/
|
|
||||||
#if 0
|
|
||||||
#else
|
|
||||||
snprintf(buf, sizeof(buf), "0-%d", get_nprocs_conf() - 1);
|
|
||||||
|
|
||||||
group_init(FINIT_CGPATH "/init", "0", 50);
|
|
||||||
group_init(FINIT_CGPATH "/user", "0", 75);
|
|
||||||
group_init(FINIT_CGPATH "/system", buf, 900);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Move ourselves to init */
|
|
||||||
echo(FINIT_CGPATH "/init/cgroup.procs", 0, "1");
|
|
||||||
|
|
||||||
fail:
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
|
||||||
|
|
||||||
static int move_pid(char *group, char *name, int pid)
|
/* Check for cpu controller, abort if missing */
|
||||||
{
|
if (!strstr(controllers, "+cpu")) {
|
||||||
char path[256];
|
logit(LOG_NOTICE, "Missing CPU controller, disabling cgroup support.");
|
||||||
|
goto abort;
|
||||||
snprintf(path, sizeof(path), "/sys/fs/cgroup/%s/%s", group, name);
|
|
||||||
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, int pid)
|
|
||||||
{
|
|
||||||
return move_pid("finit/user", name, pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cgroup_service(char *name, int pid)
|
|
||||||
{
|
|
||||||
if (pid <= 0) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return move_pid("finit/system", name, pid);
|
/* Enable all controllers */
|
||||||
|
if (fnwrite(controllers, FINIT_CGPATH "/cgroup.subtree_control")) {
|
||||||
|
err(1, "Failed enabling %s for %s", controllers, FINIT_CGPATH "/cgroup.subtree_control");
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* prepare cgroup.events watcher */
|
||||||
|
fd = iwatch_init(&iw_cgroup);
|
||||||
|
if (fd == -1)
|
||||||
|
goto abort;
|
||||||
|
|
||||||
|
if (uev_io_init(ctx, &cgw, cgroup_events_cb, NULL, fd, UEV_READ)) {
|
||||||
|
err(1, "Failed setting up cgroup.events watcher");
|
||||||
|
iwatch_exit(&iw_cgroup);
|
||||||
|
close(fd);
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Default (protected) groups, PID 1, services, and user/login processes */
|
||||||
|
cgroup_add("init", "cpu.weight:100", 1);
|
||||||
|
cgroup_add("system", "cpu.weight:9800", 1);
|
||||||
|
cgroup_add("user", "cpu.weight:100", 1);
|
||||||
|
cgroup_config();
|
||||||
|
|
||||||
|
/* Move ourselves to init (best effort, otherwise run in 'root' group */
|
||||||
|
if (fnwrite("1", FINIT_CGPATH "/init/cgroup.procs")) {
|
||||||
|
err(1, "Failed moving PID 1 to cgroup %s", FINIT_CGPATH "/init");
|
||||||
|
uev_io_stop(&cgw);
|
||||||
|
iwatch_exit(&iw_cgroup);
|
||||||
|
close(fd);
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+18
-4
@@ -1,6 +1,6 @@
|
|||||||
/* Finit control group support functions
|
/* Finit control group support functions
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2019-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -24,9 +24,23 @@
|
|||||||
#ifndef FINIT_CGROUP_H_
|
#ifndef FINIT_CGROUP_H_
|
||||||
#define FINIT_CGROUP_H_
|
#define FINIT_CGROUP_H_
|
||||||
|
|
||||||
void cgroup_init (void);
|
#include <uev/uev.h>
|
||||||
|
|
||||||
int cgroup_user (char *name, int pid);
|
struct cgroup {
|
||||||
int cgroup_service (char *name, int pid);
|
char name[16];
|
||||||
|
char cfg[128];
|
||||||
|
};
|
||||||
|
|
||||||
|
void cgroup_mark_all(void);
|
||||||
|
void cgroup_cleanup (void);
|
||||||
|
|
||||||
|
int cgroup_add (char *name, char *cfg, int is_protected);
|
||||||
|
int cgroup_del (char *dir);
|
||||||
|
void cgroup_config (void);
|
||||||
|
|
||||||
|
void cgroup_init (uev_ctx_t *ctx);
|
||||||
|
|
||||||
|
int cgroup_user (char *name, int pid);
|
||||||
|
int cgroup_service (char *name, int pid, struct cgroup *cg);
|
||||||
|
|
||||||
#endif /* FINIT_CGROUP_H_ */
|
#endif /* FINIT_CGROUP_H_ */
|
||||||
|
|||||||
+340
-159
@@ -1,6 +1,6 @@
|
|||||||
/* New client tool, replaces old /dev/initctl API and telinit tool
|
/* New client tool, replaces old /dev/initctl API and telinit tool
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2019-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -23,16 +23,22 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <err.h>
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <search.h>
|
#include <search.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <lite/lite.h>
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
#include <sys/sysinfo.h> /* sysinfo() */
|
#include <sys/sysinfo.h> /* sysinfo() */
|
||||||
|
|
||||||
|
#include "cgutil.h"
|
||||||
#include "initctl.h"
|
#include "initctl.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
#define CDIM plain ? "" : "\e[2m"
|
#define CDIM plain ? "" : "\e[2m"
|
||||||
#define CRST plain ? "" : "\e[0m"
|
#define CRST plain ? "" : "\e[0m"
|
||||||
@@ -44,23 +50,15 @@
|
|||||||
|
|
||||||
uint64_t total_ram; /* From sysinfo() */
|
uint64_t total_ram; /* From sysinfo() */
|
||||||
|
|
||||||
struct cg {
|
|
||||||
struct cg *cg_next;
|
|
||||||
|
|
||||||
char *cg_path; /* path in /sys/fs/cgroup */
|
|
||||||
uint64_t cg_prev; /* cpuacct.usage */
|
|
||||||
uint64_t cg_rss; /* memory.stat */
|
|
||||||
uint64_t cg_vmlib; /* memory.stat */
|
|
||||||
uint64_t cg_vmsize; /* memory.usage_in_bytes */
|
|
||||||
float cg_mem; /* cg_rss / total_ram * 100 */
|
|
||||||
float cg_load; /* curr - prev / 10000000.0 */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct cg dummy; /* empty result "NULL" */
|
struct cg dummy; /* empty result "NULL" */
|
||||||
struct cg *list;
|
struct cg *list;
|
||||||
|
|
||||||
|
int cgroup_avail(void)
|
||||||
|
{
|
||||||
|
return fismnt(FINIT_CGPATH);
|
||||||
|
}
|
||||||
|
|
||||||
static char *pid_cmdline(int pid, char *buf, size_t len)
|
char *pid_cmdline(int pid, char *buf, size_t len)
|
||||||
{
|
{
|
||||||
size_t i, sz;
|
size_t i, sz;
|
||||||
char *ptr;
|
char *ptr;
|
||||||
@@ -94,40 +92,84 @@ static char *pid_cmdline(int pid, char *buf, size_t len)
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *pid_comm(int pid, char *buf, size_t len)
|
char *pid_comm(int pid, char *buf, size_t len)
|
||||||
{
|
{
|
||||||
|
char *ptr = NULL;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
fp = fopenf("r", "/proc/%d/comm", pid);
|
fp = fopenf("r", "/proc/%d/comm", pid);
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
fgets(buf, len, fp);
|
if (fgets(buf, len, fp))
|
||||||
|
ptr = chomp(buf);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
return chomp(buf);
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *pid_cgroup(int pid, char *buf, size_t len)
|
||||||
|
{
|
||||||
|
char *ptr = NULL;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopenf("r", "/proc/%d/cgroup", pid);
|
||||||
|
if (!fp)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (fgets(buf, len, fp))
|
||||||
|
ptr = chomp(buf);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
if (ptr)
|
||||||
|
ptr = strchr(buf, '/');
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *cgroup_val(char *path, char *file, char *buf, size_t len)
|
||||||
|
{
|
||||||
|
char *val = NULL;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopenf("r", "%s/%s", path, file);
|
||||||
|
if (fp) {
|
||||||
|
if (fgets(buf, len, fp)) {
|
||||||
|
val = chomp(buf);
|
||||||
|
len = strcspn(val, " \t");
|
||||||
|
val[len] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t cgroup_uint64(char *path, char *file)
|
static uint64_t cgroup_uint64(char *path, char *file)
|
||||||
{
|
{
|
||||||
uint64_t val = 0;
|
uint64_t val = 0;
|
||||||
char buf[42];
|
char buf[42];
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
fp = fopenf("r", "%s/%s", path, file);
|
if (cgroup_val(path, file, buf, sizeof(buf)))
|
||||||
if (!fp)
|
|
||||||
return val;
|
|
||||||
|
|
||||||
if (fgets(buf, sizeof(buf), fp))
|
|
||||||
val = strtoull(buf, NULL, 10);
|
val = strtoull(buf, NULL, 10);
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cgroup_shares(char *path)
|
static char *cgroup_memval(char *path, char *file, char *buf, size_t len)
|
||||||
{
|
{
|
||||||
return (int)cgroup_uint64(path, "cpu.shares");
|
char data[42];
|
||||||
|
|
||||||
|
if (cgroup_val(path, file, data, sizeof(data))) {
|
||||||
|
if (!strcmp(data, "max"))
|
||||||
|
strlcpy(buf, data, len);
|
||||||
|
else
|
||||||
|
memsz(strtoull(data, NULL, 10), buf, len);
|
||||||
|
} else
|
||||||
|
buf[0] = 0;
|
||||||
|
|
||||||
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t cgroup_memuse(struct cg *cg)
|
static uint64_t cgroup_memuse(struct cg *cg)
|
||||||
@@ -135,47 +177,62 @@ static uint64_t cgroup_memuse(struct cg *cg)
|
|||||||
char buf[42];
|
char buf[42];
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
|
|
||||||
fp = fopenf("r", "%s/memory.stat", cg->cg_path);
|
fp = fopenf("r", "%s/memory.stat", cg->cg_path);
|
||||||
if (fp) {
|
if (fp) {
|
||||||
|
cg->cg_rss = 0;
|
||||||
|
cg->cg_vmlib = 0;
|
||||||
|
|
||||||
while (fgets(buf, sizeof(buf), fp)) {
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
if (!strncmp(buf, "total_rss", 9)) {
|
chomp(buf);
|
||||||
cg->cg_rss = strtoull(&buf[10], NULL, 10);
|
|
||||||
|
if (!strncmp(buf, "anon", 4)) {
|
||||||
|
cg->cg_rss += strtoull(&buf[5], NULL, 10);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!strncmp(buf, "total_mapped_file", 17)) {
|
if (!strncmp(buf, "slab", 4)) {
|
||||||
cg->cg_vmlib = strtoull(&buf[18], NULL, 10);
|
cg->cg_rss += strtoull(&buf[5], NULL, 10);
|
||||||
break; /* done */
|
continue;
|
||||||
|
}
|
||||||
|
if (!strncmp(buf, "kernel_stack", 12)) {
|
||||||
|
cg->cg_rss += strtoull(&buf[5], NULL, 10);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strncmp(buf, "pagetables", 10)) {
|
||||||
|
cg->cg_rss += strtoull(&buf[5], NULL, 10);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strncmp(buf, "percpu", 6)) {
|
||||||
|
cg->cg_rss += strtoull(&buf[5], NULL, 10);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strncmp(buf, "sock", 4)) {
|
||||||
|
cg->cg_rss += strtoull(&buf[5], NULL, 10);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strncmp(buf, "file", 4)) {
|
||||||
|
cg->cg_vmlib += strtoull(&buf[5], NULL, 10);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strncmp(buf, "file_mapped", 11)) {
|
||||||
|
cg->cg_vmlib += strtoull(&buf[5], NULL, 10);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
cg->cg_mem = (float)(cg->cg_rss * 100 / total_ram);
|
cg->cg_memshare = (float)(cg->cg_rss * 100 / total_ram);
|
||||||
|
|
||||||
/* "fuzz value for efficient access", sort of like total_cache + total_rss */
|
return cg->cg_vmsize = cgroup_uint64(cg->cg_path, "memory.current");
|
||||||
return cg->cg_vmsize = cgroup_uint64(cg->cg_path, "memory.usage_in_bytes");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *memsz(uint64_t sz, char *buf, size_t len)
|
uint64_t cgroup_memory(char *group)
|
||||||
{
|
{
|
||||||
int gb, mb, kb, b;
|
char path[256];
|
||||||
|
|
||||||
gb = sz / (1024 * 1024 * 1024);
|
paste(path, sizeof(path), FINIT_CGPATH, group);
|
||||||
sz = sz % (1024 * 1024 * 1024);
|
|
||||||
mb = sz / (1024 * 1024);
|
|
||||||
sz = sz % (1024 * 1024);
|
|
||||||
kb = sz / (1024);
|
|
||||||
b = sz % (1024);
|
|
||||||
|
|
||||||
if (gb)
|
return cgroup_uint64(path, "memory.current");
|
||||||
snprintf(buf, len, "%d.%dG", gb, mb / 102);
|
|
||||||
else if (mb)
|
|
||||||
snprintf(buf, len, "%d.%dM", mb, kb / 102);
|
|
||||||
else
|
|
||||||
snprintf(buf, len, "%d.%dk", kb, b / 102);
|
|
||||||
|
|
||||||
return buf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static float cgroup_cpuload(struct cg *cg)
|
static float cgroup_cpuload(struct cg *cg)
|
||||||
@@ -184,23 +241,28 @@ static float cgroup_cpuload(struct cg *cg)
|
|||||||
char buf[64];
|
char buf[64];
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
snprintf(fn, sizeof(fn), "%s/cpuacct.usage", cg->cg_path);
|
snprintf(fn, sizeof(fn), "%s/cpu.stat", cg->cg_path);
|
||||||
fp = fopen(fn, "r");
|
fp = fopen(fn, "r");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
err(1, "Cannot open %s", fn);
|
ERR(72, "Cannot open %s", fn);
|
||||||
|
|
||||||
if (fgets(buf, sizeof(buf), fp)) {
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
uint64_t curr;
|
uint64_t curr;
|
||||||
|
|
||||||
curr = strtoull(buf, NULL, 10);
|
chomp(buf);
|
||||||
|
if (strncmp(buf, "usage_usec", 10))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
curr = strtoull(&buf[11], NULL, 10);
|
||||||
if (cg->cg_prev != 0) {
|
if (cg->cg_prev != 0) {
|
||||||
uint64_t diff = curr - cg->cg_prev;
|
uint64_t diff = curr - cg->cg_prev;
|
||||||
|
|
||||||
/* this expects 1 sec poll interval */
|
/* this expects 1 sec poll interval */
|
||||||
cg->cg_load = (float)(diff / 1000000);
|
cg->cg_load = (float)(diff / 1000000);
|
||||||
cg->cg_load /= 10.0;
|
cg->cg_load *= 100.0;
|
||||||
}
|
}
|
||||||
cg->cg_prev = curr;
|
cg->cg_prev = curr;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
@@ -214,15 +276,17 @@ static struct cg *append(char *path)
|
|||||||
char fn[256];
|
char fn[256];
|
||||||
ENTRY item;
|
ENTRY item;
|
||||||
|
|
||||||
snprintf(fn, sizeof(fn), "%s/cpuacct.usage", path);
|
snprintf(fn, sizeof(fn), "%s/cpu.stat", path);
|
||||||
if (access(fn, F_OK)) {
|
if (access(fn, F_OK)) {
|
||||||
warn("not a cgroup path with cpuacct controller, %s", path);
|
/* older kernels, 4.19, don't have summary cpu.stat in root */
|
||||||
|
if (strcmp(path, FINIT_CGPATH))
|
||||||
|
WARN("not a cgroup path with cpu controller, %s", path);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
cg = calloc(1, sizeof(struct cg));
|
cg = calloc(1, sizeof(struct cg));
|
||||||
if (!cg)
|
if (!cg)
|
||||||
err(1, "failed allocating struct cg");
|
ERR(71, "failed allocating struct cg");
|
||||||
|
|
||||||
cg->cg_path = strdup(path);
|
cg->cg_path = strdup(path);
|
||||||
if (list)
|
if (list)
|
||||||
@@ -232,7 +296,7 @@ static struct cg *append(char *path)
|
|||||||
item.key = cg->cg_path;
|
item.key = cg->cg_path;
|
||||||
item.data = cg;
|
item.data = cg;
|
||||||
if (!hsearch(item, ENTER))
|
if (!hsearch(item, ENTER))
|
||||||
err(1, "failed adding to hash table");
|
ERR(70, "failed adding to hash table");
|
||||||
|
|
||||||
return cg;
|
return cg;
|
||||||
}
|
}
|
||||||
@@ -248,7 +312,8 @@ static struct cg *find(char *path)
|
|||||||
return append(path);
|
return append(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cg *cg_update(char *path)
|
/* update stats */
|
||||||
|
struct cg *cg_stats(char *path)
|
||||||
{
|
{
|
||||||
struct cg *cg;
|
struct cg *cg;
|
||||||
|
|
||||||
@@ -262,6 +327,21 @@ static struct cg *cg_update(char *path)
|
|||||||
return cg;
|
return cg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* query config */
|
||||||
|
struct cg *cg_conf(char *path)
|
||||||
|
{
|
||||||
|
static struct cg cg;
|
||||||
|
|
||||||
|
cgroup_val(path, "memory.min", cg.cg_mem.min, sizeof(cg.cg_mem.min));
|
||||||
|
cgroup_memval(path, "memory.max", cg.cg_mem.max, sizeof(cg.cg_mem.max));
|
||||||
|
cgroup_val(path, "cpu.weight", cg.cg_cpu.weight, sizeof(cg.cg_cpu.weight));
|
||||||
|
cgroup_val(path, "cpu.max", cg.cg_cpu.max, sizeof(cg.cg_cpu.max));
|
||||||
|
cgroup_val(path, "cpuset.cpus.effective", cg.cg_cpu.set, sizeof(cg.cg_cpu.set));
|
||||||
|
cg.cg_vmsize = cgroup_uint64(path, "memory.current");
|
||||||
|
|
||||||
|
return &cg;
|
||||||
|
}
|
||||||
|
|
||||||
static int cgroup_filter(const struct dirent *entry)
|
static int cgroup_filter(const struct dirent *entry)
|
||||||
{
|
{
|
||||||
/* Skip current dir ".", and prev dir "..", from list of files */
|
/* Skip current dir ".", and prev dir "..", from list of files */
|
||||||
@@ -278,11 +358,11 @@ static int cgroup_filter(const struct dirent *entry)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cgroup_tree(char *path, char *pfx, int top)
|
int cgroup_tree(char *path, char *pfx, int mode, int pos)
|
||||||
{
|
{
|
||||||
struct dirent **namelist = NULL;
|
struct dirent **namelist = NULL;
|
||||||
char s[32], r[32], l[32];
|
char s[32], r[32], l[32];
|
||||||
char row[screen_cols + 9]; /* + control codes */
|
char row[ttcols + 9]; /* + control codes */
|
||||||
size_t rlen = sizeof(row) - 1;
|
size_t rlen = sizeof(row) - 1;
|
||||||
size_t rplen = rlen - 9;
|
size_t rplen = rlen - 9;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
@@ -293,7 +373,7 @@ static int cgroup_tree(char *path, char *pfx, int top)
|
|||||||
int i, n;
|
int i, n;
|
||||||
int num;
|
int num;
|
||||||
|
|
||||||
if (top >= screen_rows)
|
if (pos >= ttrows)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (-1 == lstat(path, &st))
|
if (-1 == lstat(path, &st))
|
||||||
@@ -313,60 +393,29 @@ static int cgroup_tree(char *path, char *pfx, int top)
|
|||||||
|
|
||||||
if (!pfx) {
|
if (!pfx) {
|
||||||
pfx = "";
|
pfx = "";
|
||||||
if (top) {
|
switch (mode) {
|
||||||
cg = cg_update(path);
|
case 1:
|
||||||
snprintf(row, rplen, " %6.6s %6.6s %6.6s %5.1f %5.1f [%s]",
|
cg = cg_stats(path);
|
||||||
|
snprintf(row, rplen, "\r %6.6s %6.6s %6.6s %5.1f %5.1f %s",
|
||||||
memsz(cg->cg_vmsize, s, sizeof(s)),
|
memsz(cg->cg_vmsize, s, sizeof(s)),
|
||||||
memsz(cg->cg_rss, r, sizeof(r)),
|
memsz(cg->cg_rss, r, sizeof(r)),
|
||||||
memsz(cg->cg_vmlib, l, sizeof(l)),
|
memsz(cg->cg_vmlib, l, sizeof(l)),
|
||||||
cg->cg_mem, cg->cg_load, path);
|
cg->cg_memshare, cg->cg_load, path);
|
||||||
} else
|
break;
|
||||||
strlcpy(row, path, rplen);
|
case 2:
|
||||||
|
cg = cg_conf(path);
|
||||||
puts(row);
|
snprintf(row, rplen, "\r%6.6s [%-6.6s%6.6s] %6s [%-6.6s%6.6s] %s",
|
||||||
}
|
memsz(cg->cg_vmsize, s, sizeof(s)),
|
||||||
|
cg->cg_mem.min, cg->cg_mem.max, cg->cg_cpu.set,
|
||||||
n = scandir(path, &namelist, cgroup_filter, alphasort);
|
cg->cg_cpu.weight, cg->cg_cpu.max, path);
|
||||||
if (n > 0) {
|
break;
|
||||||
for (i = 0; i < n; i++) {
|
default:
|
||||||
char *nm = namelist[i]->d_name;
|
strlcpy(row, "\r", rplen);
|
||||||
char prefix[80], tmp[42];
|
strlcat(row, path, rplen);
|
||||||
|
break;
|
||||||
snprintf(buf, sizeof(buf), "%s/%s", path, nm);
|
|
||||||
if (top) {
|
|
||||||
cg = cg_update(buf);
|
|
||||||
snprintf(row, rplen,
|
|
||||||
" %6.6s %6.6s %6.6s %5.1f %5.1f ",
|
|
||||||
memsz(cg->cg_vmsize, s, sizeof(s)),
|
|
||||||
memsz(cg->cg_rss, r, sizeof(r)),
|
|
||||||
memsz(cg->cg_vmlib, l, sizeof(l)),
|
|
||||||
cg->cg_mem, cg->cg_load);
|
|
||||||
} else
|
|
||||||
row[0] = 0;
|
|
||||||
|
|
||||||
strlcat(row, pfx, rplen);
|
|
||||||
if (i + 1 == n) {
|
|
||||||
strlcat(row, END, rplen);
|
|
||||||
snprintf(prefix, sizeof(prefix), "%s ", pfx);
|
|
||||||
} else {
|
|
||||||
strlcat(row, FORK, rplen);
|
|
||||||
snprintf(prefix, sizeof(prefix), "%s%s ", pfx, PIPE);
|
|
||||||
}
|
|
||||||
strlcat(row, " ", rplen);
|
|
||||||
|
|
||||||
strlcat(row, nm, rplen);
|
|
||||||
strlcat(row, "/ ", rplen);
|
|
||||||
|
|
||||||
snprintf(tmp, sizeof(tmp), "[cpu.shares: %d]", cgroup_shares(buf));
|
|
||||||
strlcat(row, tmp, rplen);
|
|
||||||
puts(row);
|
|
||||||
|
|
||||||
rc += cgroup_tree(buf, prefix, top ? top + i : 0);
|
|
||||||
|
|
||||||
free(namelist[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(namelist);
|
puts(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num > 0) {
|
if (num > 0) {
|
||||||
@@ -384,13 +433,19 @@ static int cgroup_tree(char *path, char *pfx, int top)
|
|||||||
/* skip kernel threads for now (no cmdline) */
|
/* skip kernel threads for now (no cmdline) */
|
||||||
pid_comm(pid, comm, sizeof(comm));
|
pid_comm(pid, comm, sizeof(comm));
|
||||||
if (pid_cmdline(pid, buf, sizeof(buf))) {
|
if (pid_cmdline(pid, buf, sizeof(buf))) {
|
||||||
char proc[screen_cols];
|
char proc[ttcols];
|
||||||
int len;
|
|
||||||
|
|
||||||
if (top)
|
switch (mode) {
|
||||||
snprintf(row, rplen, "%37s", " ");
|
case 1:
|
||||||
else
|
snprintf(row, rplen, "\r%37s", " ");
|
||||||
row[0] = 0;
|
break;
|
||||||
|
case 2:
|
||||||
|
snprintf(row, rplen, "\r --.-- [ ] [ ] ");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
strlcpy(row, "\r", rplen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
strlcat(row, pfx, rplen);
|
strlcat(row, pfx, rplen);
|
||||||
strlcat(row, ++i == num ? END : FORK, rlen);
|
strlcat(row, ++i == num ? END : FORK, rlen);
|
||||||
@@ -400,6 +455,8 @@ static int cgroup_tree(char *path, char *pfx, int top)
|
|||||||
if (plain) {
|
if (plain) {
|
||||||
strlcat(row, proc, rplen);
|
strlcat(row, proc, rplen);
|
||||||
} else {
|
} else {
|
||||||
|
int len;
|
||||||
|
|
||||||
strlcat(row, CDIM, rlen);
|
strlcat(row, CDIM, rlen);
|
||||||
strlcat(row, proc, rlen);
|
strlcat(row, proc, rlen);
|
||||||
|
|
||||||
@@ -413,21 +470,174 @@ static int cgroup_tree(char *path, char *pfx, int top)
|
|||||||
puts(row);
|
puts(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (top) {
|
if (mode == 1) {
|
||||||
top += i;
|
pos += i;
|
||||||
if (top >= screen_rows)
|
if (pos >= ttrows)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fclose(fp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
|
n = scandir(path, &namelist, cgroup_filter, alphasort);
|
||||||
|
if (n > 0) {
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
char *nm = namelist[i]->d_name;
|
||||||
|
char prefix[80];
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf), "%s/%s", path, nm);
|
||||||
|
switch (mode) {
|
||||||
|
case 1:
|
||||||
|
cg = cg_stats(buf);
|
||||||
|
snprintf(row, rplen,
|
||||||
|
"\r %6.6s %6.6s %6.6s %5.1f %5.1f ",
|
||||||
|
memsz(cg->cg_vmsize, s, sizeof(s)),
|
||||||
|
memsz(cg->cg_rss, r, sizeof(r)),
|
||||||
|
memsz(cg->cg_vmlib, l, sizeof(l)),
|
||||||
|
cg->cg_memshare, cg->cg_load);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
cg = cg_conf(buf);
|
||||||
|
snprintf(row, rplen, "\r%6.6s [%-6.6s%6.6s] %6.6s [%-6.6s%6.6s] ",
|
||||||
|
memsz(cg->cg_vmsize, s, sizeof(s)),
|
||||||
|
cg->cg_mem.min, cg->cg_mem.max,
|
||||||
|
cg->cg_cpu.set, cg->cg_cpu.weight, cg->cg_cpu.max);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
strlcpy(row, "\r", rplen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
strlcat(row, pfx, rplen);
|
||||||
|
if (i + 1 == n) {
|
||||||
|
strlcat(row, END, rplen);
|
||||||
|
snprintf(prefix, sizeof(prefix), "%s ", pfx);
|
||||||
|
} else {
|
||||||
|
strlcat(row, FORK, rplen);
|
||||||
|
snprintf(prefix, sizeof(prefix), "%s%s ", pfx, PIPE);
|
||||||
|
}
|
||||||
|
strlcat(row, " ", rplen);
|
||||||
|
|
||||||
|
strlcat(row, nm, rplen);
|
||||||
|
strlcat(row, "/ ", rplen);
|
||||||
|
|
||||||
|
puts(row);
|
||||||
|
|
||||||
|
rc += cgroup_tree(buf, prefix, mode, pos + i);
|
||||||
|
|
||||||
|
free(namelist[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(namelist);
|
||||||
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int show_cgps(char *arg)
|
||||||
|
{
|
||||||
|
char path[512];
|
||||||
|
|
||||||
|
if (!arg)
|
||||||
|
arg = FINIT_CGPATH;
|
||||||
|
else if (arg[0] != '/') {
|
||||||
|
paste(path, sizeof(path), FINIT_CGPATH, arg);
|
||||||
|
arg = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cgroup_tree(arg, NULL, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cgtop(uev_t *w, void *arg, int events)
|
||||||
|
{
|
||||||
|
(void)w;
|
||||||
|
(void)events;
|
||||||
|
|
||||||
|
fputs("\e[2J\e[1;1H", stdout);
|
||||||
|
if (heading)
|
||||||
|
print_header(" VmSIZE RSS VmLIB %%MEM %%CPU GROUP");
|
||||||
|
cgroup_tree(arg, NULL, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cleanup(void)
|
||||||
|
{
|
||||||
|
ttcooked();
|
||||||
|
showcursor();
|
||||||
|
puts("");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void leave(uev_t *w, void *arg, int events)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
(void)events;
|
||||||
|
|
||||||
|
uev_exit(w->ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void key(uev_t *w, void *arg, int events)
|
||||||
|
{
|
||||||
|
char ch;
|
||||||
|
|
||||||
|
(void)arg;
|
||||||
|
(void)events;
|
||||||
|
|
||||||
|
if (read(w->fd, &ch, sizeof(ch)) != -1) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'q':
|
||||||
|
uev_exit(w->ctx);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
dbg("Got char 0x%02x", ch);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int show_cgtop(char *arg)
|
||||||
|
{
|
||||||
|
struct sysinfo si = { 0 };
|
||||||
|
uev_t timer, input, sigint, sigterm, sigquit;
|
||||||
|
char path[512];
|
||||||
|
uev_ctx_t ctx;
|
||||||
|
|
||||||
|
if (!arg)
|
||||||
|
arg = FINIT_CGPATH;
|
||||||
|
else if (arg[0] != '/') {
|
||||||
|
paste(path, sizeof(path), FINIT_CGPATH, arg);
|
||||||
|
arg = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hcreate(ttrows + 25))
|
||||||
|
ERR(70, "failed creating hash table");
|
||||||
|
|
||||||
|
sysinfo(&si);
|
||||||
|
total_ram = si.totalram * si.mem_unit;
|
||||||
|
|
||||||
|
uev_init(&ctx);
|
||||||
|
uev_timer_init(&ctx, &timer, cgtop, arg, 1, ionce ? 0 : 1000);
|
||||||
|
|
||||||
|
if (!ionce && !plain) {
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
atexit(cleanup);
|
||||||
|
ttraw();
|
||||||
|
hidecursor();
|
||||||
|
|
||||||
|
flags = fcntl(STDIN_FILENO, F_GETFL);
|
||||||
|
if (flags != -1)
|
||||||
|
(void)fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
|
||||||
|
(void)uev_io_init(&ctx, &input, key, NULL, STDIN_FILENO, UEV_READ);
|
||||||
|
|
||||||
|
(void)uev_signal_init(&ctx, &sigint, leave, NULL, SIGINT);
|
||||||
|
(void)uev_signal_init(&ctx, &sigterm, leave, NULL, SIGTERM);
|
||||||
|
(void)uev_signal_init(&ctx, &sigquit, leave, NULL, SIGQUIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return uev_run(&ctx, 0);
|
||||||
|
}
|
||||||
|
|
||||||
int show_cgroup(char *arg)
|
int show_cgroup(char *arg)
|
||||||
{
|
{
|
||||||
char path[512];
|
char path[512];
|
||||||
@@ -439,40 +649,11 @@ int show_cgroup(char *arg)
|
|||||||
arg = path;
|
arg = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
return cgroup_tree(arg, NULL, 0);
|
/* memory.current memory.min memory.max cpuset.cpus cpu.weight cpu.max */
|
||||||
}
|
if (heading)
|
||||||
|
print_header(" MEM [MIN MAX] CPU [WEIGHT MAX] GROUP");
|
||||||
|
|
||||||
int show_cgtop(char *arg)
|
return cgroup_tree(arg, NULL, 2, 0);
|
||||||
{
|
|
||||||
struct sysinfo si = { 0 };
|
|
||||||
char path[512];
|
|
||||||
int laps = 0;
|
|
||||||
|
|
||||||
if (!arg)
|
|
||||||
arg = FINIT_CGPATH;
|
|
||||||
else if (arg[0] != '/') {
|
|
||||||
paste(path, sizeof(path), FINIT_CGPATH, arg);
|
|
||||||
arg = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hcreate(screen_rows + 25))
|
|
||||||
err(1, "failed creating hash table");
|
|
||||||
|
|
||||||
sysinfo(&si);
|
|
||||||
total_ram = si.totalram * si.mem_unit;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
fputs("\e[2J\e[1;1H", stdout);
|
|
||||||
if (heading)
|
|
||||||
print_header(" VmSIZE RSS VmLIB %%MEM %%CPU GROUP");
|
|
||||||
cgroup_tree(arg, NULL, 1);
|
|
||||||
|
|
||||||
if (ionce && laps++)
|
|
||||||
break;
|
|
||||||
sleep(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+45
-3
@@ -1,6 +1,6 @@
|
|||||||
/* Cgroup utility functions for initctl
|
/* Cgroup utility functions for initctl
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2019-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -24,8 +24,50 @@
|
|||||||
#ifndef FINIT_CGUTIL_H_
|
#ifndef FINIT_CGUTIL_H_
|
||||||
#define FINIT_CGUTIL_H_
|
#define FINIT_CGUTIL_H_
|
||||||
|
|
||||||
int show_cgroup (char *arg);
|
#include <stdint.h>
|
||||||
int show_cgtop (char *arg);
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
struct cg {
|
||||||
|
struct cg *cg_next;
|
||||||
|
|
||||||
|
/* stats */
|
||||||
|
char *cg_path; /* path in /sys/fs/cgroup */
|
||||||
|
uint64_t cg_prev; /* cpuacct.usage */
|
||||||
|
uint64_t cg_rss; /* memory.stat */
|
||||||
|
uint64_t cg_vmlib; /* memory.stat */
|
||||||
|
uint64_t cg_vmsize; /* memory.current */
|
||||||
|
float cg_memshare; /* cg_rss / total_ram * 100 */
|
||||||
|
float cg_load; /* curr - prev / 10000000.0 */
|
||||||
|
|
||||||
|
/* config */
|
||||||
|
struct {
|
||||||
|
char min[32];
|
||||||
|
char max[32];
|
||||||
|
} cg_mem;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
char set[16];
|
||||||
|
char weight[32];
|
||||||
|
char max[32];
|
||||||
|
} cg_cpu;
|
||||||
|
};
|
||||||
|
|
||||||
|
int cgroup_avail(void);
|
||||||
|
|
||||||
|
char *pid_cmdline (int pid, char *buf, size_t len);
|
||||||
|
char *pid_comm (int pid, char *buf, size_t len);
|
||||||
|
char *pid_cgroup (int pid, char *buf, size_t len);
|
||||||
|
|
||||||
|
uint64_t cgroup_memory(char *group);
|
||||||
|
|
||||||
|
struct cg *cg_stats(char *path);
|
||||||
|
struct cg *cg_conf (char *path);
|
||||||
|
|
||||||
|
int cgroup_tree (char *path, char *pfx, int mode, int pos);
|
||||||
|
|
||||||
|
int show_cgroup (char *arg);
|
||||||
|
int show_cgtop (char *arg);
|
||||||
|
int show_cgps (char *arg);
|
||||||
|
|
||||||
#endif /* FINIT_CGUTIL_H_ */
|
#endif /* FINIT_CGUTIL_H_ */
|
||||||
|
|
||||||
|
|||||||
+93
-35
@@ -1,6 +1,6 @@
|
|||||||
/* External client API, using UNIX domain socket.
|
/* External client API, using UNIX domain socket.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2015-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -21,12 +21,13 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <err.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <poll.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
static int sd = -1;
|
static int sd = -1;
|
||||||
|
|
||||||
@@ -37,12 +38,18 @@ int client_connect(void)
|
|||||||
.sun_path = INIT_SOCKET,
|
.sun_path = INIT_SOCKET,
|
||||||
};
|
};
|
||||||
|
|
||||||
sd = socket(AF_UNIX, SOCK_STREAM, 0);
|
sd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
|
||||||
if (-1 == sd)
|
if (-1 == sd) {
|
||||||
err(1, "Failed creating UNIX domain socket");
|
warn("Failed creating UNIX domain socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (connect(sd, (struct sockaddr*)&sun, sizeof(sun)) == -1)
|
if (connect(sd, (struct sockaddr*)&sun, sizeof(sun)) == -1) {
|
||||||
err(1, "Failed connecting to finit");
|
if (errno != ENOENT)
|
||||||
|
warnx("Failed connecting to finit");
|
||||||
|
close(sd);
|
||||||
|
sd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
return sd;
|
return sd;
|
||||||
}
|
}
|
||||||
@@ -62,43 +69,97 @@ int client_disconnect(void)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int client_send(struct init_request *rq, ssize_t len)
|
/* Only valid after client_connect() */
|
||||||
|
int client_socket(void)
|
||||||
{
|
{
|
||||||
int sd, result = 255;
|
return sd;
|
||||||
|
}
|
||||||
|
|
||||||
sd = client_connect();
|
int client_request(struct init_request *rq, ssize_t len)
|
||||||
if (-1 == sd)
|
{
|
||||||
|
struct pollfd pfd = { 0 };
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (client_connect() == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (write(sd, rq, len) != len)
|
pfd.fd = sd;
|
||||||
goto error;
|
pfd.events = POLLOUT;
|
||||||
|
if (poll(&pfd, 1, 2000) <= 0) {
|
||||||
|
warn("Timed out waiting for Finit, errno %d", errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (read(sd, rq, len) != len)
|
if (write(sd, rq, len) != len) {
|
||||||
goto error;
|
warn("Failed communicating with Finit, errno %d", errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Exception, only command that don't need to wait for a
|
||||||
|
* response from Finit. Registers the client socket as a
|
||||||
|
* readiness notification socket with Finit
|
||||||
|
*/
|
||||||
|
if (rq->cmd == INIT_CMD_NOTIFY_SOCKET) {
|
||||||
|
rq->cmd = INIT_CMD_ACK;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pfd.fd = sd;
|
||||||
|
pfd.events = POLLIN | POLLERR | POLLHUP;
|
||||||
|
if ((rc = poll(&pfd, 1, 2000)) <= 0) {
|
||||||
|
if (rc) {
|
||||||
|
if (errno == EINTR) /* shutdown/reboot */
|
||||||
|
return -1;
|
||||||
|
warn("poll(), errno %d", errno);
|
||||||
|
} else
|
||||||
|
warnx("Timed out waiting for reply from Finit.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read(sd, rq, len) != len) {
|
||||||
|
warn("Failed reading reply from Finit, errno %d", errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (rq->cmd == INIT_CMD_NACK)
|
if (rq->cmd == INIT_CMD_NACK)
|
||||||
result = 1;
|
return -1;
|
||||||
else
|
|
||||||
result = 0;
|
return 0;
|
||||||
goto exit;
|
}
|
||||||
error:
|
|
||||||
perror("Failed communicating with finit");
|
int client_send(struct init_request *rq, ssize_t len)
|
||||||
exit:
|
{
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (client_request(rq, len))
|
||||||
|
rc = 255;
|
||||||
|
|
||||||
client_disconnect();
|
client_disconnect();
|
||||||
return result;
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int client_command(int cmd)
|
||||||
|
{
|
||||||
|
struct init_request rq = {
|
||||||
|
.magic = INIT_MAGIC,
|
||||||
|
.runlevel = getpid(),
|
||||||
|
.cmd = cmd,
|
||||||
|
};
|
||||||
|
|
||||||
|
return client_request(&rq, sizeof(rq));
|
||||||
}
|
}
|
||||||
|
|
||||||
svc_t *client_svc_iterator(int first)
|
svc_t *client_svc_iterator(int first)
|
||||||
{
|
{
|
||||||
int sd = -1;
|
|
||||||
struct init_request rq = {
|
struct init_request rq = {
|
||||||
.magic = INIT_MAGIC,
|
.magic = INIT_MAGIC,
|
||||||
.cmd = INIT_CMD_SVC_ITER,
|
.cmd = INIT_CMD_SVC_ITER,
|
||||||
};
|
};
|
||||||
static svc_t svc;
|
static svc_t svc;
|
||||||
|
|
||||||
sd = client_connect();
|
if (client_connect() == -1)
|
||||||
if (sd == -1)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (first)
|
if (first)
|
||||||
@@ -117,24 +178,22 @@ svc_t *client_svc_iterator(int first)
|
|||||||
|
|
||||||
return &svc;
|
return &svc;
|
||||||
error:
|
error:
|
||||||
perror("Failed communicating with finit");
|
warn("Failed communicating with finit, error %d", errno);
|
||||||
client_disconnect();
|
client_disconnect();
|
||||||
sd = -1;
|
sd = -1;
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
svc_t *do_cmd(int cmd, const char *arg)
|
static svc_t *do_find(int cmd, const char *arg)
|
||||||
{
|
{
|
||||||
struct init_request rq = {
|
struct init_request rq = {
|
||||||
.magic = INIT_MAGIC,
|
.magic = INIT_MAGIC,
|
||||||
.cmd = cmd,
|
.cmd = cmd,
|
||||||
};
|
};
|
||||||
static svc_t svc;
|
static svc_t svc;
|
||||||
int sd = -1;
|
|
||||||
|
|
||||||
sd = client_connect();
|
if (client_connect() == -1)
|
||||||
if (sd == -1)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
strlcpy(rq.data, arg, sizeof(rq.data));
|
strlcpy(rq.data, arg, sizeof(rq.data));
|
||||||
@@ -150,20 +209,19 @@ svc_t *do_cmd(int cmd, const char *arg)
|
|||||||
return &svc;
|
return &svc;
|
||||||
error:
|
error:
|
||||||
client_disconnect();
|
client_disconnect();
|
||||||
perror("Failed communicating with finit");
|
warn("Failed communicating with finit, error %d", errno);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
svc_t *client_svc_find(const char *arg)
|
svc_t *client_svc_find(const char *arg)
|
||||||
{
|
{
|
||||||
return do_cmd(INIT_CMD_SVC_FIND, arg);
|
return do_find(INIT_CMD_SVC_FIND, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
svc_t *client_svc_find_by_cond(const char *arg)
|
svc_t *client_svc_find_by_cond(const char *arg)
|
||||||
{
|
{
|
||||||
return do_cmd(INIT_CMD_SVC_FIND_BYC, arg);
|
return do_find(INIT_CMD_SVC_FIND_BYC, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+5
-1
@@ -1,6 +1,6 @@
|
|||||||
/* External client API, using UNIX domain socket.
|
/* External client API, using UNIX domain socket.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2015-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -29,8 +29,12 @@
|
|||||||
|
|
||||||
int client_connect (void);
|
int client_connect (void);
|
||||||
int client_disconnect (void);
|
int client_disconnect (void);
|
||||||
|
int client_socket (void);
|
||||||
|
|
||||||
|
int client_request (struct init_request *rq, ssize_t len);
|
||||||
int client_send (struct init_request *rq, ssize_t len);
|
int client_send (struct init_request *rq, ssize_t len);
|
||||||
|
int client_command (int cmd);
|
||||||
|
|
||||||
svc_t *client_svc_iterator (int first);
|
svc_t *client_svc_iterator (int first);
|
||||||
svc_t *client_svc_find (const char *arg);
|
svc_t *client_svc_find (const char *arg);
|
||||||
svc_t *client_svc_find_by_cond (const char *arg);
|
svc_t *client_svc_find_by_cond (const char *arg);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user