mirror of
https://github.com/troglobit/finit.git
synced 2026-10-12 10:12:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e9591d0a8 | ||
|
|
e3bcf9bf16 | ||
|
|
84fd3196b0 | ||
|
|
994e51e34f | ||
|
|
0a7814b391 | ||
|
|
73f72b39cf | ||
|
|
02e0aa7383 | ||
|
|
6528628b5c | ||
|
|
1480657982 | ||
|
|
33e378a345 | ||
|
|
b695b46a9d | ||
|
|
0e61ed727f | ||
|
|
e9d60a6c04 | ||
|
|
5e9edf9deb | ||
|
|
8ed2751ae1 | ||
|
|
7fec66dc09 | ||
|
|
75fa868a4b | ||
|
|
7b321de339 | ||
|
|
1691ebb292 | ||
|
|
c371c10455 | ||
|
|
a23e152f6b | ||
|
|
9210f2851e | ||
|
|
617609cbc5 | ||
|
|
b022916758 | ||
|
|
9a357b7aab | ||
|
|
ffd01b0276 | ||
|
|
2c95f091ee | ||
|
|
b75b107d6d | ||
|
|
1f2c1d2109 | ||
|
|
f328d24d01 | ||
|
|
211293a83d | ||
|
|
446f5bc8b8 | ||
|
|
0c6f748f2c | ||
|
|
a677b94ad9 | ||
|
|
6552cda605 | ||
|
|
3add682be3 | ||
|
|
abac31682d | ||
|
|
cfe915e6d5 | ||
|
|
ecf65ce44b | ||
|
|
0d742d6ae8 | ||
|
|
cf201a43df | ||
|
|
9245869e18 | ||
|
|
0f4a487328 | ||
|
|
f1b5b42919 | ||
|
|
f546129baf | ||
|
|
27451ac3f2 | ||
|
|
0a8f3a6250 | ||
|
|
70c4e7d774 | ||
|
|
5265eee25d | ||
|
|
4b06e1a49f | ||
|
|
6b9aa21509 | ||
|
|
990307fbc9 | ||
|
|
9d8a9b7fba | ||
|
|
bbc83eaa64 | ||
|
|
23d034f521 | ||
|
|
9a3148a49d | ||
|
|
8560103a24 | ||
|
|
7a75e34808 | ||
|
|
4d4fc10d57 | ||
|
|
003faae9e9 | ||
|
|
01a01d65c0 | ||
|
|
048302f06a | ||
|
|
74f0fcfccd | ||
|
|
3cfe0a33b8 | ||
|
|
465bc17ca4 | ||
|
|
d4889b435d | ||
|
|
49c0557ced | ||
|
|
6be16f2f6d | ||
|
|
bc8118d515 | ||
|
|
0c0e880f3f | ||
|
|
119e66a7e9 | ||
|
|
46ffa81f5c | ||
|
|
54701422a5 | ||
|
|
9d463e3823 | ||
|
|
56e558c960 | ||
|
|
dfaf351da1 | ||
|
|
a8433fcb7f | ||
|
|
2daa953bee | ||
|
|
3e3e9aadf5 | ||
|
|
dc873c6548 | ||
|
|
29bd7a504e | ||
|
|
a0685219cf | ||
|
|
13b107b7b1 | ||
|
|
409d68d05b | ||
|
|
ab62b5282b | ||
|
|
d02d65feeb | ||
|
|
9a0dea6aef | ||
|
|
7481505b1a | ||
|
|
8251f1a422 | ||
|
|
e269176a79 | ||
|
|
612f5a9385 | ||
|
|
4a2381eb6f | ||
|
|
0cae7d44dd | ||
|
|
340cae4afd | ||
|
|
6a89e60fc8 | ||
|
|
840d612fc2 | ||
|
|
60c676ab2d | ||
|
|
deada0fa89 | ||
|
|
7b501f255b | ||
|
|
052136cb99 | ||
|
|
742b8b72cc | ||
|
|
c37037c015 | ||
|
|
c32b5a749a | ||
|
|
7701718d7b | ||
|
|
eb4eca9607 | ||
|
|
cab94b81e8 | ||
|
|
5913217808 | ||
|
|
b49f55ab3d | ||
|
|
bf4a584e2e | ||
|
|
90a4df8d12 | ||
|
|
146bf55122 | ||
|
|
c1ed373398 | ||
|
|
5998342b3e | ||
|
|
9dc7b8a6b0 | ||
|
|
c221823654 | ||
|
|
248f7d3110 | ||
|
|
fe90ba5781 | ||
|
|
71c87734b7 | ||
|
|
cd060e8af3 | ||
|
|
33a7f123d7 | ||
|
|
d15e28ea6b | ||
|
|
836bfff08b | ||
|
|
59152b557c | ||
|
|
293b0ffa79 | ||
|
|
d5d9cd5645 | ||
|
|
2f281665af | ||
|
|
b00e7394f8 | ||
|
|
d5a5fffa52 | ||
|
|
4d24c34b28 | ||
|
|
355265651e | ||
|
|
41093df2a9 | ||
|
|
0a816d1fa4 | ||
|
|
3bfc0f0fca | ||
|
|
0aa6ee895c | ||
|
|
b1526fb2d6 | ||
|
|
b2624ac160 | ||
|
|
2c340f83ce | ||
|
|
337ee003bb | ||
|
|
791df0c986 | ||
|
|
f29e92be21 | ||
|
|
379a63fce4 | ||
|
|
b1f9a11809 | ||
|
|
2d9c63e48e | ||
|
|
d66455496a | ||
|
|
77cf72cb40 | ||
|
|
6cc587068b | ||
|
|
cc96e8908a | ||
|
|
adb25d52cd | ||
|
|
7d09567ec8 | ||
|
|
9130af1c77 | ||
|
|
cbea83b369 | ||
|
|
42cd8d284b | ||
|
|
72ebc92622 | ||
|
|
06adecaaea | ||
|
|
efc0592961 | ||
|
|
ed88469276 | ||
|
|
cbf96a1de0 | ||
|
|
cc979f27f1 | ||
|
|
fca5ce57ea | ||
|
|
53aa195ad5 | ||
|
|
e60211168e | ||
|
|
dc3ee9e467 | ||
|
|
6918f3b711 | ||
|
|
66020f48ea | ||
|
|
47b0d4cccf | ||
|
|
92c2efa655 | ||
|
|
b69aa8a8bd | ||
|
|
ca90bbfb04 | ||
|
|
0b5c555c7f | ||
|
|
6443995fc9 | ||
|
|
180faf8a40 | ||
|
|
0ebdd32f6b | ||
|
|
60bf858302 | ||
|
|
7c86b40190 | ||
|
|
4f3f140a09 | ||
|
|
10c24b1674 | ||
|
|
2b4f89ecd1 | ||
|
|
c42a6f2869 | ||
|
|
89bb609a7e | ||
|
|
da6298aecd | ||
|
|
576318cc29 | ||
|
|
0d7d331ad4 | ||
|
|
c886ecb5cc | ||
|
|
304a096877 | ||
|
|
064c7682fc | ||
|
|
58239b897b | ||
|
|
5281d82e80 | ||
|
|
5ff28c4dc6 | ||
|
|
f2218836af | ||
|
|
fbb3779d17 | ||
|
|
68f44f7a97 | ||
|
|
50e587f447 | ||
|
|
fb4c560196 | ||
|
|
8b5fa5eeaa | ||
|
|
88ec21e9cc | ||
|
|
84adec4006 | ||
|
|
19b2b2a279 | ||
|
|
e4163b7221 | ||
|
|
eaef302420 | ||
|
|
d5738da307 | ||
|
|
c9f930c7ad | ||
|
|
e2ee372b5d | ||
|
|
7ff7f93364 | ||
|
|
d5a95760ef | ||
|
|
24d1425b74 | ||
|
|
43d9e25ba7 | ||
|
|
f27998ae4f | ||
|
|
c8e0b6b9ef | ||
|
|
f7e8fccb2f | ||
|
|
7bbccb1213 | ||
|
|
d38c333e04 | ||
|
|
095f6b645c | ||
|
|
b4d10cbade | ||
|
|
5d703fd39e | ||
|
|
eaaf8d862e | ||
|
|
2468f11cd8 | ||
|
|
f8a6a119ac | ||
|
|
1889b88aab | ||
|
|
0d70023bfe | ||
|
|
41648a073b | ||
|
|
33cee0ba5f | ||
|
|
2235fb8352 | ||
|
|
eb9e94935e | ||
|
|
fb230f2137 | ||
|
|
6aa48a8b32 | ||
|
|
5b9cebbfd3 | ||
|
|
38791616e0 | ||
|
|
fede3fd2e1 | ||
|
|
a46a33238d | ||
|
|
afe0488bf2 | ||
|
|
ec5e42694d | ||
|
|
2e73563eea | ||
|
|
338521a748 | ||
|
|
6ae1083c99 | ||
|
|
846806747b | ||
|
|
8904ca993e | ||
|
|
efed0db16b | ||
|
|
11946f12d3 | ||
|
|
2ba359ed80 | ||
|
|
fafd524701 | ||
|
|
1ee6c9f46b | ||
|
|
a88eb82a68 | ||
|
|
a436a1c8cb | ||
|
|
7cb91854b0 | ||
|
|
939ae02a6a | ||
|
|
480d29175c | ||
|
|
ea68413512 | ||
|
|
4edfa9859e | ||
|
|
eb6291c943 | ||
|
|
756b7c3fb6 | ||
|
|
263aec292a | ||
|
|
5a946a4ea7 | ||
|
|
c90b4d797b | ||
|
|
6e7a2fb6d5 | ||
|
|
ddedcf77e8 | ||
|
|
924ec2ef80 | ||
|
|
a49f27c191 | ||
|
|
b41b4ce989 | ||
|
|
3d74e93fa2 | ||
|
|
443700a88e | ||
|
|
4701edef4c | ||
|
|
e6da0a22e7 | ||
|
|
7be2bbbc30 | ||
|
|
3e269c632f | ||
|
|
f2507d9fd7 | ||
|
|
e9f403bceb | ||
|
|
c03176c42a | ||
|
|
9707bfb103 | ||
|
|
11430f83c8 | ||
|
|
a22a794f55 | ||
|
|
5556501287 | ||
|
|
ab554568b2 | ||
|
|
b39a4498a3 | ||
|
|
dead2444e2 | ||
|
|
a58002588e | ||
|
|
28e101aaae | ||
|
|
6da8af8136 | ||
|
|
3069e753e1 | ||
|
|
aafd5c1010 | ||
|
|
2f51c8ea0d | ||
|
|
d1130473fc | ||
|
|
b682a5e4fe | ||
|
|
1fc0f36c6c | ||
|
|
5df5b22327 | ||
|
|
4153c7966d | ||
|
|
458d68533f | ||
|
|
63b5db38df | ||
|
|
2135639508 | ||
|
|
9c8cd6c024 | ||
|
|
450f498061 | ||
|
|
5769500afe | ||
|
|
dc61969164 | ||
|
|
6f0d448765 | ||
|
|
0c9b7a67e0 | ||
|
|
5db2fb2c32 | ||
|
|
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 |
@@ -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.
|
||||||
@@ -24,7 +24,8 @@ the maintainer(s) and make it easier for them to include your code.
|
|||||||
Coding Style
|
Coding Style
|
||||||
------------
|
------------
|
||||||
|
|
||||||
> **Tip:** Always submit code that follows the style of surrounding code!
|
> [!TIP]
|
||||||
|
> Always submit code that follows the style of surrounding code!
|
||||||
|
|
||||||
First of all, lines are allowed to be longer than 72 characters these
|
First of all, lines are allowed to be longer than 72 characters these
|
||||||
days. In fact, there exist no enforced maximum, but keeping it around
|
days. In fact, there exist no enforced maximum, but keeping it around
|
||||||
@@ -73,7 +74,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
|
||||||
|
|||||||
+22
-21
@@ -21,48 +21,49 @@ jobs:
|
|||||||
compiler: [gcc, clang]
|
compiler: [gcc, clang]
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
env:
|
env:
|
||||||
MAKEFLAGS: -j3
|
|
||||||
CC: ${{ matrix.compiler }}
|
CC: ${{ matrix.compiler }}
|
||||||
steps:
|
steps:
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get -y update
|
sudo apt-get -y update
|
||||||
sudo apt-get -y install pkg-config
|
sudo apt-get -y install pkg-config tree jq libuev-dev libite-dev
|
||||||
wget https://github.com/troglobit/libuev/releases/download/v2.3.2/libuev-2.3.2.tar.xz
|
- uses: actions/checkout@v4
|
||||||
wget https://github.com/troglobit/libite/releases/download/v2.3.1/libite-2.3.1.tar.gz
|
|
||||||
tar xf libuev-2.3.2.tar.xz
|
|
||||||
tar xf libite-2.3.1.tar.gz
|
|
||||||
(cd libuev-2.3.2 && ./configure --prefix=/usr && make && sudo make install-strip)
|
|
||||||
(cd libite-2.3.1 && ./configure --prefix=/usr && make && sudo make install-strip)
|
|
||||||
sudo ldconfig
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Static Finit
|
- name: Static Finit
|
||||||
run: |
|
run: |
|
||||||
./autogen.sh
|
./autogen.sh
|
||||||
./configure --prefix= --enable-static
|
./configure --prefix= --enable-static
|
||||||
make V=1
|
make -j3 V=1
|
||||||
- name: Regular Finit
|
- name: Regular Finit
|
||||||
run: |
|
run: |
|
||||||
./configure --prefix= --enable-x11-common-plugin --with-watchdog --with-keventd
|
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
|
||||||
make clean
|
--enable-x11-common-plugin --enable-testserv-plugin --with-watchdog \
|
||||||
make V=1
|
--with-keventd
|
||||||
- name: Install to ~/tmp and Inspect
|
make -j3 clean
|
||||||
|
make -j3 V=1
|
||||||
|
- name: Install to /tmp
|
||||||
run: |
|
run: |
|
||||||
DESTDIR=/tmp make install-strip
|
DESTDIR=/tmp make install-strip
|
||||||
tree /tmp
|
tree /tmp || true
|
||||||
|
- name: Check dependencies
|
||||||
|
run: |
|
||||||
ldd /tmp/sbin/finit
|
ldd /tmp/sbin/finit
|
||||||
size /tmp/sbin/finit
|
size /tmp/sbin/finit
|
||||||
ldd /tmp/sbin/initctl
|
ldd /tmp/sbin/initctl
|
||||||
size /tmp/sbin/initctl
|
size /tmp/sbin/initctl
|
||||||
ldd /tmp/sbin/reboot
|
ldd /tmp/sbin/reboot
|
||||||
size /tmp/sbin/reboot
|
size /tmp/sbin/reboot
|
||||||
/tmp/sbin/finit -h
|
- name: Verify starting and showing usage text
|
||||||
/tmp/sbin/initctl -h
|
run: |
|
||||||
|
sudo /tmp/sbin/finit -h
|
||||||
|
sudo /tmp/sbin/initctl -h
|
||||||
|
- name: Enable unprivileged userns (unshare)
|
||||||
|
run: |
|
||||||
|
sudo sysctl kernel.apparmor_restrict_unprivileged_userns=0
|
||||||
- name: Run Unit Tests
|
- name: Run Unit Tests
|
||||||
run: |
|
run: |
|
||||||
make -j1 distcheck
|
make check || (cat test/test-suite.log; false)
|
||||||
- name: Upload Test Results
|
- name: Upload Test Results
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: finit-test-${{ matrix.compiler }}
|
name: finit-test-${{ matrix.compiler }}
|
||||||
path: test/*
|
path: test/*.log
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- 'dev'
|
- 'dev'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
PROJECT_NAME: finit
|
PROJECT_NAME: finit
|
||||||
@@ -15,40 +16,59 @@ jobs:
|
|||||||
coverity:
|
coverity:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/cache@v2
|
- name: Fetch latest Coverity Scan MD5
|
||||||
id: coverity-toolchain-cache
|
id: var
|
||||||
with:
|
|
||||||
path: cov-analysis-linux64
|
|
||||||
key: ${{ runner.os }}-coverity
|
|
||||||
- name: Download Coverity Scan
|
|
||||||
if: steps.coverity-toolchain-cache.outputs.cache-hit != 'true'
|
|
||||||
env:
|
env:
|
||||||
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
|
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
wget -q https://scan.coverity.com/download/cxx/linux64 \
|
wget -q https://scan.coverity.com/download/cxx/linux64 \
|
||||||
--post-data "token=$TOKEN&project=${COVERITY_PROJ}" \
|
--post-data "token=$TOKEN&project=${COVERITY_PROJ}&md5=1" \
|
||||||
-O cov-analysis-linux64.tar.gz
|
-O coverity-latest.tar.gz.md5
|
||||||
mkdir cov-analysis-linux64
|
echo "md5=$(cat coverity-latest.tar.gz.md5)" | tee -a $GITHUB_OUTPUT
|
||||||
tar xzf cov-analysis-linux64.tar.gz --strip 1 -C cov-analysis-linux64
|
- uses: actions/cache@v4
|
||||||
|
id: cache
|
||||||
|
with:
|
||||||
|
path: coverity-latest.tar.gz
|
||||||
|
key: ${{ runner.os }}-coverity-${{ steps.var.outputs.md5 }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-coverity-${{ steps.var.outputs.md5 }}
|
||||||
|
${{ runner.os }}-coverity-
|
||||||
|
${{ runner.os }}-coverity
|
||||||
|
- name: Download Coverity Scan
|
||||||
|
env:
|
||||||
|
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
|
||||||
|
run: |
|
||||||
|
if [ ! -f coverity-latest.tar.gz ]; then
|
||||||
|
wget -q https://scan.coverity.com/download/cxx/linux64 \
|
||||||
|
--post-data "token=$TOKEN&project=${COVERITY_PROJ}" \
|
||||||
|
-O coverity-latest.tar.gz
|
||||||
|
else
|
||||||
|
echo "Latest Coverity Scan available from cache :-)"
|
||||||
|
md5sum coverity-latest.tar.gz
|
||||||
|
fi
|
||||||
|
mkdir coverity
|
||||||
|
tar xzf coverity-latest.tar.gz --strip 1 -C coverity
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get -y update
|
sudo apt-get -y update
|
||||||
sudo apt-get -y install pkg-config
|
sudo apt-get -y install pkg-config
|
||||||
wget https://github.com/troglobit/libuev/releases/download/v2.3.2/libuev-2.3.2.tar.xz
|
wget https://github.com/troglobit/libuev/releases/download/v2.4.0/libuev-2.4.0.tar.xz
|
||||||
wget https://github.com/troglobit/libite/releases/download/v2.3.1/libite-2.3.1.tar.gz
|
wget https://github.com/troglobit/libite/releases/download/v2.5.2/libite-2.5.2.tar.gz
|
||||||
tar xf libuev-2.3.2.tar.xz
|
tar xf libuev-2.4.0.tar.xz
|
||||||
tar xf libite-2.3.1.tar.gz
|
tar xf libite-2.5.2.tar.gz
|
||||||
(cd libuev-2.3.2 && ./configure --prefix=/usr && make && sudo make install-strip)
|
(cd libuev-2.4.0 && ./configure --prefix=/usr && make && sudo make install-strip)
|
||||||
(cd libite-2.3.1 && ./configure --prefix=/usr && make && sudo make install-strip)
|
(cd libite-2.5.2 && ./configure --prefix=/usr && make && sudo make install-strip)
|
||||||
sudo ldconfig
|
sudo ldconfig
|
||||||
- name: Build
|
- name: Configure
|
||||||
run: |
|
run: |
|
||||||
./autogen.sh
|
./autogen.sh
|
||||||
./configure --prefix= --enable-x11-common-plugin --with-watchdog --with-keventd
|
./configure --prefix= --enable-x11-common-plugin --with-watchdog --with-keventd
|
||||||
export PATH=`pwd`/cov-analysis-linux64/bin:$PATH
|
- name: Build
|
||||||
|
run: |
|
||||||
|
export PATH=`pwd`/coverity/bin:$PATH
|
||||||
cov-build --dir cov-int make
|
cov-build --dir cov-int make
|
||||||
- name: Submit result to Coverity Scan
|
- name: Submit results to Coverity Scan
|
||||||
env:
|
env:
|
||||||
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
|
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
@@ -61,3 +81,8 @@ jobs:
|
|||||||
--form version=trunk \
|
--form version=trunk \
|
||||||
--form description="${PROJECT_NAME} $(git rev-parse HEAD)" \
|
--form description="${PROJECT_NAME} $(git rev-parse HEAD)" \
|
||||||
https://scan.coverity.com/builds?project=${COVERITY_PROJ}
|
https://scan.coverity.com/builds?project=${COVERITY_PROJ}
|
||||||
|
- name: Upload build.log
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: coverity-build.log
|
||||||
|
path: cov-int/build-log.txt
|
||||||
|
|||||||
@@ -3,67 +3,60 @@ name: Release General
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- '[0-9]+.[0-9]+'
|
- '[0-9]+.[0-9]+*'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
name: Create GitHub release
|
name: Build and upload release tarball
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
outputs:
|
runs-on: ubuntu-latest
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
env:
|
||||||
release_id: ${{ steps.create_release.outputs.id }}
|
MAKEFLAGS: -j3
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
|
- name: Installing dependencies ...
|
||||||
|
run: |
|
||||||
|
sudo apt-get -y update
|
||||||
|
sudo apt-get -y install pkg-config jq libuev-dev libite-dev
|
||||||
|
- name: Setting release variables ...
|
||||||
|
id: build
|
||||||
|
run: |
|
||||||
|
ver=${GITHUB_REF#refs/tags/}
|
||||||
|
echo "ver=${ver}" >> $GITHUB_OUTPUT
|
||||||
|
if echo $ver | grep -qE '^[0-9]+\.[0-9]+(\.[0-9]+)?(-alpha|-beta|-rc)[0-9]*$'; then
|
||||||
|
echo "pre=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "pre=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
if echo $ver | grep -qE '^[0-9.]+\.[0-9.]+(\.[0-9]+)?$'; then
|
||||||
|
echo "latest=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "latest=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
- name: Creating Makefiles ...
|
||||||
|
run: |
|
||||||
|
./autogen.sh
|
||||||
|
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
|
||||||
|
--enable-x11-common-plugin --enable-testserv-plugin --with-watchdog \
|
||||||
|
--with-keventd
|
||||||
|
- name: Enable unprivileged userns (unshare)
|
||||||
|
run: |
|
||||||
|
sudo sysctl kernel.apparmor_restrict_unprivileged_userns=0
|
||||||
|
- name: Build release ...
|
||||||
|
run: |
|
||||||
|
make release || (cat test/test-suite.log; false)
|
||||||
|
ls -lF ../
|
||||||
|
mkdir -p artifacts/
|
||||||
|
mv ../*.tar.* artifacts/
|
||||||
- name: Extract ChangeLog entry ...
|
- name: Extract ChangeLog entry ...
|
||||||
# Hack to extract latest entry for body_path below
|
|
||||||
run: |
|
run: |
|
||||||
awk '/-----*/{if (x == 1) exit; x=1;next}x' ChangeLog.md \
|
awk '/-----*/{if (x == 1) exit; x=1;next}x' ChangeLog.md \
|
||||||
|head -n -1 > release.md
|
|head -n -1 > release.md
|
||||||
cat release.md
|
cat release.md
|
||||||
- name: Create release ...
|
- uses: ncipollo/release-action@v1
|
||||||
id: create_release
|
|
||||||
uses: actions/create-release@v1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
with:
|
||||||
tag_name: ${{ github.ref }}
|
name: Finit v${{ github.ref_name }}
|
||||||
release_name: Finit v${{ github.ref }}
|
prerelease: ${{ steps.build.outputs.pre }}
|
||||||
body_path: release.md
|
makeLatest: ${{ steps.build.outputs.latest }}
|
||||||
draft: false
|
bodyFile: "release.md"
|
||||||
prerelease: false
|
artifacts: "artifacts/*"
|
||||||
tarball:
|
|
||||||
name: Build and upload release tarball
|
|
||||||
needs: release
|
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Installing dependencies
|
|
||||||
run: |
|
|
||||||
sudo apt-get -y update
|
|
||||||
sudo apt-get -y install pkg-config
|
|
||||||
wget https://github.com/troglobit/libuev/releases/download/v2.3.2/libuev-2.3.2.tar.xz
|
|
||||||
wget https://github.com/troglobit/libite/releases/download/v2.3.1/libite-2.3.1.tar.gz
|
|
||||||
tar xf libuev-2.3.2.tar.xz
|
|
||||||
tar xf libite-2.3.1.tar.gz
|
|
||||||
(cd libuev-2.3.2 && ./configure --prefix=/usr && make && sudo make install-strip)
|
|
||||||
(cd libite-2.3.1 && ./configure --prefix=/usr && make && sudo make install-strip)
|
|
||||||
sudo ldconfig
|
|
||||||
- name: Creating Makefiles
|
|
||||||
run: |
|
|
||||||
./autogen.sh
|
|
||||||
./configure --prefix= --enable-x11-common-plugin --with-watchdog --with-keventd
|
|
||||||
- name: Building release
|
|
||||||
run: |
|
|
||||||
make release
|
|
||||||
ls -lF ../
|
|
||||||
mkdir -p artifacts/
|
|
||||||
mv ../*.tar.* artifacts/
|
|
||||||
- name: Uploading release artifacts
|
|
||||||
uses: skx/github-action-publish-binaries@release-0.15
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
releaseId: ${{ needs.release.outputs.release_id }}
|
|
||||||
args: artifacts/*
|
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
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@v4
|
||||||
|
- name: Check for any commits since last week
|
||||||
|
id: schedule
|
||||||
|
run: |
|
||||||
|
commits="$(git log --format=%H --since='1 week ago')"
|
||||||
|
if [ -n "$commits" ]; then
|
||||||
|
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@v4
|
||||||
|
- 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: Enable unprivileged userns (unshare)
|
||||||
|
run: |
|
||||||
|
sudo sysctl kernel.apparmor_restrict_unprivileged_userns=0
|
||||||
|
- name: Check dist tarball
|
||||||
|
run: |
|
||||||
|
ver=$(/tmp/sbin/initctl -V | awk '/Finit.*/ {print $2;}')
|
||||||
|
dir=finit-$ver/_build/sub
|
||||||
|
make -j1 distcheck || (cat $dir/test/test-suite.log; false)
|
||||||
@@ -14,6 +14,7 @@ GTAGS
|
|||||||
/autom4te.cache
|
/autom4te.cache
|
||||||
/aclocal.m4
|
/aclocal.m4
|
||||||
/ar-lib
|
/ar-lib
|
||||||
|
/backup/
|
||||||
/compile
|
/compile
|
||||||
/config.cache
|
/config.cache
|
||||||
/config.h
|
/config.h
|
||||||
@@ -36,6 +37,9 @@ GTAGS
|
|||||||
/test-driver
|
/test-driver
|
||||||
/test-suite.log
|
/test-suite.log
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
/.gdb_history
|
||||||
|
|
||||||
# TroglOS build system
|
# TroglOS build system
|
||||||
/.config
|
/.config
|
||||||
/.stamp
|
/.stamp
|
||||||
@@ -45,3 +49,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/:
|
||||||
+782
-32
@@ -3,6 +3,747 @@ Change Log
|
|||||||
|
|
||||||
All relevant changes are documented in this file.
|
All relevant changes are documented in this file.
|
||||||
|
|
||||||
|
[4.11][] - 2025-03-27
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
- Update documentation regarding transition from runlevel S to 2, how
|
||||||
|
run/tasks must "complete" before Finit can move to the next runlevel
|
||||||
|
- Improve argument handling in bundled getty when launching login
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Fix #432: allow services in `setup` state to be stopped. This fixes
|
||||||
|
a serious blocker introduced in 4.10 that prevented systems from
|
||||||
|
being rebooted when any service was in this state
|
||||||
|
- Fix fallback `SIGKILL` when stopping a service with `SIGTERM` does
|
||||||
|
not work. This fixes a serious issue with services not responding to
|
||||||
|
the default `SIGTERM`
|
||||||
|
- Fix pre/post/ready/cleanup script execution if service has an
|
||||||
|
optional `env:file` (leading `-`)
|
||||||
|
|
||||||
|
|
||||||
|
[4.10][] - 2025-03-03
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
- Add support for `cleanup:[0-3600,]script`, runs before service is
|
||||||
|
removed, unlike `post:script` that runs when service is stopped
|
||||||
|
- Improved entropy gathering in tertiary fallback of urandom plugin
|
||||||
|
- Reclassify `sysv` from run/task class to `service`
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Fix #427: using an external getty with custom login program cause
|
||||||
|
Finit to use login program as the getty command
|
||||||
|
- Fix #428: allow `sysctl` path to be set at build time
|
||||||
|
- Fix #429: regression in v4.9 causing Finit to segfault at shutdown
|
||||||
|
- Fix possible memory leak when sourcing a service `env:file`
|
||||||
|
- Finit now waits until all `post:scripts` have run before returning
|
||||||
|
OK to `initctl <reload|runlevel>`. This also applies to the new
|
||||||
|
`cleanup:scripts` introduced in this release
|
||||||
|
- RFC3154 conformance formatting fix for `/dev/kmsg` fallback logging
|
||||||
|
|
||||||
|
|
||||||
|
[4.9][] - 2025-02-15
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
> [!CAUTION]
|
||||||
|
> This release changes how Finit reacts to the exit status of `pre:`
|
||||||
|
> scripts. Finit will now no longer start the main process if its
|
||||||
|
> `pre:` script fails for any reason. So, if you have pre scripts that,
|
||||||
|
> e.g., create directories, make sure they are idempotent.
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
- Add individual timeout (optional) support for pre/post/ready scripts
|
||||||
|
- Add support for systems with broken RTC, i.e., those that at power-on
|
||||||
|
may reset the RTC to a random date instead of zero, issue #418
|
||||||
|
- Add support for detecting "in-container" when in `systemd-nspawn`
|
||||||
|
- Check exit status of `pre:` scripts, on failure drive service/sysv to
|
||||||
|
`crashed` state. (The exit code of `post:` scripts remain ignored)
|
||||||
|
- All pre/post/ready scripts are now also searched for in `$PATH`
|
||||||
|
- Reset color attributes and clear screen when starting up. This is
|
||||||
|
for boot loaders like GRUB, which leave background color artifacts
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Fix #415: only mark reverse-dependencies "dirty" if the main service
|
||||||
|
does not support SIGHUP. This helps avoid unnecessary restarts of
|
||||||
|
services that depend on a service that supports SIGHUP
|
||||||
|
- Fix #417: leaking inotify watchers in the cgroup subsystem
|
||||||
|
- Fix #421: add support for `nofail` mount option in `/etc/fstab`
|
||||||
|
- Fix #425: ordering bug in detecting .conf file changes to services
|
||||||
|
and `initctl reload`, or runlevel changes
|
||||||
|
- Fix `initctl touch` of template services, previously marking a
|
||||||
|
service created from a template as "dirty" did not take
|
||||||
|
- Fix unintended restart of template "siblings". I.e., `initctl touch`
|
||||||
|
of instantiated template service A affected B from same template
|
||||||
|
- Fix buggy `--with-rtc-date=DATE` configure option
|
||||||
|
- Fix kill on timeout of pre/post/ready scripts
|
||||||
|
|
||||||
|
|
||||||
|
[4.8][] - 2024-10-13
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
- Avoid remounting already mounted `/run` and `/tmp` directories. This
|
||||||
|
extends the existing support for detecting mounted directories to
|
||||||
|
include complex mount hierarchies are in use, overlayfs and tmpfs
|
||||||
|
mounts. Feature by Mathias Thore, Atlas Copco
|
||||||
|
- getty: trigger /etc/issue compat mode for Alpine Linux
|
||||||
|
- tmpfiles.d: skip `x11.conf` unless X11 common plugin is enabled
|
||||||
|
- tmpfiles.d: ignore x/X command, nos support for cleanup at runtime
|
||||||
|
- Drop debug mode `-D` from `udevd` in `hotplug.conf.in`, allow the
|
||||||
|
user to set this in `/etc/default/udevd` instead
|
||||||
|
- Certain initctl APIs at bootstrap are not supported, update warning
|
||||||
|
log to include command (number) for troubleshooting, issue #398
|
||||||
|
- Add support for hwrng to urandom plugin and check for empty seed
|
||||||
|
- Add `runparts -b` (batch mode) support, disables escape sequences
|
||||||
|
- New configure `--without-rc-local`, disables `/etc/rc.local` support
|
||||||
|
- New configure `--disable-cgroup` option, disables cgroup v2 detection
|
||||||
|
- `initctl show template@foo.conf` now shows how an enabled template
|
||||||
|
service has been evaluated by Finit, issue #411
|
||||||
|
- Extend `initctl` timeout connecting and waiting for Finit reply. The
|
||||||
|
previous 2 + 2 second poll timeout has proved to be too short on more
|
||||||
|
complex systems. Now a 15 + 15 second timeout is applied which should
|
||||||
|
be more resistant to temporary overload scenarios, issue #407
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Fix #397: system shutdown/reboot can block on console input if action
|
||||||
|
is started remotely (ssh). Caused by legacy TTY screen size probing,
|
||||||
|
removed from both bootstrap and shutdown/reboot
|
||||||
|
- Fix #400: both `HOOK_MOUNT_ERROR` and `sulogin()` fail to trigger on
|
||||||
|
either mount or `fsck` errors. Problem caused by unresolved status
|
||||||
|
from pipe, calling `pclose()` without extracting exit status
|
||||||
|
- Fix #402: `initctl touch` does not respect `-n` (no error) flag
|
||||||
|
- Fix #403: `initctl touch` does not support template services
|
||||||
|
- Fix #404: possible undefined behavior when `--with-fstab=no` is set
|
||||||
|
- Fix #405: `@console` getty does not work with `tty0 ttyS0`
|
||||||
|
- Fix #409: prevent tmpfiles from following symlinks for `L+` and `R`,
|
||||||
|
otherwise symlink targets would also be removed. Found and fixed by
|
||||||
|
Mathias Thore and Ming Liu, Atlas Copco
|
||||||
|
- Fix #414: Frr Zebra immediately restarts on `initctl stop zebra`.
|
||||||
|
The fix likely works for all Frr/Quagga services due to the way they
|
||||||
|
create and delete their pid file
|
||||||
|
- Cosmetic issue with `[ OK ]` messages being printed out of order at
|
||||||
|
shutdown/reboot. Caused by nested calls to `service_stop()`
|
||||||
|
- Cosmetic issue with duplicate "Restoring RTC" message at bootstrap
|
||||||
|
|
||||||
|
|
||||||
|
[4.7][] - 2024-01-07
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
- Silence "not available" messages for run/task/service with `nowarn`
|
||||||
|
- Update docs, `cgroup.root` workaround for `SCHED_RR` tasks
|
||||||
|
- Drop runlevels 0 and 6 from `keventd`, not needed at reboot/poweroff
|
||||||
|
- Mount `/dev/shm` with mode 1777 (sticky bit)
|
||||||
|
- Mount `/dev/mqueue` if available, inspiration from Alpine Linux
|
||||||
|
- Update Alpine Linux installer and configuration files, tested on
|
||||||
|
Alpine v3.19, some assembly still required
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Fix confusing warning message when tmpfiles.d fails to install symlink
|
||||||
|
- Fix tmpfiles.d legacy `/run/lock/subsys`, ordering
|
||||||
|
- Add missing `/var/tmp` and `/var/lock -> /run/lock` (tmpfiles.d)
|
||||||
|
- Fix #388: log redirection broken unless Finit runs in debug mode.
|
||||||
|
Found and fixed by Ryan Rorison
|
||||||
|
- Fix #389: must libc requires `libgen.h` for `basename()` function.
|
||||||
|
Reported and worked around with new `basenm()` function by Stargirl
|
||||||
|
- Fix #392: `service/foo/ready` condition reasserted on pidfile removal
|
||||||
|
|
||||||
|
|
||||||
|
[4.6][] - 2023-11-13
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
- Add support for service `notify:pid` and `readiness none` global
|
||||||
|
option to change how Finit expects readiness notification, issue #386
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Fix #383: dbus and runparts regression in Finit v4.5. The configure
|
||||||
|
script must expand `FINIT_RUNPATH_` before defining it in `config.h`
|
||||||
|
- Fix #384: service environment variables drop everything but the first
|
||||||
|
argument, e.g., `VAR="foo bar qux"` drops everything but `foo`
|
||||||
|
- Fix #385: internal conditions, e.g., `<int/bootstrap>` turn into flux
|
||||||
|
when leaving bootstrap, causing depending services to stop
|
||||||
|
- Fix #387: global environment variables declared with `set VAR=NAME` do
|
||||||
|
not drop leading `set `, causing `'set VAR'='NAME'` in env.
|
||||||
|
- Sanity check environment variables, for services and globally. Ensure
|
||||||
|
the variable name (key) does not contain spaces, or a leading `set `
|
||||||
|
|
||||||
|
|
||||||
|
[4.5][] - 2023-10-30
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
- Refactor `runparts` and `/etc/rc.local` to no longer block the main
|
||||||
|
loop, allowing `initctl` calls to interact with Finit. Issue #356
|
||||||
|
- Refactor the `run` stanza to no longer block the main loop, issue #362
|
||||||
|
- Allow `sulogin` with a user different from `root`, issue #357
|
||||||
|
- Allow disabling invocation of rescue mode from kernel command line
|
||||||
|
- Add `initctl -f` to force-skip asking Finit for existing services
|
||||||
|
when creating new services during bootstrap, e.g. `/etc/rc.local`
|
||||||
|
- `initctl runlevel` now returns `N S` instead of `N 10` in bootstrap
|
||||||
|
- `initctl runlevel N` during bootstrap is now allowed. It changes
|
||||||
|
the next runlevel to go to when bootstrap has completed. Effectively
|
||||||
|
overriding the `runlevel N` statement in `/etc/finit.conf`
|
||||||
|
- Improved logging on failure to `execvp()` a run/task/service, now
|
||||||
|
with `errno`, e.g., "No such file or directory" when the command
|
||||||
|
is missing from `$PATH`
|
||||||
|
- Add Bash completion support for `initctl`, configurable, issue #360
|
||||||
|
- Handle absolute path to `initctl [enable|disable]`, not supported
|
||||||
|
- Update `finit.conf(5)` man page with the recommended directory
|
||||||
|
hierarchy in `/etc/finit.d/`
|
||||||
|
- The `runparts` code has been split into `/libexec/finit/runparts`
|
||||||
|
- The `runparts` command now takes two options: `sysv` and `progress`.
|
||||||
|
The former ensures only `SNNfoo` and `KNNfoo` scripts are run.
|
||||||
|
- Add SysV Init Compatibility section to documentation
|
||||||
|
- Increased MAX path for commands, and arguments: 64 -> 256
|
||||||
|
- The bundled watchdog daemon no longer tries to log at startup, because
|
||||||
|
syslog is not available yet, any startup message leak to console
|
||||||
|
- Extend `if:` option with runtime evaluation of conditions. E.g., start
|
||||||
|
a task only `if:<run/foo/failure>` (here the run task 'foo' failed)
|
||||||
|
- Document new `if:`, `conflict:`, `nowarn` options for run/task/service
|
||||||
|
first introduced in v4.4
|
||||||
|
- Failure to open fstab should log to console, not just log to `/dev/kmsg`
|
||||||
|
- Rename `/lib/finit/system/*.conf`, added numbered prefix to ensure
|
||||||
|
proper execution order, e.g., `udevd` should always run first
|
||||||
|
- Plugins and bundled services: dbus, keventd, watchdogd, and runparts,
|
||||||
|
are now loaded *after* all services in `/lib/finit/system/`. A new
|
||||||
|
runtime-only path (for inspection) in `/run/finit/system/` is used
|
||||||
|
- Redirect `log*` output to console when `finit.debug` is enabled
|
||||||
|
- Assert `<int/container>` condition if we detect running in container
|
||||||
|
- Add support for mdev's netlink daemon mode, issue #367
|
||||||
|
- Add support for mdevd in `10-hotplug.conf`, preferred over plain mdev
|
||||||
|
- Disable modprobe plugin by default, udevd and mdev/mdevd loads modules
|
||||||
|
- Update documentation for run/task shell limitations, issue #376
|
||||||
|
- Update documentation regarding automount of `/run` and `/tmp`
|
||||||
|
- Update plugin documentation, add section about limited tmpfiles.d(5) support
|
||||||
|
- Skip registering service when `if:!name` matches a known service.
|
||||||
|
This allows conditional loading of alternative services, e.g. if udevd
|
||||||
|
is already loaded we do not need mdevd
|
||||||
|
- Drop `doc/bootstrap.md`, inaccurate and confusing to users
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Fix #227: believed to have been fixed in v4.3, the root cause was
|
||||||
|
actually that Finit was waiting for a process that was no longer in
|
||||||
|
the system. The fix is to ask the kernel on process-stop-timeout and
|
||||||
|
replay the lost PID so that Finit can continue with reboot/shutdown
|
||||||
|
- Fix #358: fix inotify events for `/etc/finit.conf`, improved log
|
||||||
|
messages and error handling
|
||||||
|
- Fix #361: cgroup move fail if run/task/services start as non-root.
|
||||||
|
Regression in the v4.4 release cycle while adding support for the
|
||||||
|
pre:/post:/ready: scripts. Now the latter scripts also properly run
|
||||||
|
in their correct cgroup
|
||||||
|
- Fix #366: document `fsck.*` kernel command line options and simplify
|
||||||
|
the configure flags `--enable-fsckfix` and `--enable-fastboot` to
|
||||||
|
only adjust the default values for the `fsck.*` options.
|
||||||
|
- Fix #371: swap load order of `/lib/finit/system/*` vs `/etc/finit.d/*`
|
||||||
|
We must run `10-hotplug.conf` first to ensure devices and modules are
|
||||||
|
up and loaded before the user's run/task/services are called. The order
|
||||||
|
at bootstrap is now saved in `/run/finit/conf.order` for inspection,
|
||||||
|
`/run/finit/exec.order` shows the start order of each process
|
||||||
|
- Fix #372: lost `udevadm` calls due to overloading
|
||||||
|
- Adjust final `udevadm settle` timeout: 5 -> 30 sec
|
||||||
|
- Fixed dbus plugin, the function that located `<pidfile> ...` in the
|
||||||
|
`dbus/system.conf` caused spurious line breaks which led to the
|
||||||
|
service not being loaded properly
|
||||||
|
- The `runparts` executor now skips backup files (`foo~`)
|
||||||
|
- The `runparts` stanza now properly appends ` start` to scripts that
|
||||||
|
start with `S[0-9]+`. This has been broken for a very long time.
|
||||||
|
- Fix #377: expand service `env:file` variables, allow constructs like:
|
||||||
|
|
||||||
|
RUNDIR=/var/run/somesvc
|
||||||
|
DAEMON_ARGS=--workdir $RUNDIR --other-args...
|
||||||
|
- Fix #378: warn on console if run/task times out during bootstrap
|
||||||
|
- Fix #378: add run/task support for `<!>` to allow transition from
|
||||||
|
bootstrap to multi-user runlevel even though task has not run yet.
|
||||||
|
- Fix #382: do not clear `<service/foo/STATE>` conditions on reload.
|
||||||
|
Introduced back in v4.3-rc2, 82cc10be8, the support for automatic
|
||||||
|
service conditions have had a weird and unintended behavior. Any
|
||||||
|
change in state (see `doc/svc-machine.png`) caused Finit to clear
|
||||||
|
out *all* previously acquired service conditions.
|
||||||
|
|
||||||
|
However, when moving between RUNNING and PAUSED states, a service
|
||||||
|
should not have its conditions cleared. The PAUSED state, seen
|
||||||
|
also by all conditions moving to FLUX, is only temporary while an
|
||||||
|
`initctl reload` is processed. If a service has no changes to be
|
||||||
|
applied it will move back to RUNNING.
|
||||||
|
|
||||||
|
Also, we cannot clear the service conditions because other run/task
|
||||||
|
or services may depend on it and clearing them would cause Finit to
|
||||||
|
`SIGTERM` these processes (since they are no longer eligible to run).
|
||||||
|
|
||||||
|
|
||||||
|
[4.4][] - 2023-05-15
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
> **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 also 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
|
[4.2][] - 2022-01-16
|
||||||
--------------------
|
--------------------
|
||||||
@@ -207,7 +948,7 @@ make sure to read the whole change log when upgrading.
|
|||||||
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
|
* A proper rescue mode has been added. It is started extremely early
|
||||||
and is protected with a bundled `suslogin`. Exiting rescue mode now
|
and is protected with a bundled `sulogin`. Exiting rescue mode now
|
||||||
brings up the system as a normal boot, as one expects
|
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
|
||||||
@@ -756,7 +1497,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
|
||||||
@@ -787,7 +1528,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
|
||||||
@@ -1038,37 +1779,46 @@ Major bug fix release.
|
|||||||
|
|
||||||
* Initial release
|
* Initial release
|
||||||
|
|
||||||
[UNRELEASED]: https://github.com/troglobit/finit/compare/4.2...HEAD
|
[UNRELEASED]: https://github.com/troglobit/finit/compare/4.11...HEAD
|
||||||
[4.2]: https://github.com/troglobit/finit/compare/4.1...4.2
|
[4.11]: https://github.com/troglobit/finit/compare/4.10...4.11
|
||||||
[4.1]: https://github.com/troglobit/finit/compare/4.0...4.1
|
[4.10]: https://github.com/troglobit/finit/compare/4.9...4.10
|
||||||
[4.0]: https://github.com/troglobit/finit/compare/3.1...4.0
|
[4.9]: https://github.com/troglobit/finit/compare/4.8...4.9
|
||||||
[3.1]: https://github.com/troglobit/finit/compare/3.0...3.1
|
[4.8]: https://github.com/troglobit/finit/compare/4.7...4.8
|
||||||
[3.0]: https://github.com/troglobit/finit/compare/2.4...3.0
|
[4.7]: https://github.com/troglobit/finit/compare/4.6...4.7
|
||||||
[2.4]: https://github.com/troglobit/finit/compare/2.3...2.4
|
[4.6]: https://github.com/troglobit/finit/compare/4.5...4.6
|
||||||
[2.3]: https://github.com/troglobit/finit/compare/2.2...2.3
|
[4.5]: https://github.com/troglobit/finit/compare/4.4...4.5
|
||||||
[2.2]: https://github.com/troglobit/finit/compare/2.1...2.2
|
[4.4]: https://github.com/troglobit/finit/compare/4.3...4.4
|
||||||
[2.1]: https://github.com/troglobit/finit/compare/2.0...2.1
|
[4.3]: https://github.com/troglobit/finit/compare/4.2...4.3
|
||||||
[2.0]: https://github.com/troglobit/finit/compare/1.12...2.0
|
[4.2]: https://github.com/troglobit/finit/compare/4.1...4.2
|
||||||
|
[4.1]: https://github.com/troglobit/finit/compare/4.0...4.1
|
||||||
|
[4.0]: https://github.com/troglobit/finit/compare/3.1...4.0
|
||||||
|
[3.1]: https://github.com/troglobit/finit/compare/3.0...3.1
|
||||||
|
[3.0]: https://github.com/troglobit/finit/compare/2.4...3.0
|
||||||
|
[2.4]: https://github.com/troglobit/finit/compare/2.3...2.4
|
||||||
|
[2.3]: https://github.com/troglobit/finit/compare/2.2...2.3
|
||||||
|
[2.2]: https://github.com/troglobit/finit/compare/2.1...2.2
|
||||||
|
[2.1]: https://github.com/troglobit/finit/compare/2.0...2.1
|
||||||
|
[2.0]: https://github.com/troglobit/finit/compare/1.12...2.0
|
||||||
[1.12]: https://github.com/troglobit/finit/compare/1.11...1.12
|
[1.12]: https://github.com/troglobit/finit/compare/1.11...1.12
|
||||||
[1.11]: https://github.com/troglobit/finit/compare/1.10...1.11
|
[1.11]: https://github.com/troglobit/finit/compare/1.10...1.11
|
||||||
[1.10]: https://github.com/troglobit/finit/compare/1.9...1.10
|
[1.10]: https://github.com/troglobit/finit/compare/1.9...1.10
|
||||||
[1.9]: https://github.com/troglobit/finit/compare/1.8...1.9
|
[1.9]: https://github.com/troglobit/finit/compare/1.8...1.9
|
||||||
[1.8]: https://github.com/troglobit/finit/compare/1.7...1.8
|
[1.8]: https://github.com/troglobit/finit/compare/1.7...1.8
|
||||||
[1.7]: https://github.com/troglobit/finit/compare/1.6...1.7
|
[1.7]: https://github.com/troglobit/finit/compare/1.6...1.7
|
||||||
[1.6]: https://github.com/troglobit/finit/compare/1.5...1.6
|
[1.6]: https://github.com/troglobit/finit/compare/1.5...1.6
|
||||||
[1.5]: https://github.com/troglobit/finit/compare/1.4...1.5
|
[1.5]: https://github.com/troglobit/finit/compare/1.4...1.5
|
||||||
[1.4]: https://github.com/troglobit/finit/compare/1.3...1.4
|
[1.4]: https://github.com/troglobit/finit/compare/1.3...1.4
|
||||||
[1.3]: https://github.com/troglobit/finit/compare/1.2...1.3
|
[1.3]: https://github.com/troglobit/finit/compare/1.2...1.3
|
||||||
[1.2]: https://github.com/troglobit/finit/compare/1.1...1.2
|
[1.2]: https://github.com/troglobit/finit/compare/1.1...1.2
|
||||||
[1.1]: https://github.com/troglobit/finit/compare/1.0...1.1
|
[1.1]: https://github.com/troglobit/finit/compare/1.0...1.1
|
||||||
[1.0]: https://github.com/troglobit/finit/compare/0.9...1.0
|
[1.0]: https://github.com/troglobit/finit/compare/0.9...1.0
|
||||||
[0.9]: https://github.com/troglobit/finit/compare/0.8...0.9
|
[0.9]: https://github.com/troglobit/finit/compare/0.8...0.9
|
||||||
[0.8]: https://github.com/troglobit/finit/compare/0.7...0.8
|
[0.8]: https://github.com/troglobit/finit/compare/0.7...0.8
|
||||||
[0.7]: https://github.com/troglobit/finit/compare/0.6...0.7
|
[0.7]: https://github.com/troglobit/finit/compare/0.6...0.7
|
||||||
[0.6]: https://github.com/troglobit/finit/compare/0.5...0.6
|
[0.6]: https://github.com/troglobit/finit/compare/0.5...0.6
|
||||||
[0.5]: https://github.com/troglobit/finit/compare/0.4...0.5
|
[0.5]: https://github.com/troglobit/finit/compare/0.4...0.5
|
||||||
[0.4]: https://github.com/troglobit/finit/compare/0.3...0.4
|
[0.4]: https://github.com/troglobit/finit/compare/0.3...0.4
|
||||||
[0.3]: https://github.com/troglobit/finit/compare/0.2...0.3
|
[0.3]: https://github.com/troglobit/finit/compare/0.2...0.3
|
||||||
[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
|
||||||
|
|||||||
@@ -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-2024 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
|
||||||
|
|||||||
+10
-1
@@ -1,5 +1,5 @@
|
|||||||
ACLOCAL_AMFLAGS = -I m4
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
SUBDIRS = man plugins src test
|
SUBDIRS = man plugins src system test tmpfiles.d
|
||||||
doc_DATA = README.md LICENSE contrib/finit.conf
|
doc_DATA = README.md LICENSE contrib/finit.conf
|
||||||
EXTRA_DIST = README.md LICENSE ChangeLog.md contrib/finit.conf
|
EXTRA_DIST = README.md LICENSE ChangeLog.md contrib/finit.conf
|
||||||
|
|
||||||
@@ -10,6 +10,10 @@ if DOC
|
|||||||
SUBDIRS += doc
|
SUBDIRS += doc
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if BASH
|
||||||
|
bashdir = $(BASH_DIR)
|
||||||
|
dist_bash_DATA = initctl
|
||||||
|
endif
|
||||||
# Compat hook
|
# Compat hook
|
||||||
install-dev:
|
install-dev:
|
||||||
@make -C src install-pkgincludeHEADERS
|
@make -C src install-pkgincludeHEADERS
|
||||||
@@ -29,3 +33,8 @@ 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 \
|
||||||
|
--with-bash-completion-dir=no
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
[![License Badge][]][License] [![GitHub Status]][GitHub] [![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)
|
||||||
* [Features](#features)
|
* [Features](#features)
|
||||||
* [Bootstrap](doc/bootstrap.md#bootstrap)
|
|
||||||
* [Runlevels](#runlevels)
|
* [Runlevels](#runlevels)
|
||||||
* [Syntax](doc/config.md#syntax)
|
* [Syntax](doc/config.md#syntax)
|
||||||
* [Runparts & /etc/rc.local](#runparts--etcrclocal)
|
* [Runparts & /etc/rc.local](#runparts--etcrclocal)
|
||||||
@@ -23,11 +22,10 @@ Introduction
|
|||||||
------------
|
------------
|
||||||
|
|
||||||
Fast init for Linux systems. Reverse engineered from the [EeePC
|
Fast init for Linux systems. Reverse engineered from the [EeePC
|
||||||
fastinit][] over ten years ago by [Claudio Matsuoka][] — "gaps filled
|
fastinit][] 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 of Finit booting [Alpine Linux (HowTo)](https://github.com/troglobit/finit/tree/master/contrib/alpine).*
|
||||||
|
|
||||||
Features include:
|
Features include:
|
||||||
|
|
||||||
@@ -37,7 +35,11 @@ Features include:
|
|||||||
* Process supervision similar to [systemd][]
|
* Process supervision similar to [systemd][]
|
||||||
* Sourcing environment files
|
* Sourcing environment files
|
||||||
* Conditions for network/process/custom dependencies
|
* Conditions for network/process/custom dependencies
|
||||||
|
* Readiness notification; PID files (native) for synchronizing system
|
||||||
|
startup, support for systemd [sd_notify()][], or [s6 style][] too
|
||||||
|
* Limited support for [tmpfiles.d(5)][] (no aging, attributes, or subvolumes)
|
||||||
* Pre/Post script actions
|
* Pre/Post script actions
|
||||||
|
* Rudimentary [templating support](doc/config.md#templating)
|
||||||
* Tooling to enable/disable services
|
* Tooling to enable/disable services
|
||||||
* Built-in getty
|
* Built-in getty
|
||||||
* Built-in watchdog, with support for hand-over to [watchdogd](https://troglobit.com/watchdogd.html)
|
* Built-in watchdog, with support for hand-over to [watchdogd](https://troglobit.com/watchdogd.html)
|
||||||
@@ -45,14 +47,27 @@ Features include:
|
|||||||
* Cgroups v2, both configuration and monitoring in `initctl top`
|
* Cgroups v2, both configuration and monitoring in `initctl top`
|
||||||
* Plugin support for customization
|
* Plugin support for customization
|
||||||
* Proper rescue mode with bundled `sulogin` for protected maintenance shell
|
* 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, e.g., for embedded systems, can be found in the following
|
||||||
|
> [Buildroot][] based examples: [myLinux][], [Infix][], or the plain
|
||||||
|
> [br2-finit-demo](https://github.com/troglobit/br2-finit-demo).
|
||||||
|
|
||||||
|
|
||||||
Example
|
Example
|
||||||
@@ -61,14 +76,26 @@ 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][].
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> As of Finit v4.4, `.conf` lines can be broken up using the standard
|
||||||
|
> UNIX continuation character (`\`), trailing comments are now also
|
||||||
|
> 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
|
||||||
@@ -97,6 +124,11 @@ service :8080 [2345] merecat -n -p 8080 /var/www -- Old web server
|
|||||||
#sysv [S] /etc/init.d/acpid -- Starting ACPI Daemon
|
#sysv [S] /etc/init.d/acpid -- Starting ACPI Daemon
|
||||||
#task [S] /etc/init.d/kbd -- 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
|
||||||
|
|
||||||
@@ -215,13 +247,51 @@ 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
|
||||||
|
```
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> 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
|
||||||
@@ -263,8 +333,8 @@ unnecessary overhead, which can be removed at build-time using:
|
|||||||
|
|
||||||
**Cgroups**
|
**Cgroups**
|
||||||
|
|
||||||
Finit supports cgroups v2 and comes with the following default groups
|
Finit supports cgroups v2 and comes with the following default groups in
|
||||||
in which services and user sessions are placed in:
|
which services and user sessions are placed in:
|
||||||
|
|
||||||
/sys/fs/cgroup
|
/sys/fs/cgroup
|
||||||
|-- init/ # cpu.weight:100
|
|-- init/ # cpu.weight:100
|
||||||
@@ -300,6 +370,11 @@ The `initctl` tool has three commands to help debug and optimize the
|
|||||||
setup and monitoring of cgroups. See the `ps`, `top`, and `cgroup`
|
setup and monitoring of cgroups. See the `ps`, `top`, and `cgroup`
|
||||||
commands for details.
|
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
|
||||||
------------------------
|
------------------------
|
||||||
@@ -320,8 +395,33 @@ Right after the runlevel change when all services have started properly,
|
|||||||
No configuration stanza in `/etc/finit.conf` is required for `rc.local`.
|
No configuration stanza in `/etc/finit.conf` is required for `rc.local`.
|
||||||
If it exists and is an executable shell script Finit calls it at the very
|
If it exists and is an executable shell script Finit calls it at the very
|
||||||
end of the boot, before calling the `HOOK_SYSTEM_UP`. See more on hooks
|
end of the boot, before calling the `HOOK_SYSTEM_UP`. See more on hooks
|
||||||
in [doc/plugins.md](doc/plugins.md#hooks), and about the system bootstrap
|
in [doc/plugins.md](doc/plugins.md#hooks).
|
||||||
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:
|
||||||
|
|
||||||
|
- `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
|
||||||
@@ -409,24 +509,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'
|
-1, --once Only one lap in commands like 'top'
|
||||||
-p, --plain Use plain table headings, no ctrl chars
|
-p, --plain Use plain table headings, no ctrl chars
|
||||||
-q, --quiet Silent, only return status of command
|
-q, --quiet Silent, only return status of command
|
||||||
-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
|
||||||
@@ -438,16 +539,21 @@ 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 clear <COND> Clear (deassert) user-defined conditions -usr/COND
|
||||||
cond status Show condition status, default cond command
|
cond status Show condition status, default cond command
|
||||||
cond dump Dump all conditions and their status
|
cond dump [TYPE] Dump all, or a type of, conditions and their status
|
||||||
|
|
||||||
log [NAME] Show ten last Finit, or NAME, messages from syslog
|
log [NAME] Show ten last Finit, or NAME, messages from syslog
|
||||||
start <NAME>[:ID] Start service by name, with optional ID
|
start <NAME>[:ID] Start service by name, with optional ID
|
||||||
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 by name (SIGHUP or restart)
|
reload <NAME>[:ID] Reload service as if .conf changed (SIGHUP or restart)
|
||||||
|
This allows restart of run/tasks that have already run
|
||||||
|
Note: Finit .conf file(s) are *not* reloaded!
|
||||||
restart <NAME>[:ID] Restart (stop/start) service by name
|
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
|
||||||
|
|
||||||
@@ -455,11 +561,15 @@ Commands:
|
|||||||
ps List processes based on cgroups
|
ps List processes based on cgroups
|
||||||
top Show top-like listing based on cgroups
|
top Show top-like listing based on cgroups
|
||||||
|
|
||||||
|
plugins List installed plugins
|
||||||
|
|
||||||
runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot
|
runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot
|
||||||
reboot Reboot system
|
reboot Reboot system
|
||||||
halt Halt system
|
halt Halt system
|
||||||
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
|
||||||
@@ -467,9 +577,10 @@ 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]
|
||||||
> the current runlevel these services will not be respawned automatically
|
> Even though it is possible to start services not belonging in the
|
||||||
> by Finit if they exit (crash). Hence, if the runlevel is 2, the below
|
> current runlevel these services will not be respawned automatically 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
|
The `status` command is the default, it displays a quick overview of all
|
||||||
@@ -478,24 +589,24 @@ scripting and documentation:
|
|||||||
|
|
||||||
```
|
```
|
||||||
alpine:~# initctl -p
|
alpine:~# initctl -p
|
||||||
PID IDENT STATUS RUNLEVELS DESCRIPTION
|
PID IDENT STATUS RUNLEVELS DESCRIPTION
|
||||||
======================================================================
|
======================================================================
|
||||||
1506 acpid running [--2345----] ACPI daemon
|
1506 acpid running [---2345----] ACPI daemon
|
||||||
1509 crond running [--2345----] Cron daemon
|
1509 crond running [---2345----] Cron daemon
|
||||||
1489 dropbear running [--2345----] Dropbear SSH daemon
|
1489 dropbear running [---2345----] Dropbear SSH daemon
|
||||||
1511 klogd running [S12345----] Kernel log daemon
|
1511 klogd running [S-12345----] Kernel log daemon
|
||||||
1512 ntpd running [--2345----] NTP daemon
|
1512 ntpd running [---2345----] NTP daemon
|
||||||
1473 syslogd running [S12345----] Syslog daemon
|
1473 syslogd running [S-12345----] Syslog daemon
|
||||||
|
|
||||||
alpine:~# initctl -pv
|
alpine:~# initctl -pv
|
||||||
PID IDENT STATUS RUNLEVELS COMMAND
|
PID IDENT STATUS RUNLEVELS COMMAND
|
||||||
======================================================================
|
======================================================================
|
||||||
1506 acpid running [--2345----] acpid -f
|
1506 acpid running [---2345----] acpid -f
|
||||||
1509 crond running [--2345----] crond -f -S $CRON_OPTS
|
1509 crond running [---2345----] crond -f -S $CRON_OPTS
|
||||||
1489 dropbear running [--2345----] dropbear -R -F $DROPBEAR_OPTS
|
1489 dropbear running [---2345----] dropbear -R -F $DROPBEAR_OPTS
|
||||||
1511 klogd running [S12345----] klogd -n $KLOGD_OPTS
|
1511 klogd running [S-12345----] klogd -n $KLOGD_OPTS
|
||||||
1512 ntpd running [--2345----] ntpd -n $NTPD_OPTS
|
1512 ntpd running [---2345----] ntpd -n $NTPD_OPTS
|
||||||
1473 syslogd running [S12345----] syslogd -n
|
1473 syslogd running [S-12345----] syslogd -n
|
||||||
```
|
```
|
||||||
|
|
||||||
The environment variables to each of the services above are read from,
|
The environment variables to each of the services above are read from,
|
||||||
@@ -520,7 +631,7 @@ Condition(s):
|
|||||||
User : root
|
User : root
|
||||||
Group : root
|
Group : root
|
||||||
Uptime : 2 hour 46 min 56 sec
|
Uptime : 2 hour 46 min 56 sec
|
||||||
Runlevels : [--2345----]
|
Runlevels : [---2345----]
|
||||||
Memory : 1.2M
|
Memory : 1.2M
|
||||||
CGroup : /system/dropbear cpu 0 [100, max] mem [--.--, max]
|
CGroup : /system/dropbear cpu 0 [100, max] mem [--.--, max]
|
||||||
|- 1485 dropbear -R -F
|
|- 1485 dropbear -R -F
|
||||||
@@ -591,14 +702,23 @@ and proposed extensions.
|
|||||||
[upstart]: https://upstart.ubuntu.com/
|
[upstart]: https://upstart.ubuntu.com/
|
||||||
[systemd]: https://www.freedesktop.org/wiki/Software/systemd/
|
[systemd]: https://www.freedesktop.org/wiki/Software/systemd/
|
||||||
[openrc]: https://www.gentoo.org/proj/en/base/openrc/
|
[openrc]: https://www.gentoo.org/proj/en/base/openrc/
|
||||||
|
[sd_notify()]: https://www.freedesktop.org/software/systemd/man/sd_notify.html
|
||||||
|
[s6 style]: https://skarnet.org/software/s6/notifywhenup.html
|
||||||
[run-parts(8)]: https://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
[run-parts(8)]: https://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
||||||
|
[tmpfiles.d(5)]: https://www.freedesktop.org/software/systemd/man/tmpfiles.d.html
|
||||||
[original finit]: http://helllabs.org/finit/
|
[original finit]: http://helllabs.org/finit/
|
||||||
[EeePC fastinit]: https://web.archive.org/web/20071208212450/http://wiki.eeeuser.com/boot_process:the_boot_process
|
[EeePC fastinit]: https://web.archive.org/web/20071208212450/http://wiki.eeeuser.com/boot_process:the_boot_process
|
||||||
[Claudio Matsuoka]: https://github.com/cmatsuoka
|
[Claudio Matsuoka]: https://github.com/cmatsuoka
|
||||||
[Joachim Wiberg]: https://troglobit.com
|
[Joachim Wiberg]: https://troglobit.com
|
||||||
|
[Buildroot]: https://buildroot.org
|
||||||
|
[Infix]: https://kernelkit.github.io
|
||||||
|
[finit.conf(5)]: https://man.troglobit.com/man5/finit.conf.5.html
|
||||||
[License]: https://en.wikipedia.org/wiki/MIT_License
|
[License]: 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
|
||||||
[GitHub]: https://travis-ci.org/troglobit/finit
|
[myLinux]: https://github.com/troglobit/myLinux/
|
||||||
[GitHub 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
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Run test suite with the correct configure params
|
||||||
|
|
||||||
|
make distclean
|
||||||
|
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
|
||||||
|
--enable-x11-common-plugin --with-watchdog --with-keventd
|
||||||
|
make -j17 clean check
|
||||||
+159
-25
@@ -1,10 +1,11 @@
|
|||||||
AC_INIT(Finit, 4.2, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/finit.html)
|
AC_INIT([Finit], [4.11-rc2], [https://github.com/troglobit/finit/issues],
|
||||||
|
[finit], [https://troglobit.com/projects/finit/])
|
||||||
AC_CONFIG_AUX_DIR(aux)
|
AC_CONFIG_AUX_DIR(aux)
|
||||||
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
|
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
|
||||||
AM_SILENT_RULES([yes])
|
AM_SILENT_RULES([yes])
|
||||||
|
|
||||||
AC_CONFIG_SRCDIR([src/finit.c])
|
AC_CONFIG_SRCDIR([src/finit.c])
|
||||||
AC_CONFIG_HEADER([config.h])
|
AC_CONFIG_HEADERS([config.h])
|
||||||
AC_CONFIG_FILES([Makefile
|
AC_CONFIG_FILES([Makefile
|
||||||
contrib/Makefile
|
contrib/Makefile
|
||||||
contrib/alpine/Makefile contrib/alpine/finit.d/Makefile contrib/alpine/finit.d/available/Makefile
|
contrib/alpine/Makefile contrib/alpine/finit.d/Makefile contrib/alpine/finit.d/available/Makefile
|
||||||
@@ -14,8 +15,10 @@ AC_CONFIG_FILES([Makefile
|
|||||||
man/Makefile
|
man/Makefile
|
||||||
plugins/Makefile
|
plugins/Makefile
|
||||||
src/Makefile
|
src/Makefile
|
||||||
test/test.env
|
system/Makefile system/10-hotplug.conf
|
||||||
test/Makefile])
|
test/test.env test/Makefile
|
||||||
|
test/lib/Makefile test/src/Makefile
|
||||||
|
tmpfiles.d/Makefile])
|
||||||
|
|
||||||
# Older versions of autoconf (<2.58) do not have AC_CONFIG_MACRO_DIR()
|
# Older versions of autoconf (<2.58) do not have AC_CONFIG_MACRO_DIR()
|
||||||
#m4_include([m4/plugin.m4])
|
#m4_include([m4/plugin.m4])
|
||||||
@@ -32,9 +35,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
|
||||||
@@ -65,12 +67,20 @@ AC_ARG_ENABLE(fsckfix,
|
|||||||
AS_HELP_STRING([--enable-fsckfix], [Run fsck fix mode (options: -yf) on filesystems listed in /etc/fstab]),,[
|
AS_HELP_STRING([--enable-fsckfix], [Run fsck fix mode (options: -yf) on filesystems listed in /etc/fstab]),,[
|
||||||
enable_fsckfix=no])
|
enable_fsckfix=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(cgroup,
|
||||||
|
AS_HELP_STRING([--disable-cgroup], [Disable cgroup v2 support, default: autodetect from /sys/fs/cgroup]),,[
|
||||||
|
enable_cgroup=yes])
|
||||||
|
|
||||||
AC_ARG_ENABLE(redirect,
|
AC_ARG_ENABLE(redirect,
|
||||||
AS_HELP_STRING([--disable-redirect], [Disable redirection of service output to /dev/null]),,[
|
AS_HELP_STRING([--disable-redirect], [Disable redirection of service output to /dev/null]),,[
|
||||||
enable_redirect=yes])
|
enable_redirect=yes])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(kernel_logging,
|
||||||
|
AS_HELP_STRING([--disable-kernel-logging], [Disable kernel logging to console (use 'quiet' instead!]),,[
|
||||||
|
enable_kernel_logging=yes])
|
||||||
|
|
||||||
AC_ARG_ENABLE(logrotate,
|
AC_ARG_ENABLE(logrotate,
|
||||||
AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp, default enabled]),,[
|
AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp]),,[
|
||||||
enable_logrotate=yes])
|
enable_logrotate=yes])
|
||||||
|
|
||||||
AC_ARG_ENABLE(doc,
|
AC_ARG_ENABLE(doc,
|
||||||
@@ -81,19 +91,37 @@ AC_ARG_ENABLE(contrib,
|
|||||||
AS_HELP_STRING([--disable-contrib], [Disable build and install of contrib section]),,[
|
AS_HELP_STRING([--disable-contrib], [Disable build and install of contrib section]),,[
|
||||||
enable_contrib=yes])
|
enable_contrib=yes])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE([rescue],
|
||||||
|
AS_HELP_STRING([--disable-rescue], [Disable potentially unsafe rescue mode]),,
|
||||||
|
[enable_rescue=yes])
|
||||||
|
|
||||||
# Check for extra plugins to enable
|
# 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], [no], [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([hotplug], [yes], [Setup and start udev or mdev hotplug daemon])
|
AC_PLUGIN([hook-scripts], [no], [Trigger script execution from hook points])
|
||||||
|
AC_PLUGIN([hotplug], [yes], [Start udevd or mdev kernel event datamon])
|
||||||
AC_PLUGIN([rtc], [yes], [Save and restore RTC using hwclock])
|
AC_PLUGIN([rtc], [yes], [Save and restore RTC using hwclock])
|
||||||
|
AC_PLUGIN([tty], [yes], [Automatically activate new TTYs, e.g. USB-to-serial])
|
||||||
AC_PLUGIN([urandom], [yes], [Setup and save random seed at boot/shutdown])
|
AC_PLUGIN([urandom], [yes], [Setup and save random seed at boot/shutdown])
|
||||||
|
AC_PLUGIN([testserv], [no], [Test plugin to start test serv daemon])
|
||||||
|
|
||||||
# Check for extra arguments or packages
|
# Check for extra arguments or packages
|
||||||
|
AC_ARG_WITH([bash-completion-dir],
|
||||||
|
AS_HELP_STRING([--with-bash-completion-dir[=PATH]], [Directory to install Bash completion, default: auto]),
|
||||||
|
[bash_dir=$withval], [bash_dir=yes])
|
||||||
|
|
||||||
|
AC_ARG_WITH(fstab,
|
||||||
|
AS_HELP_STRING([--with-fstab=FILE], [System default fstab, default $sysconfdir/fstab]),
|
||||||
|
[fstab=$withval], [fstab=yes])
|
||||||
|
|
||||||
AC_ARG_WITH(heading,
|
AC_ARG_WITH(heading,
|
||||||
AS_HELP_STRING([--with-heading=GREET], [Heading for boot progress. Default: PRETTY_NAME from /etc/os-release, fallback to "Finit vX.YY"]),
|
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])
|
||||||
@@ -123,7 +151,7 @@ AC_ARG_WITH(hostname,
|
|||||||
[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,
|
||||||
@@ -133,10 +161,29 @@ AC_ARG_WITH(random-seed,
|
|||||||
AC_ARG_WITH(keventd,
|
AC_ARG_WITH(keventd,
|
||||||
AS_HELP_STRING([--with-keventd], [Enable built-in keventd, default: no]),, [with_keventd=no])
|
AS_HELP_STRING([--with-keventd], [Enable built-in keventd, default: no]),, [with_keventd=no])
|
||||||
|
|
||||||
|
AC_ARG_WITH(sulogin,
|
||||||
|
AS_HELP_STRING([--with-sulogin@<:@=USER@:>@], [Enable built-in sulogin, optional USER to request password for (default root), default: no.]),[sulogin=$withval],[with_sulogin=no])
|
||||||
|
|
||||||
AC_ARG_WITH(watchdog,
|
AC_ARG_WITH(watchdog,
|
||||||
AS_HELP_STRING([--with-watchdog=[DEV]], [Enable built-in watchdog, default: /dev/watchdog]),
|
AS_HELP_STRING([--with-watchdog@<:@=DEV@:>@], [Enable built-in watchdog, default: /dev/watchdog]),
|
||||||
[watchdog=$withval], [with_watchdog=no watchdog=])
|
[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:SS", default "2000-01-01 00:00:00"]),
|
||||||
|
[rtc_date=$withval], [rtc_date=no])
|
||||||
|
|
||||||
|
AC_ARG_WITH(rtc-file,
|
||||||
|
AS_HELP_STRING([--with-rtc-file=FILE], [If RTC is missing, save and restore system clock from this file, default: no]),
|
||||||
|
[rtc_file=$withval], [rtc_file=no])
|
||||||
|
|
||||||
### Enable features ###########################################################################
|
### Enable features ###########################################################################
|
||||||
|
|
||||||
# Create config.h from selected features and fallback defaults
|
# Create config.h from selected features and fallback defaults
|
||||||
@@ -146,6 +193,12 @@ AS_IF([test "x$enable_auto_reload" = "xyes"], [
|
|||||||
AS_IF([test "x$enable_kernel_cmdline" = "xyes"], [
|
AS_IF([test "x$enable_kernel_cmdline" = "xyes"], [
|
||||||
AC_DEFINE(KERNEL_CMDLINE, 1, [Dumpster diving after init args from /proc/cmdline])])
|
AC_DEFINE(KERNEL_CMDLINE, 1, [Dumpster diving after init args from /proc/cmdline])])
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_kernel_logging" = "xyes"], [
|
||||||
|
AC_DEFINE(KERNEL_LOGGING, 1, [Keep kernel warn/err logs to console])])
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_cgroup" = "xyes"], [
|
||||||
|
AC_DEFINE(CGROUP2_ENABLED, 1, [Autodetect cgroup v2 support from /sys/fs/cgroup])])
|
||||||
|
|
||||||
AS_IF([test "x$enable_fastboot" = "xyes"], [
|
AS_IF([test "x$enable_fastboot" = "xyes"], [
|
||||||
AC_DEFINE(FAST_BOOT, 1, [Skip fsck check on filesystems listed in /etc/fstab])])
|
AC_DEFINE(FAST_BOOT, 1, [Skip fsck check on filesystems listed in /etc/fstab])])
|
||||||
|
|
||||||
@@ -159,9 +212,24 @@ AS_IF([test "x$enable_redirect" = "xyes"], [
|
|||||||
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.])])
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_rescue" != "xno"], [
|
||||||
|
AC_DEFINE([RESCUE_MODE], 1, [Define to enable support for rescue mode.])])
|
||||||
|
|
||||||
AM_CONDITIONAL(LOGROTATE, [test "x$enable_logrotate" = "xyes"])
|
AM_CONDITIONAL(LOGROTATE, [test "x$enable_logrotate" = "xyes"])
|
||||||
|
|
||||||
### With features ##############################################################################
|
### With features ##############################################################################
|
||||||
|
AS_IF([test "x$bash_dir" = "xyes"], [
|
||||||
|
PKG_CHECK_MODULES([BASH_COMPLETION], [bash-completion >= 2.0],
|
||||||
|
[BASH_DIR="$(pkg-config --variable=completionsdir bash-completion)"],
|
||||||
|
[BASH_DIR="$datadir/bash-completion/completions"])], [
|
||||||
|
BASH_DIR="$bash_dir"])
|
||||||
|
|
||||||
|
AS_IF([test "x$with_fstab" != "xno"], [
|
||||||
|
AS_IF([test "x$fstab" = "xyes"], [fstab=$sysconfdir/fstab])
|
||||||
|
AC_EXPAND_DIR(fstab_path, "$fstab")
|
||||||
|
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])])
|
||||||
@@ -177,10 +245,9 @@ AC_DEFINE_UNQUOTED(FINIT_RCSD, "$rcsd_path", [Finit rcS.d/, default /etc/finit.d
|
|||||||
AC_SUBST(FINIT_RCSD, "$rcsd_path")
|
AC_SUBST(FINIT_RCSD, "$rcsd_path")
|
||||||
|
|
||||||
AS_IF([test "x$with_rc_local" != "xno"], [
|
AS_IF([test "x$with_rc_local" != "xno"], [
|
||||||
AS_IF([test "x$rclocal" = "xyes"], [
|
AS_IF([test "x$rclocal" = "xyes"], [rclocal=$sysconfdir/rc.local])
|
||||||
rclocal=$sysconfdir/rc.local])])
|
AC_EXPAND_DIR(rclocal_path, "$rclocal")
|
||||||
AC_EXPAND_DIR(rclocal_path, "$rclocal")
|
AC_DEFINE_UNQUOTED(FINIT_RC_LOCAL, "$rclocal_path", [Compat SysV /etc/rc.local file to run last at boot.])])
|
||||||
AC_DEFINE_UNQUOTED(FINIT_RC_LOCAL, "$rclocal_path", [Compat SysV /etc/rc.local file to run last at boot.])
|
|
||||||
|
|
||||||
AS_IF([test "x$with_sysconfig" != "xno"], [
|
AS_IF([test "x$with_sysconfig" != "xno"], [
|
||||||
AS_IF([test "x$sysconfig" != "xdefault"], [
|
AS_IF([test "x$sysconfig" != "xdefault"], [
|
||||||
@@ -214,8 +281,26 @@ 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_UNQUOTED(RTC_TIMESTAMP_CUSTOM, "$rtc_date", [Custom RTC restore date, default: 2000-01-01 00:00])], [
|
||||||
|
rtc_date=""])
|
||||||
|
|
||||||
|
AS_IF([test "x$rtc_file" != "xno"], [
|
||||||
|
AS_IF([test "x$rtc_file" = "xyes"], [
|
||||||
|
rtc_file=/var/lib/misc/rtc])
|
||||||
|
AC_EXPAND_DIR(rtcfile_path, "$rtc_file")
|
||||||
|
AC_DEFINE_UNQUOTED(RTC_FILE, "$rtcfile_path", [Save and restore system time from this file if /dev/rtc is missing.])],[
|
||||||
|
AC_DEFINE_UNQUOTED(RTC_FILE, NULL)])
|
||||||
|
|
||||||
AS_IF([test "x$with_keventd" != "xno"], [with_keventd=yes])
|
AS_IF([test "x$with_keventd" != "xno"], [with_keventd=yes])
|
||||||
|
|
||||||
|
AS_IF([test "x$with_sulogin" != "xno"], [
|
||||||
|
AS_IF([test "x$sulogin" = "xyes"], [
|
||||||
|
sulogin=root])
|
||||||
|
with_sulogin=yes
|
||||||
|
AC_DEFINE_UNQUOTED(SULOGIN_USER, "$sulogin", [Built-in sulogin user, default: root])], [
|
||||||
|
sulogin=])
|
||||||
|
|
||||||
AS_IF([test "x$with_watchdog" != "xno"], [
|
AS_IF([test "x$with_watchdog" != "xno"], [
|
||||||
AS_IF([test "x$watchdog" = "xyes"], [
|
AS_IF([test "x$watchdog" = "xyes"], [
|
||||||
watchdog=/dev/watchdog])
|
watchdog=/dev/watchdog])
|
||||||
@@ -223,31 +308,70 @@ AS_IF([test "x$with_watchdog" != "xno"], [
|
|||||||
AC_DEFINE_UNQUOTED(WDT_DEVNODE, "$watchdog", [Built-in watchdog device node])], [
|
AC_DEFINE_UNQUOTED(WDT_DEVNODE, "$watchdog", [Built-in watchdog device node])], [
|
||||||
watchdog=])
|
watchdog=])
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_hook_scripts_plugin" != "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(BASH, [test "x$bash_dir" != "xno"])
|
||||||
|
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
||||||
AM_CONDITIONAL(KEVENTD, [test "x$with_keventd" != "xno"])
|
AM_CONDITIONAL(KEVENTD, [test "x$with_keventd" != "xno"])
|
||||||
|
AM_CONDITIONAL(SULOGIN, [test "x$with_sulogin" != "xno"])
|
||||||
AM_CONDITIONAL(WATCHDOGD, [test "x$with_watchdog" != "xno"])
|
AM_CONDITIONAL(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"])
|
||||||
|
|
||||||
|
# Workaround for as-of-yet unreleased runstatedir support, planned for
|
||||||
|
# autoconf 2.70, which some major distros have backported.
|
||||||
|
AS_IF([test -z "$runstatedir"], runstatedir="$localstatedir/run")
|
||||||
|
AC_SUBST(runstatedir)
|
||||||
|
|
||||||
# Override default libdir, used for plugins and rescue.conf
|
# 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(finit_runpath, "$runstatedir/finit/system")
|
||||||
|
AC_DEFINE_UNQUOTED(FINIT_RUNPATH_, "$finit_runpath", [Finit runtime dynamic system services])
|
||||||
|
|
||||||
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])
|
||||||
|
|
||||||
|
AC_EXPAND_DIR(bash_completion_dir, "$BASH_DIR")
|
||||||
|
AC_SUBST(BASH_DIR, "$bash_completion_dir")
|
||||||
|
|
||||||
AS_IF([test "$heading" = ""], [heading="<DEFAULT>"])
|
AS_IF([test "$heading" = ""], [heading="<DEFAULT>"])
|
||||||
AS_IF([test "$heading" = "no"], [heading="<NONE>"])
|
AS_IF([test "$heading" = "no"], [heading="<NONE>"])
|
||||||
|
|
||||||
|
RTC_DATE=$rtc_date
|
||||||
|
AS_IF([test "$rtc_date" = ""], [RTC_DATE="<DEFAULT>"])
|
||||||
|
AS_IF([test "$rtc_date" = "no"], [RTC_DATE="<DEFAULT>"])
|
||||||
|
|
||||||
# Generate all files
|
# Generate all files
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|
||||||
@@ -255,14 +379,16 @@ cat <<EOF
|
|||||||
|
|
||||||
------------------ Summary ------------------
|
------------------ Summary ------------------
|
||||||
$PACKAGE_NAME version $PACKAGE_VERSION
|
$PACKAGE_NAME version $PACKAGE_VERSION
|
||||||
Prefix................: $prefix
|
Prefix................: $(eval echo $prefix)
|
||||||
Exec prefix...........: $eprefix
|
Exec prefix...........: $(eval echo $exec_prefix)
|
||||||
|
Libdir................: $(eval echo $libdir)
|
||||||
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
|
||||||
Compat rc.local path..: $rclocal_path
|
Compat rc.local path..: `eval echo $rclocal`
|
||||||
System environment....: ${sysconfig_path:-${sysconfig}}
|
System environment....: ${sysconfig_path:-${sysconfig}}
|
||||||
Random seed path......: $random_path
|
Random seed path......: $random_path
|
||||||
C Compiler............: $CC $CFLAGS $CPPFLAGS $LDFLAGS $LIBS
|
C Compiler............: $CC $CFLAGS $CPPFLAGS $LDFLAGS $LIBS
|
||||||
@@ -271,16 +397,24 @@ cat <<EOF
|
|||||||
Behavior:
|
Behavior:
|
||||||
Boot heading..........: $heading
|
Boot heading..........: $heading
|
||||||
Plugins...............: $plugins
|
Plugins...............: $plugins
|
||||||
|
RTC restore date......: $RTC_DATE
|
||||||
|
RTC fallback file.....: $rtc_file
|
||||||
|
|
||||||
Optional features:
|
Optional features:
|
||||||
Install doc/..........: $enable_doc
|
Install doc/..........: $enable_doc
|
||||||
Install contrib/......: $enable_contrib
|
Install contrib/......: $enable_contrib
|
||||||
|
Bash completion.......: $bash_completion_dir
|
||||||
Built-in keventd......: $with_keventd
|
Built-in keventd......: $with_keventd
|
||||||
|
Built-in sulogin......: $with_sulogin $sulogin
|
||||||
Built-in watchdogd....: $with_watchdog $watchdog
|
Built-in watchdogd....: $with_watchdog $watchdog
|
||||||
Built-in logrotate....: $enable_logrotate
|
Built-in logrotate....: $enable_logrotate
|
||||||
|
Use cgroup v2.........: $enable_cgroup
|
||||||
|
Parse kernel cmdline..: $enable_kernel_cmdline
|
||||||
|
Keep kernel logging...: $enable_kernel_logging
|
||||||
Skip fsck check.......: $enable_fastboot
|
Skip fsck check.......: $enable_fastboot
|
||||||
Run fsck fix mode.....: $enable_fsckfix
|
Run fsck fix mode.....: $enable_fsckfix
|
||||||
Redirect output.......: $enable_redirect
|
Redirect output.......: $enable_redirect
|
||||||
|
Rescue mode...........: $enable_rescue
|
||||||
Default hostname......: $hostname
|
Default hostname......: $hostname
|
||||||
Default group.........: $group
|
Default group.........: $group
|
||||||
Default runlevel......: $runlevel
|
Default runlevel......: $runlevel
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
HowTo: Finit on Alpine Linux 3.4-3.6
|
HowTo: Finit on Alpine Linux 3.4...3.19
|
||||||
====================================
|
=======================================
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> https://troglobit.com/post/2021-02-12-alpine-linux-with-finit/
|
||||||
|
|
||||||
HowTo use Finit to boot an [Alpine Linux][] system. It is assumed that
|
HowTo use Finit to boot an [Alpine Linux][] system. It is assumed that
|
||||||
the user has already installed make, a compiler, C library header files,
|
the user has already installed make, a compiler, C library header files,
|
||||||
|
|||||||
@@ -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 --with-watchdog \
|
--enable-alsa-utils-plugin --without-watchdog \
|
||||||
--with-keventd
|
--with-keventd --with-sulogin
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "*** Building ..."
|
echo "*** Building ..."
|
||||||
@@ -35,4 +35,3 @@ fi
|
|||||||
echo
|
echo
|
||||||
echo "*** Done"
|
echo "*** Done"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
SUBDIRS = available
|
SUBDIRS = available
|
||||||
docsdir := @docdir@/contrib/alpine/finit.d
|
docsdir := @docdir@/contrib/alpine/finit.d
|
||||||
d_LINKS = acpid.conf crond.conf dropbear.conf getty.conf \
|
d_LINKS = acpid.conf crond.conf dropbear.conf getty.conf \
|
||||||
keymap.conf modules.conf ntpd.conf \
|
keymap.conf modules.conf ntpd.conf syslogd.conf
|
||||||
klogd.conf syslogd.conf
|
|
||||||
|
|
||||||
install-exec-hook:
|
install-exec-hook:
|
||||||
@$(MKDIR_P) $(DESTDIR)$(docsdir)/available
|
@$(MKDIR_P) $(DESTDIR)$(docsdir)/available
|
||||||
|
|||||||
@@ -1,4 +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 syslog.conf watchdog.conf
|
lxdm.conf modules.conf ntpd.conf syslogd.conf watchdog.conf
|
||||||
EXTRA_DIST = $(docs_DATA)
|
EXTRA_DIST = $(docs_DATA)
|
||||||
|
|||||||
@@ -4,4 +4,4 @@
|
|||||||
#module evdev
|
#module evdev
|
||||||
#module mousedev
|
#module mousedev
|
||||||
#module 8139cp
|
#module 8139cp
|
||||||
module softdog
|
#module softdog
|
||||||
|
|||||||
+35
-29
@@ -1,45 +1,53 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
if [ "x`id -u`" != "x0" ]; then
|
if [ "$(id -u)" != "0" ]; then
|
||||||
echo
|
printf "\n\e[1m*** This script must run as root\e[0m\n\n"
|
||||||
echo "*** This script must run as root"
|
|
||||||
echo
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# shellcheck disable=SC3037,SC3045,SC2154
|
||||||
|
yorn()
|
||||||
|
{
|
||||||
|
printf "\e[1m> %s (y/N)?\e[0m " "$*"
|
||||||
|
read -rn1 yorn
|
||||||
|
echo
|
||||||
|
|
||||||
|
if [ "$yorn" = "y" ] || [ "$yorn" = "Y" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
# Adjust base directory
|
# Adjust base directory
|
||||||
grep -q alpine Makefile 2>/dev/null
|
if grep -q contrib/alpine Makefile 2>/dev/null; then
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
cd ../..
|
cd ../..
|
||||||
elif [ ! -e configure.ac ]; then
|
fi
|
||||||
echo "*** Please run this script from the Finit base directory."
|
|
||||||
|
if [ ! -e configure.ac ]; then
|
||||||
|
printf "\n\e[1m*** Please run this script from the Finit base directory.\e[0m\n"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo
|
printf "\n\e[1mInstall Finit on Alpine Linux\n"
|
||||||
echo "*** Install Finit on Alpine Linux"
|
printf "========================================================================\e[0m\n"
|
||||||
echo "========================================================================"
|
printf "/sbin/finit - PID 1\n"
|
||||||
echo "/sbin/finit - PID 1"
|
printf "/lib/finit/plugins/* - All enabled Finit plugins\n"
|
||||||
echo "/lib/finit/plugins/* - All enabled Finit plugins"
|
printf "/etc/finit.conf - Finit configuration file\n"
|
||||||
echo "/etc/finit.conf - Finit configuration file"
|
printf "/etc/finit.d/ - Finit services\n"
|
||||||
echo "/etc/finit.d/ - Finit services"
|
|
||||||
echo
|
|
||||||
read -p "Do you want to continue (y/N)? " yorn
|
|
||||||
|
|
||||||
if [ "x$yorn" = "xy" -o "x$yorn" = "xY" ]; then
|
if yorn "Do you want to continue"; then
|
||||||
echo
|
printf "\n\e[1m*** Installing Finit files ...\e[0m\n"
|
||||||
echo "*** Installing Finit files ..."
|
|
||||||
make install
|
make install
|
||||||
cd /usr/share/doc/finit/contrib/alpine
|
cd /usr/share/doc/finit/contrib/alpine || exit 1
|
||||||
for file in finit.conf rc.local; do
|
for file in finit.conf rc.local; do
|
||||||
install -vbD $file /etc/$file
|
install -vbD $file /etc/$file
|
||||||
done
|
done
|
||||||
cp -va finit.d /etc/
|
cp -va finit.d /etc/
|
||||||
|
|
||||||
read -p "*** Install Finit as the system default Init (y/N)? " yorn
|
if yorn "Install Finit as the system default Init"; then
|
||||||
if [ "x$yorn" = "xy" -o "x$yorn" = "xY" ]; then
|
printf "\e[1m*** Updating /sbin/init symlink --> finit ...\e[0m\n"
|
||||||
echo "*** Updating /sbin/init symlink --> finit ..."
|
cd /sbin || exit 1
|
||||||
cd /sbin
|
|
||||||
rm init
|
rm init
|
||||||
ln -s finit init
|
ln -s finit init
|
||||||
|
|
||||||
@@ -48,10 +56,8 @@ if [ "x$yorn" = "xy" -o "x$yorn" = "xY" ]; then
|
|||||||
ln -s reboot shutdown
|
ln -s reboot shutdown
|
||||||
ln -s reboot suspend
|
ln -s reboot suspend
|
||||||
fi
|
fi
|
||||||
echo "*** Done"
|
printf "\n\e[1m*** Done\e[0m\n"
|
||||||
echo
|
echo
|
||||||
else
|
else
|
||||||
echo
|
printf "\n\e[1m*** Aborting install.\e[0m\n\n"
|
||||||
echo "*** Aborting install."
|
|
||||||
echo
|
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -20,8 +20,9 @@ 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
|
> [!TIP]
|
||||||
> the main section of Debian. So just install the -dev packages :)
|
> 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:
|
||||||
@@ -47,7 +48,8 @@ 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`
|
> [!NOTE]
|
||||||
|
> For the X Window system, you may need to `sudo apt install elogind`
|
||||||
> (Bullseye and later), followed by `initctl reload` to activate it (it
|
> (Bullseye and later), followed by `initctl reload` to activate it (it
|
||||||
> is enabled by default), and logout/login again. The elogind daemon
|
> is enabled by default), and logout/login again. The elogind daemon
|
||||||
> ensures a regular non-root user can start and interact with an X
|
> ensures a regular non-root user can start and interact with an X
|
||||||
|
|||||||
@@ -59,6 +59,3 @@ else
|
|||||||
echo "*** Use 'sudo contrib/debian/install.sh' later to install Finit"
|
echo "*** Use 'sudo contrib/debian/install.sh' later to install Finit"
|
||||||
echo
|
echo
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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 */
|
||||||
@@ -18,7 +18,7 @@ PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig ./configure \
|
|||||||
--sysconfdir=/etc --localstatedir=/var \
|
--sysconfdir=/etc --localstatedir=/var \
|
||||||
--enable-dbus-plugin --enable-x11-common-plugin \
|
--enable-dbus-plugin --enable-x11-common-plugin \
|
||||||
--enable-alsa-utils-plugin --with-watchdog \
|
--enable-alsa-utils-plugin --with-watchdog \
|
||||||
--with-keventd
|
--with-keventd --with-sulogin
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "*** Building ..."
|
echo "*** Building ..."
|
||||||
@@ -35,4 +35,3 @@ fi
|
|||||||
echo
|
echo
|
||||||
echo "*** Done"
|
echo "*** Done"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
Bootstrap
|
|
||||||
=========
|
|
||||||
|
|
||||||
1. Prepare emergency shell, if enabled
|
|
||||||
2. Set up initial signal handlers
|
|
||||||
3. Set up default $PATH early
|
|
||||||
4. Mount `/proc` and `/sys`
|
|
||||||
5. Check kernel command line for `debug` to figure out log level
|
|
||||||
6. Load all `.so` plugins
|
|
||||||
7. Call `fsck` on file systems listed in `/etc/fstab`
|
|
||||||
8. Populate `/dev` using either udev or mdev, depending on system type
|
|
||||||
9. Parse `/etc/finit.conf`
|
|
||||||
10. Start built-in watchdog, if enabled and `WDT_DEVNODE` exists. This
|
|
||||||
means any WDT that requires a kernel module need to be either
|
|
||||||
compiled into the kernel, or insmod'ed in `/etc/finit.conf`
|
|
||||||
11. Load all `/etc/finit.d/*.conf` files and set hostname
|
|
||||||
12. Remount `/` read-write if `/` is listed in `/etc/fstab` without `ro`
|
|
||||||
13. Call 1st level hooks, `HOOK_ROOTFS_UP`
|
|
||||||
14. Mount all file systems listed in `/etc/fstab` and swap, if available.
|
|
||||||
On mount error `HOOK_MOUNT_ERROR` is called. After mount, regardless
|
|
||||||
of error, `HOOK_MOUNT_POST` is called
|
|
||||||
15. Enable SysV init signals
|
|
||||||
16. Call 2nd level hooks, `HOOK_BASEFS_UP`
|
|
||||||
17. Cleanup stale files from `/tmp/*` et al, handled by `bootmisc` plugin
|
|
||||||
18. Load kernel params from `/etc/sysctl.d/*.conf`, `/etc/sysctl.conf`
|
|
||||||
et al. (Supports all locations that SysV init does.), handled by
|
|
||||||
`procps` plugin
|
|
||||||
19. Start all 'S' runlevel tasks and services
|
|
||||||
20. Bring up loopback interface and all `/etc/network/interfaces`, if
|
|
||||||
the `.conf` setting `network <SCRIPT>` is set, it is called instead
|
|
||||||
21. Call 3rd level hooks, `HOOK_NETWORK_UP`
|
|
||||||
22. If `runparts <DIR>` is set, [run-parts(8)][] is called on `<DIR>`
|
|
||||||
23. Switch to the configured runlevel from `/etc/finit.conf`, default 2.
|
|
||||||
At every runlevel change all `*.conf` files in `/etc/finit.d/` are
|
|
||||||
(re)loaded and new services, tasks, and blocking run commands are
|
|
||||||
started. Provided they are allowed in the new runlevel and all of
|
|
||||||
their conditions, if any, are set.
|
|
||||||
24. Call 4th level hooks, `HOOK_SVC_UP`
|
|
||||||
25. Call `/etc/rc.local`, if it exists and is an executable shell script
|
|
||||||
26. Call 5th level (last) hooks, `HOOK_SYSTEM_UP`
|
|
||||||
27. Start all configured TTYs
|
|
||||||
|
|
||||||
In (19) and (23) tasks and services defined in `/etc/finit.conf` and
|
|
||||||
`/etc/finit.d/*.conf` are started.
|
|
||||||
|
|
||||||
Notice the seven hook points that are called at various point in the
|
|
||||||
bootstrap process. This is where plugins can extend the boot in any
|
|
||||||
way they please. There are other hook points available, for more on
|
|
||||||
this, see [plugins.md](plugins.md).
|
|
||||||
|
|
||||||
For instance, at `HOOK_BASEFS_UP` a plugin could read an XML file from a
|
|
||||||
USB stick, convert/copy its contents to the system's `/etc/` directory,
|
|
||||||
well before all 'S' runlevel tasks are started. This could be used with
|
|
||||||
system images that are created read-only and all configuration is stored
|
|
||||||
on external media.
|
|
||||||
|
|
||||||
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
|
||||||
+48
-26
@@ -1,5 +1,5 @@
|
|||||||
Building
|
Building Finit
|
||||||
========
|
==============
|
||||||
|
|
||||||
* [Introduction](#introduction)
|
* [Introduction](#introduction)
|
||||||
* [Configure](#configure)
|
* [Configure](#configure)
|
||||||
@@ -17,20 +17,21 @@ optional plugins to enable. It depends on two external libraries:
|
|||||||
- [libuEv][], the event loop
|
- [libuEv][], the event loop
|
||||||
- [libite][] (-lite), much needed frog DNA
|
- [libite][] (-lite), much needed frog DNA
|
||||||
|
|
||||||
**NOTE:** Most free/open source software that uses `configure` default
|
> [!IMPORTANT]
|
||||||
to install to `/usr/local`. However, some Linux distributions do no
|
> Most free/open source software packages that use `configure` default
|
||||||
longer search that path for installed software, e.g. Fedora and Alpine
|
> to install to `/usr/local`. However, some Linux distributions do no
|
||||||
Linux. To get finit's configure script to find its dependencies you
|
> longer search that path for installed software, e.g. Fedora and Alpine
|
||||||
have to help the `pkg-config` tool a bit if you do not change the
|
> Linux. To get finit's configure script to find its dependencies you
|
||||||
default prefix path:
|
> have to help the `pkg-config` tool a bit if you do not change the
|
||||||
|
> default prefix path:
|
||||||
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 required 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
|
||||||
@@ -54,7 +55,7 @@ Below are a few of the main switches to configure:
|
|||||||
will be linked statically.
|
will be linked statically.
|
||||||
|
|
||||||
* `--enable-kernel-cmdline`: Enable Finit pre-4.1 parsing of init args from
|
* `--enable-kernel-cmdline`: Enable Finit pre-4.1 parsing of init args from
|
||||||
`/proc/cmdline`, this is not recommended since Finit may be running as the
|
`/proc/cmdline`, this is *not recommended* since Finit may be running as the
|
||||||
init for container apps that can see the host's `/proc` filesystem
|
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.
|
||||||
@@ -65,8 +66,20 @@ 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
|
||||||
-------
|
-------
|
||||||
@@ -74,8 +87,8 @@ Example
|
|||||||
First, unpack the archive:
|
First, unpack the archive:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ tar xf finit-4.1.tar.gz
|
$ tar xf finit-4.3.tar.gz
|
||||||
$ cd finit-4.1/
|
$ cd finit-4.3/
|
||||||
```
|
```
|
||||||
|
|
||||||
Then configure, build and install:
|
Then configure, build and install:
|
||||||
@@ -83,7 +96,7 @@ 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-keventd --with-watchdog
|
--with-keventd --with-watchdog
|
||||||
$ make
|
$ make
|
||||||
.
|
.
|
||||||
.
|
.
|
||||||
@@ -91,7 +104,7 @@ $ make
|
|||||||
$ DESTDIR=/tmp/finit make install
|
$ DESTDIR=/tmp/finit make install
|
||||||
```
|
```
|
||||||
|
|
||||||
In this example the [finit-4.1.tar.gz][1] archive is unpacked to the
|
In this example the [finit-4.3.tar.gz][1] archive is unpacked to the
|
||||||
user's home directory, configured, built and installed to a temporary
|
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
|
||||||
@@ -104,10 +117,11 @@ Linux config to:
|
|||||||
|
|
||||||
CONFIG_UEVENT_HELPER_PATH="/sbin/mdev"
|
CONFIG_UEVENT_HELPER_PATH="/sbin/mdev"
|
||||||
|
|
||||||
**Note:** If you run into problems starting Finit, take a look at
|
> [!TIP]
|
||||||
`finit.c`. One of the most common problems is a custom Linux kernel
|
> If you run into problems starting Finit, take a look at `finit.c`.
|
||||||
build that lack `CONFIG_DEVTMPFS`. Another is too much cruft in the
|
> One of the most common problems is a custom Linux kernel build that
|
||||||
system `/etc/fstab`.
|
> lack `CONFIG_DEVTMPFS`. Another is too much cruft in the system
|
||||||
|
> `/etc/fstab`.
|
||||||
|
|
||||||
|
|
||||||
Running
|
Running
|
||||||
@@ -146,17 +160,24 @@ 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.
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> In rescue mode `initctl` will not work, the same goes for `reboot`,
|
||||||
|
> `shutdown`, and `poweroff` commands, provided they are the Finit
|
||||||
|
> versions of these commands. Use the `-f` flag to force the action.
|
||||||
|
|
||||||
|
|
||||||
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"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Notice the `--` separator.
|
||||||
|
|
||||||
To debug startup issues, in particular issues with getty/login, add
|
To debug startup issues, in particular issues with getty/login, add
|
||||||
the following to your Finit .conf file:
|
the following to your Finit .conf file:
|
||||||
|
|
||||||
@@ -171,10 +192,11 @@ 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 options should be enabled on production
|
> [!CAUTION]
|
||||||
systems since they can potentially give a user root access.
|
> None of these options should be enabled on production systems since
|
||||||
|
> they can potentially give a user root access.
|
||||||
|
|
||||||
|
|
||||||
[1]: ftp://troglobit.com/finit/finit-4.1.tar.gz
|
[1]: ftp://troglobit.com/finit/finit-4.3.tar.gz
|
||||||
[libuEv]: https://github.com/troglobit/libuev
|
[libuEv]: https://github.com/troglobit/libuev
|
||||||
[libite]: https://github.com/troglobit/libite
|
[libite]: https://github.com/troglobit/libite
|
||||||
|
|||||||
+84
-14
@@ -4,19 +4,70 @@ Tips & Tricks with the kernel cmdline
|
|||||||
This document summarizes the different boot parameters that can be
|
This document summarizes the different boot parameters that can be
|
||||||
passed on the Linux kernel command line. Not limited to Finit.
|
passed on the Linux kernel command line. Not limited to Finit.
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> Remember to use `--` to separate kernel parameters from parameters to
|
||||||
|
> init. E.g., `init=/sbin/finit -- finit.debug rescue`
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
|
* `fsck.mode=<auto,force,skip>`, default: `auto`, unless built with
|
||||||
|
`configure --enable-fastboot`, in which case the default is `skip`
|
||||||
|
|
||||||
|
* `fsck.repair=<preen,yes,no>`, default: `preen`, unless built with
|
||||||
|
`configure --enable-fsckfix`, in which case the default is `yes`.
|
||||||
|
This configure option also sets `fsck.mode=force`, unless fastboot
|
||||||
|
is selected at the same time. I.e., the `--enable-fastboot` build
|
||||||
|
option overrides the `fsck.mode` default value.
|
||||||
|
|
||||||
|
* `finit.cond=foo[,bar[,baz]]`: set `<boot/foo>` condition, optionally
|
||||||
|
multiple conditions can be set using the same option, separated with a
|
||||||
|
comma. Alternatively, multiple `foo.cond=arg` can be given. Each will
|
||||||
|
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.
|
||||||
@@ -26,25 +77,44 @@ 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 rescue/maintenance mode. If your system comes with
|
* `rescue`: Start rescue/maintenance mode. If your system comes with
|
||||||
the bundled `sulogin` program (Finit, or from util-linux/Busybox),
|
the bundled `sulogin` program (Finit, or from util-linux/Busybox),
|
||||||
you will be given a root login to a maintenance shell. However, if
|
you will be given a root login to a maintenance shell. However, if
|
||||||
`sulogin` is missing, the file `/lib/finit/rescue.conf` is read and
|
`sulogin` is missing, the file `/lib/finit/rescue.conf` is read and
|
||||||
the system booted in a limited fallback mode. See [config.md][]
|
the system booted in a limited fallback mode. See [config.md][]
|
||||||
for more information.
|
for more information.
|
||||||
|
|
||||||
* `single`, or `S`: Single user mode, runlevel 1, in Finit. Useful to
|
This option can be disabled with `configure --without-rescue`
|
||||||
debug problems with the regular runlevel. All services and TTYs in
|
|
||||||
`[1]` will be started, so a `tty [1] @console nologin` configuration
|
**Note:** in this mode `initctl` will not work. Correct the problem
|
||||||
presents you with a root console without login.
|
and use `reboot -f` to force reboot.
|
||||||
|
|
||||||
|
* `single`, or `S`: Overrides the configured runlevel (default: 2) to go
|
||||||
|
to after bootstrap by forcing it to runlevel 1, this is also known
|
||||||
|
as single user mode. Useful to debug startup problems. All services
|
||||||
|
and TTYs in `[1]` will be started, so a `tty [1] @console nologin`
|
||||||
|
configuration presents you with a root console without login.
|
||||||
|
|
||||||
|
* `1-9`, except `6`: override the configured `runlevel`. Like the `S`
|
||||||
|
and `rescue`, giving a single number on the kernel command line tells
|
||||||
|
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)][].
|
For more on kernel boot parameters, see the man page [bootparam(7)][].
|
||||||
|
|
||||||
[config.md][]: config.md#rescue-mode
|
[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
|
||||||
|
|||||||
+92
-30
@@ -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"*
|
||||||
@@ -27,6 +27,16 @@ specified separated by comma. Multiple conditions are logically AND'ed
|
|||||||
during evaluation, i.e. all conditions must be satisfied in order for a
|
during evaluation, i.e. all conditions must be satisfied in order for a
|
||||||
service to run.
|
service to run.
|
||||||
|
|
||||||
|
A special syntax, using a leading `!` in run/task/service conditions,
|
||||||
|
denote if a:
|
||||||
|
|
||||||
|
- service does not support `SIGHUP`
|
||||||
|
- run/task should not block runlevel changes (i.e., bootstrap)
|
||||||
|
|
||||||
|
Finit guarantees by default that all run/tasks run (at least) once
|
||||||
|
per runlevel. For most tasks this is a good default, for example
|
||||||
|
checking SSH host keys or loading keymap. However, for conditions
|
||||||
|
that are unlikely to happen it is not. (See example below.)
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
@@ -35,22 +45,41 @@ 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
|
> [!IMPORTANT]
|
||||||
asserted. I.e., if the Zebra process above stops or restarts, netd
|
> Conditions also stop services when a condition is no longer asserted.
|
||||||
will also stop or restart.
|
> I.e., if the `zebra` process above stops or restarts, `netd` will also
|
||||||
|
> stop or restart.
|
||||||
|
|
||||||
|
Another example is `dropbear`, it does not support `SIGHUP`, but we can
|
||||||
|
also see optional sourcing of arguments from an environment file:
|
||||||
|
|
||||||
|
service [2345789] <!> env:-/etc/default/dropbear dropbear -F -R $DROPBEAR_ARGS -- Dropbear SSH daemon
|
||||||
|
|
||||||
|
Finally, the weird "block runlevel changes" example. Here we see what
|
||||||
|
happens when Finit receives `SIGPWR`, sent from a power daemon like
|
||||||
|
[powstatd(8)][]. A condition is asserted and a user can set up their
|
||||||
|
own task to act on it. We do not want this task to block Finit from
|
||||||
|
moving to the next runlevel after bootstrap, so we set `<!>`:
|
||||||
|
|
||||||
|
task [S0123456789] <!sys/pwr/fail> name:pwrfail initctl poweroff -- Power failure, shutting down
|
||||||
|
|
||||||
|
|
||||||
Triggering
|
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:
|
||||||
@@ -78,24 +107,49 @@ on this, see [Internals](#internals).) Thus, after a reconfiguration it
|
|||||||
is up to the "owner" of the condition to convey the new (or possibly
|
is up to the "owner" of the condition to convey the new (or possibly
|
||||||
unchanged) state of it.
|
unchanged) state of it.
|
||||||
|
|
||||||
> **Note:** For `pid/` conditions it is expected that services "touch"
|
|
||||||
> or recreate their PID file on `SIGHUP`.
|
|
||||||
|
|
||||||
Static (one-shot) conditions, like `usr/`, never enter the `flux` state.
|
Static (one-shot) conditions, like `usr/`, never enter the `flux` state.
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> For `pid/` conditions it is expected that the service reassert, i.e.,
|
||||||
|
> "touch" or recreate, their PID file on `SIGHUP`. This can be done by
|
||||||
|
> calling `utimensat()` on the PID file. Provided, of course, that the
|
||||||
|
> service supports reloading on `SIGHUP`, otherwise it will be restarted
|
||||||
|
> by Finit when they instead exit on the signal. For such services, use
|
||||||
|
> `<!>` to tell Finit the service does not support `SIGHUP`.
|
||||||
|
|
||||||
|
|
||||||
Built-in Conditions
|
Built-in Conditions
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
Finit comes with a set of plugins for conditions: `pidfile`, `netlink`,
|
Finit comes with a set of plugins for conditions:
|
||||||
`sys`, and `usr`. The `pidfile` plugin (recursively) watches `/run/`
|
|
||||||
(recursively) for PID files created by the monitored services, and sets
|
- `devmon` (built-in)
|
||||||
a corresponding condition in the `pid/` namespace. Similarly, the
|
- `netlink`
|
||||||
`netlink` plugin provides basic conditions for when an interface is
|
- `pidfile`
|
||||||
brought up/down and when a default route (gateway) is set, in the `net/`
|
- `sys`
|
||||||
namespace. The `sys` and `usr` plugins monitor are passive condition
|
- `usr`
|
||||||
monitors where the action is provided by `keventd`, signal handlers,
|
|
||||||
and in the case of `usr`, the end-user via the `initctl` tool
|
The `devmon` (built-in) plugin monitors `/dev` and `/dev/dir` for device
|
||||||
|
nodes being created and removed. It is active only when a run, task, or
|
||||||
|
service has declared a `<dev/foo>` or `<dev/dir/bar>` condition.
|
||||||
|
|
||||||
|
The `pidfile` plugin (recursively) watches `/run/` (recursively) for PID
|
||||||
|
files created by the monitored services, and sets a corresponding
|
||||||
|
condition in the `pid/` namespace.
|
||||||
|
|
||||||
|
Similarly, the `netlink` plugin provides basic conditions for when an
|
||||||
|
interface is brought up/down and when a default route (gateway) is set,
|
||||||
|
in the `net/` namespace.
|
||||||
|
|
||||||
|
The `sys` and `usr` plugins monitor are passive condition monitors where
|
||||||
|
the action is provided by `keventd`, signal handlers, and in the case of
|
||||||
|
`usr`, the end-user via the `initctl` tool.
|
||||||
|
|
||||||
|
Additionally, the various states of a run/task/sysv/service can also be
|
||||||
|
used as conditions, the image above shows the state names. The syntax
|
||||||
|
for a `service` type process: `<service/foo/STATE>`. The other types,
|
||||||
|
in particular run/task/sysv, there are the additional states `success`
|
||||||
|
and `failure`.
|
||||||
|
|
||||||
With the example listed above, finit does not start the `/sbin/netd`
|
With the example listed above, finit does not start the `/sbin/netd`
|
||||||
daemon until `setupd` and `zebra` has started *and* created their PID
|
daemon until `setupd` and `zebra` has started *and* created their PID
|
||||||
@@ -114,14 +168,19 @@ Built-in conditions:
|
|||||||
- `net/<IFNAME>/exist`
|
- `net/<IFNAME>/exist`
|
||||||
- `net/<IFNAME>/up`
|
- `net/<IFNAME>/up`
|
||||||
- `net/<IFNAME>/running`
|
- `net/<IFNAME>/running`
|
||||||
|
- `service/<NAME[:ID]>/<STATE>`
|
||||||
|
- `{run, task, sysv}/<NAME[:ID]>/{<STATE>, success, failure}`
|
||||||
- `sys/pwr/ac`
|
- `sys/pwr/ac`
|
||||||
- `sys/pwr/fail`
|
- `sys/pwr/fail`
|
||||||
- `sys/key/ctrlaltdel`
|
- `sys/key/ctrlaltdel`
|
||||||
- `usr/foo`
|
- `usr/foo`
|
||||||
|
- `boot/arg`
|
||||||
|
- `dev/node` and `dev/dir/node`
|
||||||
|
|
||||||
**Note:** `up` means administratively up, the interface flag `IFF_UP`.
|
> [!NOTE]
|
||||||
`running` is the `IFF_RUNNING` flag, meaning operatively up. The
|
> Here, `up` means administratively up, the interface flag `IFF_UP`.
|
||||||
difference is that `running` tells if the NIC has link.
|
> `running` is the `IFF_RUNNING` flag, meaning operatively up. The
|
||||||
|
> difference is that `running` tells if the NIC has link.
|
||||||
|
|
||||||
|
|
||||||
Composition
|
Composition
|
||||||
@@ -153,8 +212,9 @@ the service stanza for the daemon. It is far from optimal since any
|
|||||||
synchronization of depending services may fail due to the daemon not
|
synchronization of depending services may fail due to the daemon not
|
||||||
having reinitialized/created their IPC sockets, or similar.
|
having reinitialized/created their IPC sockets, or similar.
|
||||||
|
|
||||||
> **Note:** in versions of Finit prior to v4, the PID conditions were
|
> [!NOTE]
|
||||||
> called 'svc' conditions, and they were far more complex.
|
> In versions of Finit prior to v4, the PID conditions were called 'svc'
|
||||||
|
> conditions, and they were far more complex.
|
||||||
|
|
||||||
|
|
||||||
Debugging
|
Debugging
|
||||||
@@ -163,7 +223,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.
|
||||||
@@ -231,3 +291,5 @@ Therefore, any plugin that supplies Finit with conditions must ensure
|
|||||||
that their state is updated after each reconfiguration. This can be
|
that their state is updated after each reconfiguration. This can be
|
||||||
done by binding to the `HOOK_SVC_RECONF` hook. For an example of how
|
done by binding to the `HOOK_SVC_RECONF` hook. For an example of how
|
||||||
to do this, see `plugins/pidfile.c`.
|
to do this, see `plugins/pidfile.c`.
|
||||||
|
|
||||||
|
[powstatd(8)]: https://manpages.ubuntu.com/manpages/trusty/en/man8/powstatd.8.html
|
||||||
|
|||||||
+833
-117
File diff suppressed because it is too large
Load Diff
+3
-2
@@ -34,8 +34,9 @@ build time:
|
|||||||
./configure --with-rcsd=/etc/init.d --with-config=/etc/init.d/init.conf
|
./configure --with-rcsd=/etc/init.d --with-config=/etc/init.d/init.conf
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Note:** remember `--prefix` et al as well, the default is likely
|
> [!IMPORTANT]
|
||||||
> *not* what you want. See the [build docs][1] for details.
|
> Remember `--prefix` et al as well, the default is likely *not* what
|
||||||
|
> you want. See the [build docs][1] for details.
|
||||||
|
|
||||||
The resulting directory structure is depicted below. Please notice how
|
The resulting directory structure is depicted below. Please notice how
|
||||||
`/etc/finit.conf` now resides in the same sub-directory as a non-symlink
|
`/etc/finit.conf` now resides in the same sub-directory as a non-symlink
|
||||||
|
|||||||
+159
-29
@@ -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.
|
||||||
@@ -27,33 +28,95 @@ For your convenience a set of *optional* plugins are available:
|
|||||||
system and runs at `HOOK_BASEFS_UP`. The `/var`, `/run`, and `/dev`
|
system and runs at `HOOK_BASEFS_UP`. The `/var`, `/run`, and `/dev`
|
||||||
file systems must be writable for this plugin to work.
|
file systems must be writable for this plugin to work.
|
||||||
|
|
||||||
Note: On an embedded system both `/var` and `/run` can be `tmpfs` RAM
|
This plugin is a wrapper for the [tmpfiles.d(5)][] implementation that
|
||||||
disks and `/dev` is usually a `devtmpfs`. This must be defined in the
|
Finit has. Capable but limited: no aging, attributes, or subvolumes.
|
||||||
`/etc/fstab` file and in the Linux kernel config.
|
|
||||||
|
By default, `/lib/finit/tmpfiles.d` carries all the default .conf
|
||||||
|
files distributed with Finit. It is read first but can be overridden
|
||||||
|
by any of the standard tmpfiles.d directories, e.g. `/etc/tmpfiles.d`.
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> On an embedded system both `/var` and `/run` can be `tmpfs` RAM
|
||||||
|
> disks and `/dev` is usually a `devtmpfs`. This must be defined in
|
||||||
|
> the `/etc/fstab` file and in the Linux kernel config.
|
||||||
|
|
||||||
* *dbus.so*: Setup and start system message bus, D-Bus, at boot.
|
* *dbus.so*: Setup and start system message bus, D-Bus, at boot.
|
||||||
_Optional plugin._
|
_Optional plugin._
|
||||||
|
|
||||||
* *hotplug.so*: Setup and start either udev or mdev hotplug daemon, if
|
* *hook-scripts.so*: Trigger the execution of scripts from plugin hook
|
||||||
available.
|
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*: Replaced with `/lib/finit/system/10-hotplug.conf`, which
|
||||||
|
checks for `udevd` and `mdev` at boot. This file can be overridden by a
|
||||||
|
file in `/etc/finit.d/10-hotplug.conf`.
|
||||||
|
|
||||||
|
Enabled by default.
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> 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
|
||||||
|
|
||||||
|
Since these tasks run in the background, they return `[ OK ]` at boot,
|
||||||
|
unless the modprobe tool does not exist. Check syslog for warnings
|
||||||
|
and the actual status of the operation using `initctl`.
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> 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
|
||||||
|
|
||||||
* *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,40 +130,107 @@ 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/down/foo.sh
|
||||||
|
#!/bin/sh
|
||||||
|
echo 'I run just before the reboot() syscall at shutdown/reboot'
|
||||||
|
echo 'I have access to /dev since devtmpfs is exempt from umount'
|
||||||
|
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/down/foo.sh
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> 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()`
|
||||||
detects an event. See the source code for `plugins/*.c` for more help
|
detects an event. See the source code for `plugins/*.c` for more help
|
||||||
and ideas.
|
and ideas.
|
||||||
|
|
||||||
|
[tmpfiles.d(5)]: https://www.freedesktop.org/software/systemd/man/tmpfiles.d.html
|
||||||
|
|||||||
+56
-1
@@ -1,7 +1,60 @@
|
|||||||
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 +64,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
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 138 KiB After Width: | Height: | Size: 320 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 814 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
@@ -0,0 +1,141 @@
|
|||||||
|
_cond()
|
||||||
|
{
|
||||||
|
initctl -pt cond dump | awk '{print $4}' | sed 's/<\(.*\)>/\1/'
|
||||||
|
}
|
||||||
|
|
||||||
|
_ident()
|
||||||
|
{
|
||||||
|
if [ -n "$1" ]; then
|
||||||
|
initctl ident | grep -q $1
|
||||||
|
else
|
||||||
|
initctl ident
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_svc()
|
||||||
|
{
|
||||||
|
initctl ls -pt | grep $1 | sed "s/.*\/\(.*\)/\1/g" | sort -u
|
||||||
|
}
|
||||||
|
|
||||||
|
_enabled()
|
||||||
|
{
|
||||||
|
echo "$(_svc enabled)"
|
||||||
|
}
|
||||||
|
|
||||||
|
_available()
|
||||||
|
{
|
||||||
|
all=$(mktemp)
|
||||||
|
ena=$(mktemp)
|
||||||
|
echo "$(_svc available)" >$all
|
||||||
|
echo "$(_svc enabled)" >$ena
|
||||||
|
grep -v -f $ena $all
|
||||||
|
rm $all $ena
|
||||||
|
}
|
||||||
|
|
||||||
|
# Determine first non-option word. Usually the command
|
||||||
|
_firstword() {
|
||||||
|
local firstword i
|
||||||
|
|
||||||
|
firstword=
|
||||||
|
for ((i = 1; i < ${#COMP_WORDS[@]}; ++i)); do
|
||||||
|
if [[ ${COMP_WORDS[i]} != -* ]]; then
|
||||||
|
firstword=${COMP_WORDS[i]}
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo $firstword
|
||||||
|
}
|
||||||
|
|
||||||
|
# Determine last non-option word. Uusally a sub-command
|
||||||
|
_lastword() {
|
||||||
|
local lastword i
|
||||||
|
|
||||||
|
lastword=
|
||||||
|
for ((i = 1; i < ${#COMP_WORDS[@]}; ++i)); do
|
||||||
|
if [[ ${COMP_WORDS[i]} != -* ]] && [[ -n ${COMP_WORDS[i]} ]] && [[ ${COMP_WORDS[i]} != $cur ]]; then
|
||||||
|
lastword=${COMP_WORDS[i]}
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo $lastword
|
||||||
|
}
|
||||||
|
|
||||||
|
_initctl()
|
||||||
|
{
|
||||||
|
local cur command
|
||||||
|
|
||||||
|
cur=${COMP_WORDS[COMP_CWORD]}
|
||||||
|
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||||
|
firstword=$(_firstword)
|
||||||
|
lastword=$(_lastword)
|
||||||
|
|
||||||
|
commands="status cond debug help kill ls log version list enable \
|
||||||
|
disable touch show cat edit create delete reload start \
|
||||||
|
stop restart signal cgroup ps top plugins runlevel reboot \
|
||||||
|
halt poweroff suspend utmp"
|
||||||
|
cond_cmds="set get clear status dump"
|
||||||
|
cond_types="hook net pid service task usr"
|
||||||
|
signals="int term hup stop tstp cont usr1 usr2 pwr"
|
||||||
|
options="-b --batch \
|
||||||
|
-c --create \
|
||||||
|
-d --debug \
|
||||||
|
-f --force \
|
||||||
|
-h --help \
|
||||||
|
-j --json \
|
||||||
|
-n --noerr \
|
||||||
|
-1 --once \
|
||||||
|
-p --plain \
|
||||||
|
-q --quiet \
|
||||||
|
-t --no-heading \
|
||||||
|
-v --verbose \
|
||||||
|
-V --version"
|
||||||
|
|
||||||
|
case "${firstword}" in
|
||||||
|
enable)
|
||||||
|
COMPREPLY=($(compgen -W "$(_available)" -- $cur))
|
||||||
|
;;
|
||||||
|
disable|touch)
|
||||||
|
COMPREPLY=($(compgen -W "$(_enabled)" -- $cur))
|
||||||
|
;;
|
||||||
|
show|cat|edit|delete)
|
||||||
|
COMPREPLY=($(compgen -W "$(_svc .)" -- $cur))
|
||||||
|
;;
|
||||||
|
start|stop|restart|log|status)
|
||||||
|
COMPREPLY=($(compgen -W "$(_ident)" -- $cur))
|
||||||
|
;;
|
||||||
|
signal|kill)
|
||||||
|
if $(_ident "${prev}"); then
|
||||||
|
COMPREPLY=($(compgen -W "$signals" -- $cur))
|
||||||
|
else
|
||||||
|
COMPREPLY=($(compgen -W "$(_ident)" -- $cur))
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
cond)
|
||||||
|
case "${lastword}" in
|
||||||
|
set|clear)
|
||||||
|
compopt -o nospace
|
||||||
|
COMPREPLY=($(compgen -W "usr/" -- $cur))
|
||||||
|
;;
|
||||||
|
get)
|
||||||
|
COMPREPLY=($(compgen -W "$(_cond)" -- $cur))
|
||||||
|
;;
|
||||||
|
dump)
|
||||||
|
COMPREPLY=($(compgen -W "$cond_types" -- $cur))
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
COMPREPLY=($(compgen -W "$cond_cmds" -- $cur))
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
COMPREPLY=($(compgen -W "$commands" -- $cur))
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ $cur == -* ]]; then
|
||||||
|
COMPREPLY=($(compgen -W "$options" -- $cur))
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
complete -F _initctl initctl
|
||||||
+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")])
|
||||||
|
|||||||
+175
-5
@@ -2,7 +2,7 @@
|
|||||||
.\" First parameter, NAME, should be all caps
|
.\" First parameter, NAME, should be all caps
|
||||||
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||||
.\" other parameters are allowed: see man(7), man(1)
|
.\" other parameters are allowed: see man(7), man(1)
|
||||||
.Dd June 6, 2021
|
.Dd Apr 22, 2023
|
||||||
.\" Please adjust this date whenever revising the manpage.
|
.\" Please adjust this date whenever revising the manpage.
|
||||||
.Dt FINIT 8 SMM
|
.Dt FINIT 8 SMM
|
||||||
.Os Linux
|
.Os Linux
|
||||||
@@ -11,9 +11,17 @@
|
|||||||
.Nd Fast init for Linux systems
|
.Nd Fast init for Linux systems
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm /sbin/finit
|
.Nm /sbin/finit
|
||||||
.Op finit.status_style=classic
|
.Op --
|
||||||
.Op finit.show_status=[on,off]
|
.Op debug
|
||||||
|
.Op finit.cond=foo[,bar[,baz]]
|
||||||
|
.Op finit.config=/path/to/alt/finit.conf
|
||||||
.Op finit.debug
|
.Op finit.debug
|
||||||
|
.Op finit.fstab=/etc/fstab.alt
|
||||||
|
.Op finit.status=<on,off>
|
||||||
|
.Op finit.status_style=<classic,modern>
|
||||||
|
.Op loglevel=<0-7>
|
||||||
|
.Op panic=SEC
|
||||||
|
.Op quiet
|
||||||
.Op rescue | recover
|
.Op rescue | recover
|
||||||
.Op single | S
|
.Op single | S
|
||||||
.Nm /sbin/telinit
|
.Nm /sbin/telinit
|
||||||
@@ -43,6 +51,15 @@ Sourcing environment files
|
|||||||
.It
|
.It
|
||||||
Conditions for network/process/custom dependencies
|
Conditions for network/process/custom dependencies
|
||||||
.It
|
.It
|
||||||
|
Process readiness notification for synchronizing system startup as well
|
||||||
|
as reconfiguration at runtime. Natively PID files are used, but systemd
|
||||||
|
.Cm sd_notify()
|
||||||
|
and s6 notification is also supported.
|
||||||
|
.It
|
||||||
|
Limited support for
|
||||||
|
.Xr tmpfiles.d 5 ,
|
||||||
|
no aging, attributes, or subvolumes
|
||||||
|
.It
|
||||||
Pre/Post script actions
|
Pre/Post script actions
|
||||||
.It
|
.It
|
||||||
Tooling to enable/disable services
|
Tooling to enable/disable services
|
||||||
@@ -61,12 +78,156 @@ Plugin support for customization
|
|||||||
.It
|
.It
|
||||||
Proper rescue mode with bundled `sulogin` for protected maintenance shell
|
Proper rescue mode with bundled `sulogin` for protected maintenance shell
|
||||||
.El
|
.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
|
.Sh BOOTING
|
||||||
.Pp
|
.Pp
|
||||||
Before laucnhing services, the system needs to be bootstrapped. This
|
Before laucnhing services, the system needs to be bootstrapped. This
|
||||||
involves mounting all filesystems (not already mounted by an initramfs)
|
involves mounting all filesystems (not already mounted by an initramfs)
|
||||||
in
|
in
|
||||||
.Pa /etc/fstab ,
|
.Pa /etc/fstab ,
|
||||||
|
or any alternate
|
||||||
|
.Pa fstab
|
||||||
|
file provided on the Finit command line using
|
||||||
|
.Cm finit.fstab ,
|
||||||
ensuring that necessary filesystems like:
|
ensuring that necessary filesystems like:
|
||||||
.Pa /dev ,
|
.Pa /dev ,
|
||||||
.Pa /proc ,
|
.Pa /proc ,
|
||||||
@@ -109,14 +270,22 @@ file removed, service B is also stopped.
|
|||||||
.Pp
|
.Pp
|
||||||
The following condition families are available today:
|
The following condition families are available today:
|
||||||
.Pp
|
.Pp
|
||||||
.Bl -tag -width pid -offset indent
|
.Bl -tag -width service -offset indent
|
||||||
.It Cm net
|
.It Cm net
|
||||||
Linux netlink events, e.g. net/route/default, net/eth0/up, and
|
Linux netlink events, e.g. net/route/default, net/eth0/up, and
|
||||||
net/et0/running
|
net/et0/running
|
||||||
.It Cm pid
|
.It Cm pid
|
||||||
PID files basd on the service declaration
|
PID files based on the service declaration
|
||||||
.Cm name:id ,
|
.Cm name:id ,
|
||||||
gives the condition pid/name:id
|
gives the condition pid/name:id
|
||||||
|
.It Cm service
|
||||||
|
Tracks run/task/service state stansitions, including readiness. E.g.,
|
||||||
|
.Cm service/foo/ready
|
||||||
|
can be used as a condition for service
|
||||||
|
.Cm bar ,
|
||||||
|
provided
|
||||||
|
.Cm foo
|
||||||
|
properly signals its readiness to Finit.
|
||||||
.It Cm sys
|
.It Cm sys
|
||||||
System conditions, e.g. sys/key/ctrlaltdel and sys/pwr/fail
|
System conditions, e.g. sys/key/ctrlaltdel and sys/pwr/fail
|
||||||
.It Cm usr
|
.It Cm usr
|
||||||
@@ -172,6 +341,7 @@ Runtime files, including the condition subsystem
|
|||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr finit.conf 5
|
.Xr finit.conf 5
|
||||||
.Xr initctl 8
|
.Xr initctl 8
|
||||||
|
.Xr tmpfiles.d 5
|
||||||
.Sh AUTHORS
|
.Sh AUTHORS
|
||||||
.Nm
|
.Nm
|
||||||
was conceived and reverse engineered by Claudio Matsuoka. Since v1.0,
|
was conceived and reverse engineered by Claudio Matsuoka. Since v1.0,
|
||||||
|
|||||||
+229
-73
@@ -2,7 +2,7 @@
|
|||||||
.\" First parameter, NAME, should be all caps
|
.\" First parameter, NAME, should be all caps
|
||||||
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||||
.\" other parameters are allowed: see man(7), man(1)
|
.\" other parameters are allowed: see man(7), man(1)
|
||||||
.Dd Oct 17, 2020
|
.Dd July 11, 2023
|
||||||
.Dt FINIT.CONF 5 SMM
|
.Dt FINIT.CONF 5 SMM
|
||||||
.Os Linux
|
.Os Linux
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@@ -12,48 +12,79 @@
|
|||||||
.Nm /etc/finit.conf
|
.Nm /etc/finit.conf
|
||||||
.Nm /etc/finit.d/*.conf
|
.Nm /etc/finit.d/*.conf
|
||||||
.Nm /etc/finit.d/available/*.conf
|
.Nm /etc/finit.d/available/*.conf
|
||||||
|
.Nm /etc/finit.d/enabled/*.conf
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
.Nm finit
|
.Nm Finit
|
||||||
can be configured using only the original
|
based systems can be set up with a single file:
|
||||||
.Pa /etc/finit.conf
|
.Pa /etc/finit.conf .
|
||||||
file or in combination with
|
This is the traditional way of doing it which can be ideal for some
|
||||||
.Pa /etc/finit.d/*.conf .
|
setups since it gives a great overview of the system configuration.
|
||||||
Useful for package-based Linux distributions \(em each package can
|
|
||||||
provide its own "script" file.
|
|
||||||
.Pp
|
.Pp
|
||||||
.Bl -tag -width /etc/finit.d/*.conf -offset indent -compact
|
More comprehensive setups, however, require more careful planning.
|
||||||
.It Pa /etc/finit.conf
|
The recommendation is per-package
|
||||||
Main configuration file
|
.Cm *.conf
|
||||||
.It Pa /etc/finit.d/*.conf
|
files in
|
||||||
Snippets, usually one service per file
|
.Pa /etc/finit.d/available/ .
|
||||||
.El
|
This allows end users to enable and disable parts of the system
|
||||||
|
configuration at runtime. Finit tracks which tasks and services belong
|
||||||
|
to a given file, so that when the user calls
|
||||||
|
.Cm initctl reload
|
||||||
|
to activate the changes they have made, only the affected tasks and
|
||||||
|
services are stopped, started, or restarted. Hence, this approach is
|
||||||
|
useful for modern package-based Linux distributions.
|
||||||
.Pp
|
.Pp
|
||||||
Not all configuration directives are available in
|
The following sections describe the more of this in detail, starting
|
||||||
.Pa /etc/finit.d/*.conf
|
with files, the file format, and available directives. Remember to
|
||||||
and some directives are only available at bootstrap, runlevel
|
also visit the other manual pages (references at the bottom).
|
||||||
.Cm S ,
|
|
||||||
see the section
|
|
||||||
.Sx Limitations
|
|
||||||
below for details.
|
|
||||||
.Sh FILES
|
.Sh FILES
|
||||||
.Bl -tag -width /etc/finit.d/available/*.conf -compact
|
.Bl -tag -width /etc/finit.d/available/*.conf -compact
|
||||||
.It Pa /etc/finit.conf
|
.It Pa /etc/finit.conf
|
||||||
Main configuration file
|
Main configuration file, optional
|
||||||
.It Pa /etc/finit.d/*.conf
|
.It Pa /etc/finit.d/*.conf
|
||||||
Static service definitions
|
Static (system) service definitions
|
||||||
.It Pa /etc/finit.d/available/*.conf
|
.It Pa /etc/finit.d/available/*.conf
|
||||||
Available services
|
Available (installed) services
|
||||||
.It Pa /etc/finit.d/enabled/*.conf
|
.It Pa /etc/finit.d/enabled/*.conf
|
||||||
Enabled services, symlinks from available
|
Enabled services (symlink back)
|
||||||
.El
|
.El
|
||||||
.Sh FILE FORMAT
|
|
||||||
Lines starting with `#' are ignored. Note that end-of-line comments are
|
|
||||||
NOT supported, comments must be on a line of their own.
|
|
||||||
.Pp
|
.Pp
|
||||||
A configuration stanza must be on a single (long) line and
|
Static services,
|
||||||
.Em cannot
|
.Cm .conf
|
||||||
be broken up in multiple lines by use of a backslash as the last
|
files in
|
||||||
character.
|
.Pa /etc/finit.d/ ,
|
||||||
|
cannot be enabled or disabled using
|
||||||
|
.Cm initctl [enable | disable] service[.conf] .
|
||||||
|
An enabled service is a symlink back to the corresponding
|
||||||
|
.Cm ../available/
|
||||||
|
service
|
||||||
|
.Cm .conf
|
||||||
|
file. Please use the
|
||||||
|
.Cm initctl
|
||||||
|
tool to manage these symlinks to ensure proper operation.
|
||||||
|
.Pp
|
||||||
|
.Sy NOTE:
|
||||||
|
Previous versions of
|
||||||
|
.Nm Finit
|
||||||
|
created symlinks in
|
||||||
|
.Pa /etc/finit.d/
|
||||||
|
if
|
||||||
|
.Pa /etc/finit.d/enabled/
|
||||||
|
was missing, this is as of v4.4 not supported.
|
||||||
|
.Sh FILE FORMAT
|
||||||
|
The file format is line based, empty lines and comments, lines starting
|
||||||
|
with `#', are ignored. A configuration directive starts with a keyword
|
||||||
|
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
|
.Sh DIRECTIVES
|
||||||
This section lists all supported configuration directives. There also exist
|
This section lists all supported configuration directives. There also exist
|
||||||
deprecated directives, see the Markdown documentation for details on these.
|
deprecated directives, see the Markdown documentation for details on these.
|
||||||
@@ -108,6 +139,10 @@ is the runlevel number 0-9, where 6 is reserved for reboot and 0 for
|
|||||||
halt. All other can be used by operating system administrators.
|
halt. All other can be used by operating system administrators.
|
||||||
Default: 2
|
Default: 2
|
||||||
.Pp
|
.Pp
|
||||||
|
It s recommended to keep runlevel 1 as single-user mode, because
|
||||||
|
.Nm
|
||||||
|
disables networking in this mode.
|
||||||
|
.Pp
|
||||||
.Sy Note:
|
.Sy Note:
|
||||||
only read and executed in runlevel S (bootstrap).
|
only read and executed in runlevel S (bootstrap).
|
||||||
.It Cm run Oo LVLS Oc Ao COND Ac Ar /path/to/cmd ARGS Op -- Optional description
|
.It Cm run Oo LVLS Oc Ao COND Ac Ar /path/to/cmd ARGS Op -- Optional description
|
||||||
@@ -140,13 +175,13 @@ task [s] echo "foo" | cat >/tmp/bar
|
|||||||
.Ed
|
.Ed
|
||||||
.It Cm sysv Oo LVLS Oc Ao COND Ac Ar /path/to/script ARGS Op -- Optional description
|
.It Cm sysv Oo LVLS Oc Ao COND Ac Ar /path/to/script ARGS Op -- Optional description
|
||||||
Similar to
|
Similar to
|
||||||
.Cm task
|
.Cm service
|
||||||
is the
|
is the
|
||||||
.Cm sysv
|
.Cm sysv
|
||||||
stanza, which can be used to call SysV style start/stop scripts. The
|
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
|
primary intention for this command is to be able to re-use traditional
|
||||||
existing setup and init scripts in Linux distributions.
|
SysV init scripts in Linux distributions.
|
||||||
.Pp
|
.Pp
|
||||||
When entering an allowed runlevel, Finit calls
|
When entering an allowed runlevel, Finit calls
|
||||||
.Cm init-script start ,
|
.Cm init-script start ,
|
||||||
when entering a disallowed runlevel, Finit calls
|
when entering a disallowed runlevel, Finit calls
|
||||||
@@ -181,6 +216,12 @@ After which they have to be restarted manually using
|
|||||||
.Cm initctl restart NAME .
|
.Cm initctl restart NAME .
|
||||||
The number of restarts, the delay between each restart, and more is
|
The number of restarts, the delay between each restart, and more is
|
||||||
configurable, see the options below.
|
configurable, see the options below.
|
||||||
|
.Pp
|
||||||
|
.Bd -filled -offset indent
|
||||||
|
.Sy Tip:
|
||||||
|
to allow endless restarts, see below option
|
||||||
|
.Cm respawn
|
||||||
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
For daemons that support it, we recommend appending
|
For daemons that support it, we recommend appending
|
||||||
.Cm --foreground , --no-background , -n , -F ,
|
.Cm --foreground , --no-background , -n , -F ,
|
||||||
@@ -194,7 +235,21 @@ services and are supported using the same syntax as forking
|
|||||||
.Cm sysv
|
.Cm sysv
|
||||||
services, using the
|
services, using the
|
||||||
.Cm pid:!/path/to/pidfile.pid
|
.Cm pid:!/path/to/pidfile.pid
|
||||||
command modifier syntax.
|
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
|
.Pp
|
||||||
.Sy Example: in the case of
|
.Sy Example: in the case of
|
||||||
.Cm ospfd
|
.Cm ospfd
|
||||||
@@ -255,6 +310,51 @@ can depend on the
|
|||||||
.Cm <pid/bar>
|
.Cm <pid/bar>
|
||||||
condition.
|
condition.
|
||||||
.Pp
|
.Pp
|
||||||
|
As an alternative "readiness" notification, Finit supports both systemd
|
||||||
|
and s6 style notification. This can be enabled by using the `notify`
|
||||||
|
option:
|
||||||
|
.Bl -tag -width 1n
|
||||||
|
.It Cm notify:systemd
|
||||||
|
tells Finit the service uses the
|
||||||
|
.Cm sd_notify()
|
||||||
|
API to signal PID 1 when it has completed its startup and is ready
|
||||||
|
to service events. This API expects
|
||||||
|
the environment variable
|
||||||
|
.Cm NOTIFY_SOCKET
|
||||||
|
to be set to the socket where the application can send
|
||||||
|
.Cm "READY=1\n"
|
||||||
|
when it is starting up or has processed a
|
||||||
|
.Cm SIGHUP .
|
||||||
|
For details, see:
|
||||||
|
.Pp
|
||||||
|
.Lk https://www.freedesktop.org/software/systemd/man/sd_notify.html
|
||||||
|
.It Cm notify:s6
|
||||||
|
puts Finit in s6 compatibility mode. Compared to the systemd
|
||||||
|
notification, s6 expect compliant daemons to send
|
||||||
|
.Cm "\\n"
|
||||||
|
and then close their socket. For details, see:
|
||||||
|
.Pp
|
||||||
|
.Lk https://skarnet.org/software/s6/notifywhenup.html
|
||||||
|
.Pp
|
||||||
|
Finit takes care of "hard-wiring" the READY state as long as the
|
||||||
|
application is running, events across any `SIGHUP`. Since s6 can give
|
||||||
|
its applications the descriptor number (must be >3) on then command
|
||||||
|
line, Finit provides the following syntax (
|
||||||
|
.Cm %n
|
||||||
|
is replaced by Finit with then descriptor number):
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
service notify:s6 mdevd -C -O 4 -D %n
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
When a service is ready, either by Finit detecting its PID file, or
|
||||||
|
their respective readiness mechanism has been triggered, Finit creates
|
||||||
|
then service's ready condition which other services can depend on:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
$ initctl -v cond get service/mdevd/ready
|
||||||
|
on
|
||||||
|
.Ed
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
If a service should not be automatically started, it can be configured
|
If a service should not be automatically started, it can be configured
|
||||||
as manual with the
|
as manual with the
|
||||||
.Cm manual:yes
|
.Cm manual:yes
|
||||||
@@ -284,17 +384,39 @@ number of seconds before Finit tries to restart
|
|||||||
a crashing service, default: 2 seconds for the first five retries,
|
a crashing service, default: 2 seconds for the first five retries,
|
||||||
then back-off to 5 seconds. The maximum of this configured value
|
then back-off to 5 seconds. The maximum of this configured value
|
||||||
and the above (2 and 5) will be used
|
and the above (2 and 5) will be used
|
||||||
|
.It Cm restart:always
|
||||||
|
no upper limit on the number of times Finit tries to restart a crashing
|
||||||
|
service. Same as
|
||||||
|
.Cm restart:-1
|
||||||
.It Cm norestart
|
.It Cm norestart
|
||||||
dont restart on failures, same as
|
dont restart on failures, same as
|
||||||
.Cm restart:0
|
.Cm restart:0
|
||||||
|
.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
|
.It Cm oncrash:reboot
|
||||||
when all retries have failed, and the service
|
when all retries have failed, and the service
|
||||||
has
|
has
|
||||||
.Em crashed ,
|
.Em crashed ,
|
||||||
if this option is set the system is rebooted. Note, future releases
|
if this option is set the system is rebooted.
|
||||||
may include other
|
.It Cm oncrash:script
|
||||||
.Cm oncrash:
|
Similar to
|
||||||
actions.
|
.Cm oncrash:reboot ,
|
||||||
|
but instead of rebooting this action calls the
|
||||||
|
.Cm post:script
|
||||||
|
(see below) to let the operator decide the best course of action. If
|
||||||
|
the post:script option is not set, this is a no-op.
|
||||||
|
.Pp
|
||||||
|
The post:script is called with the same environment variables
|
||||||
|
.Sy except
|
||||||
|
for the
|
||||||
|
.Cm EXIT_CODE
|
||||||
|
variable which is set to
|
||||||
|
.Cm "crashed" .
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
When stopping a service (run/task/sysv/service), either manually or when
|
When stopping a service (run/task/sysv/service), either manually or when
|
||||||
@@ -312,52 +434,61 @@ e.g.,
|
|||||||
.Cm kill:10
|
.Cm kill:10
|
||||||
to wait 10 seconds before sending SIGKILL.
|
to wait 10 seconds before sending SIGKILL.
|
||||||
.Pp
|
.Pp
|
||||||
Services support the
|
Services, including the
|
||||||
.Cm pre:script
|
.Cm sysv
|
||||||
and
|
variant, support pre/post/ready and cleanup scripts:
|
||||||
.Cm post:script
|
.Bl -tag -width 1n
|
||||||
command actions as well. These run as the same
|
.It Cm pre:[0-3600,]script
|
||||||
|
called before the sysv/service is stated
|
||||||
|
.It Cm post:[0-3600,]script
|
||||||
|
called after the sysv/service has stopped
|
||||||
|
.It Cm ready:[0-3600,]script
|
||||||
|
called when the sysv/service is ready
|
||||||
|
.It Cm cleanup:[0-3600,]script
|
||||||
|
called when run/task/sysv/service is removed
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
The optional number (0-3600) is the timeout before Finit kills the
|
||||||
|
script, it defaults to the kill delay value and can be disabled by
|
||||||
|
setting it to zero. These scripts run as the same
|
||||||
.Cm @USER:GROUP
|
.Cm @USER:GROUP
|
||||||
as the service itself, with any
|
as the service itself, with any
|
||||||
.Cm env:file
|
.Cm env:file
|
||||||
sourced. The scripts must use an absolute path, but are executed from
|
sourced. The scripts must use an absolute path, but are executed from
|
||||||
the
|
the
|
||||||
.Cm $HOME
|
.Cm $HOME
|
||||||
of the given user. The scripts are not called with any argument
|
of the given user. The scripts are not called with any argument, but
|
||||||
(currently), but both get the
|
both get a set of environment variables:
|
||||||
.Cm SERVICE_IDENT=foo
|
.Pp
|
||||||
environment variable set. Here
|
.Bl -tag -width 1n -compact
|
||||||
.Cm foo
|
.It Cm SERVICE_IDENT=foo:1
|
||||||
denotes the identity of the service, which if there are multiple
|
.It Cm SERVICE_NAME=foo
|
||||||
services named
|
.It Cm SERVICE_ID=1
|
||||||
.Cm foo ,
|
.El
|
||||||
may be
|
.Pp
|
||||||
.Cm foo:1 ,
|
The
|
||||||
or any unique identifier specified in the .conf file. The
|
|
||||||
.Cm post:script
|
.Cm post:script
|
||||||
is called with an additional set of environment variables:
|
is called with an additional set of environment variables, and yes the
|
||||||
|
naming looks like it should be swapped:
|
||||||
.Bl -tag -offset indent -width 1n
|
.Bl -tag -offset indent -width 1n
|
||||||
.It Cm EXIT_CODE=[exited,signal]
|
.It Cm EXIT_CODE=[exited,signal,crashed]
|
||||||
set to one of
|
set to one of
|
||||||
.Cm exited
|
.Cm exited ,
|
||||||
|
.Cm signal ,
|
||||||
or
|
or
|
||||||
.Cm signal
|
.Cm crashed
|
||||||
|
(see above).
|
||||||
.It Cm EXIT_STATUS=[num,SIGNAME]
|
.It Cm EXIT_STATUS=[num,SIGNAME]
|
||||||
set to one of exit status code from the program, if it exited normally,
|
set to one of exit status code from the program, if it exited normally,
|
||||||
or the signal name (HUP, TERM, etc.) if it exited due to signal
|
or the signal name (HUP, TERM, etc.) if it exited due to signal
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
The scripts have a default execution time of 3 seconds before they are
|
When a run/task/sys/service is removed (disable + reload) it is first
|
||||||
SIGKILLed, this can be adjusted using the
|
stopped and then removed from the runlevel. The
|
||||||
.Cm kill:SEC
|
.Cm post:script
|
||||||
modifier syntax.
|
always runs when the process has stopped, and the
|
||||||
.Pp
|
.Cm cleanup:script
|
||||||
.Sy Note:
|
runs when the the stanza has been removed from the runlevel.
|
||||||
the
|
|
||||||
.Cm pre:script
|
|
||||||
.Em must
|
|
||||||
be idempotent, because a service can transition between READY and HALTED
|
|
||||||
states any number of times before going to RUNNING.
|
|
||||||
.It Cm runparts Aq DIR
|
.It Cm runparts Aq DIR
|
||||||
Call
|
Call
|
||||||
.Xr run-parts 8
|
.Xr run-parts 8
|
||||||
@@ -726,6 +857,31 @@ the example sets
|
|||||||
to denote that it doesn't support SIGHUP. That way Finit will
|
to denote that it doesn't support SIGHUP. That way Finit will
|
||||||
stop/start the service instead of sending SIGHUP at restart/reload
|
stop/start the service instead of sending SIGHUP at restart/reload
|
||||||
events.
|
events.
|
||||||
|
.Sh TEMPLATING
|
||||||
|
Finit comes with rudimentary support for templating, similar to that of
|
||||||
|
systemd. Best illustrated with an example:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
$ initctl show avahi-autoipd@
|
||||||
|
service :%i avahi-autoipd --syslog %i -- ZeroConf for %i
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
To enable ZeroConf for, e.g.,
|
||||||
|
.Cm eth0 ,
|
||||||
|
use
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
$ initctl enable avahi-autoipd@eth0.conf
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
The enabled symlink will be set up to
|
||||||
|
.Cm avahi-autoipd@.conf
|
||||||
|
and every instance of
|
||||||
|
.Cm %i
|
||||||
|
will in the instantiated directive be replaced with
|
||||||
|
.Cm eth0 .
|
||||||
|
Inspect the result with:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
$ initctl status avahi-autoipd:eth0
|
||||||
|
.Ed
|
||||||
.Sh CGROUPS
|
.Sh CGROUPS
|
||||||
There are three major cgroup configuration directives:
|
There are three major cgroup configuration directives:
|
||||||
.Pp
|
.Pp
|
||||||
@@ -842,6 +998,6 @@ settings in
|
|||||||
.Xr finit 8 ,
|
.Xr finit 8 ,
|
||||||
.Xr initctl 8
|
.Xr initctl 8
|
||||||
.Sh AUTHORS
|
.Sh AUTHORS
|
||||||
.Nm finit
|
.Nm Finit
|
||||||
was conceived and reverse engineered by Claudio Matsuoka. Since v1.0,
|
was conceived and reverse engineered by Claudio Matsuoka. Since v1.0,
|
||||||
maintained by Joachim Wiberg, with contributions by many others.
|
maintained by Joachim Wiberg, with contributions by many others.
|
||||||
|
|||||||
+122
-31
@@ -11,7 +11,7 @@
|
|||||||
.Nd Control tool for Finit
|
.Nd Control tool for Finit
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm /sbin/initctl
|
.Nm /sbin/initctl
|
||||||
.Op Fl bcfhlpqtv
|
.Op Fl bcfhjlpqtvV
|
||||||
.Op COMMAND
|
.Op COMMAND
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
.Nm
|
.Nm
|
||||||
@@ -24,13 +24,27 @@ This program follows the usual UNIX command line syntax, with long
|
|||||||
options starting with two dashes (`-'). The options are as follows:
|
options starting with two dashes (`-'). The options are as follows:
|
||||||
.Bl -tag -width Ds
|
.Bl -tag -width Ds
|
||||||
.It Fl b, -batch
|
.It Fl b, -batch
|
||||||
Batch mode, no screen size probing.
|
Batch mode, no screen size probing. Useful for scripting.
|
||||||
.It Fl c, -create
|
.It Fl c, -create
|
||||||
Create missing paths (and files) as needed. Useful with the edit command.
|
Create missing paths (and files) as needed. Useful with the
|
||||||
|
.Cm edit
|
||||||
|
command.
|
||||||
.It Fl f, -force
|
.It Fl f, -force
|
||||||
Ignore missing files and arguments, never prompt.
|
Ignore missing files and arguments, never prompt.
|
||||||
.It Fl h, -help
|
.It Fl h, -help
|
||||||
Show built-in help text.
|
Show built-in help text.
|
||||||
|
.It Fl j, -json
|
||||||
|
JSON output in
|
||||||
|
.Ar status
|
||||||
|
and
|
||||||
|
.Ar cond
|
||||||
|
commands.
|
||||||
|
.It Fl n, -noerr
|
||||||
|
When scripting
|
||||||
|
.Nm
|
||||||
|
to stop, start, restart, or signal a task or service, this option can be
|
||||||
|
used to ignore error 69 (no such task or service) and instead return 0
|
||||||
|
(OK).
|
||||||
.It Fl 1, -once
|
.It Fl 1, -once
|
||||||
Only one lap in commands like top.
|
Only one lap in commands like top.
|
||||||
.It Fl p, -plain
|
.It Fl p, -plain
|
||||||
@@ -41,16 +55,20 @@ Silent, only return status of command.
|
|||||||
Skip table headings.
|
Skip table headings.
|
||||||
.It Fl v, -verbose
|
.It Fl v, -verbose
|
||||||
Verbose output, where applicable.
|
Verbose output, where applicable.
|
||||||
|
.It Fl V, -version
|
||||||
|
Show program version.
|
||||||
.El
|
.El
|
||||||
.Sh COMMANDS
|
.Sh COMMANDS
|
||||||
.Bl -tag -width Ds
|
.Bl -tag -width Ds
|
||||||
.It Nm Ar debug
|
.It Nm Ar debug
|
||||||
Toggle finit (daemon) debug to
|
Toggle
|
||||||
|
.Nm finit
|
||||||
|
(daemon) debug to
|
||||||
.Pa /dev/console
|
.Pa /dev/console
|
||||||
.It Nm Ar help
|
.It Nm Ar help
|
||||||
Show built-in help text
|
Show built-in help text.
|
||||||
.It Nm Ar version
|
.It Nm Ar version
|
||||||
Show Finit (daemon) version
|
Show program version.
|
||||||
.It Nm Ar ls | list
|
.It Nm Ar ls | list
|
||||||
List all
|
List all
|
||||||
.Cm *.conf
|
.Cm *.conf
|
||||||
@@ -60,7 +78,16 @@ files in
|
|||||||
Create
|
Create
|
||||||
.Cm .conf
|
.Cm .conf
|
||||||
in
|
in
|
||||||
.Pa /etc/finit.d/available
|
.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
|
.It Nm Ar delete Ar CONF
|
||||||
Delete
|
Delete
|
||||||
.Cm .conf
|
.Cm .conf
|
||||||
@@ -100,82 +127,146 @@ Disable
|
|||||||
.Cm .conf
|
.Cm .conf
|
||||||
in
|
in
|
||||||
.Pa /etc/finit.d/enabled ,
|
.Pa /etc/finit.d/enabled ,
|
||||||
i.e., removes symlink
|
i.e., removes symlink.
|
||||||
.It Nm Ar reload
|
.It Nm Ar reload
|
||||||
Reload
|
Reload
|
||||||
.Cm *.conf in
|
.Cm *.conf in
|
||||||
.Pa /etc/finit.d ,
|
.Pa /etc/finit.d ,
|
||||||
i.e., activates changes
|
i.e., activates changes.
|
||||||
.It Nm Ar cond set Ar COND
|
.It Nm Ar cond set Ar COND Op COND ...
|
||||||
Set (assert) user-defined condition,
|
Set (assert) user-defined condition,
|
||||||
.Cm +usr/COND
|
.Cm +usr/COND
|
||||||
.It Nm Ar cond clr | clear Ar 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,
|
Clear (deassert) user-defined condition,
|
||||||
.Cm -usr/COND
|
.Cm -usr/COND
|
||||||
.It Nm Ar cond status
|
.It Nm Ar cond status
|
||||||
Show condition status, default
|
Show condition status, default
|
||||||
.Cm cond
|
.Cm cond
|
||||||
command.
|
command. Also supports the
|
||||||
.It Nm Ar cond dump
|
.Fl j
|
||||||
Dump all conditions and their status
|
option for detailed JSON output.
|
||||||
|
.It Nm Ar cond dump Op Cm TYPE
|
||||||
|
Dump all, or a given type of, conditions and their status. Also
|
||||||
|
supports the
|
||||||
|
.Fl j
|
||||||
|
option for detailed JSON output.
|
||||||
.It Nm Ar ident Op Cm NAME
|
.It Nm Ar ident Op Cm NAME
|
||||||
Display indentities of all run/task/services, or only instances
|
Display indentities of all run/task/services, or only instances
|
||||||
matching
|
matching
|
||||||
.Cm NAME .
|
.Cm NAME .
|
||||||
A partial string, e.g.,
|
A partial string, e.g.,
|
||||||
.Cm NAM ,
|
.Cm NAM ,
|
||||||
will not match anything
|
will not match anything.
|
||||||
.It Nm Ar log Op Cm NAME
|
.It Nm Ar log Op Cm NAME
|
||||||
Show ten last Finit, or
|
Show ten last Finit, or
|
||||||
.Cm NAME ,
|
.Cm NAME ,
|
||||||
messages from syslog
|
messages from syslog.
|
||||||
.It Nm Ar start Cm NAME[:ID]
|
.It Nm Ar start Cm NAME[:ID]
|
||||||
Start service by name, with optional ID, e.g.,
|
Start service by name, with optional ID, e.g.,
|
||||||
.Cm initctl start tty:1
|
.Cm initctl start tty:1
|
||||||
.It Nm Ar stop Cm NAME[:ID]
|
.It Nm Ar stop Cm NAME[:ID]
|
||||||
Stop/Pause a running service by name
|
Stop/Pause a running service by name.
|
||||||
.It Nm Ar reload Cm NAME[:ID]
|
.It Nm Ar reload Cm NAME[:ID]
|
||||||
Reload service by name (SIGHUP or restart)
|
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]
|
.It Nm Ar restart Cm NAME[:ID]
|
||||||
Restart (stop/start) service by name
|
Restart (stop/start) service by name.
|
||||||
.It Nm Ar status Cm NAME[:ID]
|
.It Nm Ar status Cm NAME[:ID]
|
||||||
Show service status, by name. If only
|
Show service status, by name. If only
|
||||||
.Cm NAME
|
.Cm NAME
|
||||||
is given and multiple instances exits, a summary of all matching
|
is given and multiple instances exits, a summary of all matching
|
||||||
instances are shown. Only an exact match displays the detailed status
|
instances are shown. Only an exact match displays detailed status
|
||||||
for a particular instance
|
for a given instance.
|
||||||
|
.Pp
|
||||||
|
With the
|
||||||
|
.Fl q
|
||||||
|
option this command is silent, provided the
|
||||||
|
.Ar NAME[:ID]
|
||||||
|
selection matches a single run/task/service. The exit code of
|
||||||
|
.Nm
|
||||||
|
is non-zero if there is a problem. Zero is returned if a run/task has
|
||||||
|
run (at least) once in the current runlevel, and when a service is running
|
||||||
|
(as expected). See the
|
||||||
|
.Fl j
|
||||||
|
option for detailed JSON output suitable for machine parsing.
|
||||||
|
.Pp
|
||||||
|
.Sy Tip:
|
||||||
|
.Xr jq 1
|
||||||
|
is a useful scripting tool in combination with JSON output.
|
||||||
.It Nm Ar status
|
.It Nm Ar status
|
||||||
Show status of all services, default command
|
Show status of all services, default command. Also supports the
|
||||||
|
.Fl j
|
||||||
|
option for detailed JSON output.
|
||||||
.It Nm Ar cgroup
|
.It Nm Ar cgroup
|
||||||
List cgroup config overview
|
List cgroup config overview.
|
||||||
.It Nm Ar ps
|
.It Nm Ar ps
|
||||||
List processes based on cgroups
|
List processes based on cgroups.
|
||||||
.It Nm Ar top
|
.It Nm Ar top
|
||||||
Show top-like listing based on cgroups
|
Show top-like listing based on cgroups.
|
||||||
|
.It Nm Ar plugins
|
||||||
|
List installed plugins.
|
||||||
.It Nm Ar runlevel Op Ar 0-9
|
.It Nm Ar runlevel Op Ar 0-9
|
||||||
Show or set runlevel: 0 halt, 6 reboot
|
Show or set runlevel: 0 halt, 6 reboot.
|
||||||
|
.Pp
|
||||||
|
If called at boot (runlevel S) to set the runlevel, Finit only schedules
|
||||||
|
the change, effectively overriding the configured runlevel from
|
||||||
|
.Pa /etc/finit.conf .
|
||||||
|
Useful to trigger a fail-safe mode, or similar.
|
||||||
.It Nm Ar reboot
|
.It Nm Ar reboot
|
||||||
Reboot system, default if
|
Reboot system, default if
|
||||||
.Cm reboot
|
.Cm reboot
|
||||||
is symlinked to
|
is symlinked to
|
||||||
.Nm
|
.Nm .
|
||||||
.It Nm Ar halt
|
.It Nm Ar halt
|
||||||
Halt system, default if
|
Halt system, default if
|
||||||
.Cm halt
|
.Cm halt
|
||||||
is symlinked to
|
is symlinked to
|
||||||
.Nm
|
.Nm .
|
||||||
.It Nm Ar poweroff
|
.It Nm Ar poweroff
|
||||||
Power-off system, default if
|
Power-off system, default if
|
||||||
.Cm poweroff
|
.Cm poweroff
|
||||||
is symlinked to
|
is symlinked to
|
||||||
.Nm
|
.Nm .
|
||||||
.It Nm Ar suspend
|
.It Nm Ar suspend
|
||||||
Suspend system, default if
|
Suspend system, default if
|
||||||
.Cm suspend
|
.Cm suspend
|
||||||
is symlinked to
|
is symlinked to
|
||||||
.Nm
|
.Nm .
|
||||||
.It Nm Ar utmp show
|
.It Nm Ar utmp show
|
||||||
Raw dump of UTMP/WTMP db
|
Raw dump of UTMP/WTMP db.
|
||||||
.El
|
.El
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr finit.conf 5
|
.Xr finit.conf 5
|
||||||
|
|||||||
+22
-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 pidfile.c procps.c sys.c tty.c usr.c
|
libplug_la_SOURCES = bootmisc.c pidfile.c procps.c sys.c usr.c
|
||||||
|
|
||||||
if BUILD_ALSA_UTILS_PLUGIN
|
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
|
||||||
@@ -37,6 +37,10 @@ if BUILD_RTC_PLUGIN
|
|||||||
libplug_la_SOURCES += rtc.c
|
libplug_la_SOURCES += rtc.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if BUILD_TTY_PLUGIN
|
||||||
|
libplug_la_SOURCES += tty.c
|
||||||
|
endif
|
||||||
|
|
||||||
if BUILD_URANDOM_PLUGIN
|
if BUILD_URANDOM_PLUGIN
|
||||||
libplug_la_SOURCES += urandom.c
|
libplug_la_SOURCES += urandom.c
|
||||||
endif
|
endif
|
||||||
@@ -46,7 +50,7 @@ libplug_la_SOURCES += x11-common.c
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
else
|
else
|
||||||
pkglib_LTLIBRARIES = bootmisc.la modprobe.la pidfile.la procps.la sys.la tty.la usr.la
|
pkglib_LTLIBRARIES = bootmisc.la pidfile.la procps.la sys.la usr.la
|
||||||
|
|
||||||
if BUILD_ALSA_UTILS_PLUGIN
|
if BUILD_ALSA_UTILS_PLUGIN
|
||||||
pkglib_LTLIBRARIES += alsa-utils.la
|
pkglib_LTLIBRARIES += alsa-utils.la
|
||||||
@@ -56,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
|
||||||
@@ -76,6 +84,10 @@ if BUILD_RTC_PLUGIN
|
|||||||
pkglib_LTLIBRARIES += rtc.la
|
pkglib_LTLIBRARIES += rtc.la
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if BUILD_TTY_PLUGIN
|
||||||
|
pkglib_LTLIBRARIES += tty.la
|
||||||
|
endif
|
||||||
|
|
||||||
if BUILD_URANDOM_PLUGIN
|
if BUILD_URANDOM_PLUGIN
|
||||||
pkglib_LTLIBRARIES += urandom.la
|
pkglib_LTLIBRARIES += urandom.la
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* Save and restore ALSA sound settings using alsactl
|
/* Save and restore ALSA sound settings using alsactl
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2012-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -36,12 +36,12 @@
|
|||||||
static void save(void *arg)
|
static void save(void *arg)
|
||||||
{
|
{
|
||||||
if (rescue) {
|
if (rescue) {
|
||||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (whichp(ALSACTL)) {
|
if (whichp(ALSACTL)) {
|
||||||
_d("Saving sound settings ...");
|
dbg("Saving sound settings ...");
|
||||||
run_interactive(ALSACTL " -g store", "Saving sound settings");
|
run_interactive(ALSACTL " -g store", "Saving sound settings");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,12 +49,12 @@ static void save(void *arg)
|
|||||||
static void restore(void *arg)
|
static void restore(void *arg)
|
||||||
{
|
{
|
||||||
if (rescue) {
|
if (rescue) {
|
||||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (whichp(ALSACTL)) {
|
if (whichp(ALSACTL)) {
|
||||||
_d("Restoring sound settings ...");
|
dbg("Restoring sound settings ...");
|
||||||
run_interactive(ALSACTL " -g restore", "Restoring sound settings");
|
run_interactive(ALSACTL " -g restore", "Restoring sound settings");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+51
-83
@@ -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-2024 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,8 +21,12 @@
|
|||||||
* 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>
|
||||||
#ifdef _LIBITE_LITE
|
#ifdef _LIBITE_LITE
|
||||||
# include <libite/lite.h>
|
# include <libite/lite.h>
|
||||||
@@ -34,15 +38,18 @@
|
|||||||
#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);
|
||||||
@@ -55,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;
|
||||||
}
|
}
|
||||||
@@ -74,7 +81,7 @@ static int bootclean(const char *fpath, const struct stat *sb, int tflag, struct
|
|||||||
if (ftw->level == 0)
|
if (ftw->level == 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
_d("Removing %s ...", fpath);
|
dbg("Removing %s ...", fpath);
|
||||||
(void)remove(fpath);
|
(void)remove(fpath);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -104,10 +111,43 @@ static void clean(void *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ln(const char *target, const char *linkpath, int ignerr)
|
/* Kernel defines the following compulsory and recommended links
|
||||||
|
* https://github.com/torvalds/linux/blob/v5.18/Documentation/admin-guide/devices.rst#compulsory-links
|
||||||
|
*/
|
||||||
|
static void kernel_links(void)
|
||||||
{
|
{
|
||||||
if (symlink(target, linkpath) && !ignerr)
|
struct {
|
||||||
_pe("Failed creating %s -> %s symlink", target, linkpath);
|
char *tgt, *lnk;
|
||||||
|
int optional;
|
||||||
|
} k[] = {
|
||||||
|
{ "/proc/self/fd", "/dev/fd", 0 },
|
||||||
|
{ "fd/0", "/dev/stdin", 0 },
|
||||||
|
{ "fd/1", "/dev/stdout", 0 },
|
||||||
|
{ "fd/2", "/dev/stderr", 0 },
|
||||||
|
{ "socksys", "/dev/nfsd", 0 },
|
||||||
|
{ "null", "/dev/X0R", 0 },
|
||||||
|
{ "/proc/kcore", "/dev/core", 1 },
|
||||||
|
{ "ram0", "/dev/ramdisk", 1 },
|
||||||
|
{ "qft0", "/dev/ftape", 1 },
|
||||||
|
{ "video0", "/dev/bttv0", 1 },
|
||||||
|
{ "radio0", "/dev/radio", 1 },
|
||||||
|
};
|
||||||
|
char *fn, buf[80];
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < NELEMS(k); i++) {
|
||||||
|
fn = k[i].tgt;
|
||||||
|
|
||||||
|
if (k[i].optional) {
|
||||||
|
if (fn[0] != '/') {
|
||||||
|
snprintf(buf, sizeof(buf), "/dev/%s", k[i].tgt);
|
||||||
|
fn = buf;
|
||||||
|
}
|
||||||
|
if (!fexist(fn))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ln(k[i].tgt, k[i].lnk);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -119,87 +159,15 @@ static void setup(void *arg)
|
|||||||
|
|
||||||
prev = umask(0);
|
prev = umask(0);
|
||||||
|
|
||||||
_d("Setting up FHS structure in /var ...");
|
/* Kernel symlinks, e.g. /proc/self/fd -> /dev/fd */
|
||||||
makedir("/var/cache", 0755);
|
kernel_links();
|
||||||
makedir("/var/db", 0755); /* _PATH_VARDB on some systems */
|
|
||||||
makedir("/var/games", 0755);
|
|
||||||
makedir("/var/lib", 0755);
|
|
||||||
makedir("/var/lib/misc", 0755); /* _PATH_VARDB on some systems */
|
|
||||||
makedir("/var/lib/alarm", 0755);
|
|
||||||
makedir("/var/lib/urandom",0755);
|
|
||||||
if (fisdir("/run")) {
|
|
||||||
_d("System with new /run tmpfs ...");
|
|
||||||
if (!fisdir("/run/lock"))
|
|
||||||
makedir("/run/lock", 1777);
|
|
||||||
ln("/run/lock", "/var/lock", 0);
|
|
||||||
ln("/dev/shm", "/run/shm", 0);
|
|
||||||
|
|
||||||
/* compat only, should really be set up by OS/dist */
|
/* Create all system tmpfiles.d(5) */
|
||||||
ln("/run", "/var/run", 1);
|
tmpfilesd();
|
||||||
} else {
|
|
||||||
makedir("/var/lock", 1777);
|
|
||||||
makedir("/var/run", 0755);
|
|
||||||
}
|
|
||||||
makedir("/var/log", 0755);
|
|
||||||
makedir("/var/mail", 0755);
|
|
||||||
makedir("/var/opt", 0755);
|
|
||||||
makedir("/var/spool", 0755);
|
|
||||||
makedir("/var/spool/cron", 0755);
|
|
||||||
makedir("/var/tmp", 0755);
|
|
||||||
makedir("/var/empty", 0755);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* UTMP actually needs multiple db files
|
|
||||||
*/
|
|
||||||
if (has_utmp()) {
|
|
||||||
int gid;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If /etc/group or "utmp" group is missing, default to
|
|
||||||
* "root", or "wheel", group.
|
|
||||||
*/
|
|
||||||
_d("Setting up necessary UTMP files ...");
|
|
||||||
gid = getgroup("utmp");
|
|
||||||
if (gid < 0)
|
|
||||||
gid = 0;
|
|
||||||
|
|
||||||
create("/var/run/utmp", 0644, 0, gid); /* Currently logged in */
|
|
||||||
create("/var/log/wtmp", 0644, 0, gid); /* Login history */
|
|
||||||
create("/var/log/btmp", 0600, 0, gid); /* Failed logins */
|
|
||||||
create("/var/log/lastlog", 0644, 0, gid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set BOOT_TIME UTMP entry */
|
/* Set BOOT_TIME UTMP entry */
|
||||||
utmp_set_boot();
|
utmp_set_boot();
|
||||||
|
|
||||||
#ifdef TOUCH_ETC_NETWORK_RUN_IFSTATE
|
|
||||||
touch("/etc/network/run/ifstate");
|
|
||||||
#else
|
|
||||||
erase("/etc/network/run/ifstate");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_d("Setting up misc files ...");
|
|
||||||
makedir("/var/run/network",0755); /* Needed by Debian/Ubuntu ifupdown */
|
|
||||||
makedir("/var/run/lldpd", 0755); /* Needed by lldpd */
|
|
||||||
makedir("/var/run/pluto", 0755); /* Needed by Openswan */
|
|
||||||
mksubsys("/var/run/quagga", 0755, "quagga", "quagga");
|
|
||||||
mksubsys("/var/log/quagga", 0755, "quagga", "quagga");
|
|
||||||
mksubsys("/var/run/frr", 0755, "frr", "frr");
|
|
||||||
mksubsys("/var/log/frr", 0755, "frr", "frr");
|
|
||||||
makedir("/var/run/sshd", 01755); /* OpenSSH */
|
|
||||||
|
|
||||||
if (!fexist("/etc/mtab"))
|
|
||||||
ln("../proc/self/mounts", "/etc/mtab", 1);
|
|
||||||
|
|
||||||
/* Void Linux has a uuidd that runs as uuid:uuid and needs /run/uuid */
|
|
||||||
mksubsys("/var/run/uuidd", 0755, "uuidd", "uuidd");
|
|
||||||
|
|
||||||
/* Debian has /run/sudo, ensure correct perms and SELinux label */
|
|
||||||
mksubsys("/var/run/sudo", 0711, "root", "root");
|
|
||||||
mksubsys("/var/run/sudo/ts", 0700, "root", "root");
|
|
||||||
if (whichp("restorecon"))
|
|
||||||
run("restorecon /var/run/sudo /var/run/sudo/ts");
|
|
||||||
|
|
||||||
umask(prev);
|
umask(prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+103
-28
@@ -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-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -35,60 +35,135 @@
|
|||||||
#include "service.h"
|
#include "service.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
|
||||||
#define DAEMON "dbus-daemon"
|
#define DBUS_DAEMON "dbus-daemon"
|
||||||
#define ARGS "--nofork --system --syslog-only"
|
#define DBUS_ARGS "--nofork --system --syslog-only"
|
||||||
#define DESC "D-Bus message bus daemon"
|
#define DBUS_DESC "D-Bus message bus daemon"
|
||||||
|
|
||||||
#ifndef DAEMONUSER
|
#ifndef DBUS_DAEMONUSER
|
||||||
#define DAEMONUSER "messagebus"
|
#define DBUS_DAEMONUSER "messagebus"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef DAEMONPIDFILE
|
#ifndef DBUS_DAEMONGROUP
|
||||||
#define DAEMONPIDFILE "/var/run/dbus/pid"
|
#define DBUS_DAEMONGROUP "messagebus"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dumnpster diving for the D-Bus main configuration file
|
||||||
|
* where <pidfile> is defined.
|
||||||
|
*/
|
||||||
|
static char *dbus_pidfn(void)
|
||||||
|
{
|
||||||
|
char *alt[] = {
|
||||||
|
"/usr/share/dbus-1/system.conf",
|
||||||
|
"/etc/dbus-1/system.conf",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; alt[i]; i++) {
|
||||||
|
char *fn = alt[i];
|
||||||
|
char buf[256];
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopen(fn, "r");
|
||||||
|
if (!fp)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
fn = NULL;
|
||||||
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
char *pos;
|
||||||
|
|
||||||
|
pos = strstr(buf, "<pidfile>");
|
||||||
|
if (!pos)
|
||||||
|
continue;
|
||||||
|
fn = pos + strlen("<pidfile>");
|
||||||
|
pos = strstr(fn, "</pidfile>");
|
||||||
|
if (!pos) {
|
||||||
|
fn = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*pos = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
if (fn)
|
||||||
|
return strdup(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
{
|
{
|
||||||
|
char *group = DBUS_DAEMONGROUP;
|
||||||
|
char *user = DBUS_DAEMONUSER;
|
||||||
char line[256];
|
char line[256];
|
||||||
|
char *pidfn;
|
||||||
mode_t prev;
|
mode_t prev;
|
||||||
char *cmd;
|
char *cmd;
|
||||||
|
|
||||||
if (rescue) {
|
if (rescue) {
|
||||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = which(DAEMON);
|
cmd = which(DBUS_DAEMON);
|
||||||
if (!cmd) {
|
if (!cmd) {
|
||||||
_d("Skipping plugin, %s is not installed.", DAEMON);
|
dbg("Skipping plugin, %s is not installed.", DBUS_DAEMON);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
prev =umask(0);
|
if (getuser(user, NULL) == -1) {
|
||||||
|
if (getuser("dbus", NULL) == -1)
|
||||||
|
user = "root"; /* fallback */
|
||||||
|
else
|
||||||
|
user = "dbus"; /* e.g., Buildroot */
|
||||||
|
}
|
||||||
|
|
||||||
mksubsys("/var/run/dbus", 0755, DAEMONUSER, DAEMONUSER);
|
if (getgroup(group) == -1) {
|
||||||
if (whichp("dbus-uuidgen"))
|
if (getgroup("dbus") == -1)
|
||||||
run_interactive("dbus-uuidgen --ensure", "Creating machine UUID for D-Bus");
|
group = "root"; /* fallback */
|
||||||
|
else
|
||||||
|
group = "dbus"; /* e.g., Buildroot */
|
||||||
|
}
|
||||||
|
|
||||||
/* Clean up from any previous pre-bootstrap run */
|
/* Clean up from any previous pre-bootstrap run */
|
||||||
remove(DAEMONPIDFILE);
|
pidfn = dbus_pidfn();
|
||||||
|
if (pidfn)
|
||||||
/* Register service with Finit */
|
remove(pidfn);
|
||||||
snprintf(line, sizeof(line), "[S12345789] cgroup.system pid:!%s @%s:%s %s %s -- %s",
|
|
||||||
DAEMONPIDFILE, DAEMONUSER, DAEMONUSER, cmd, ARGS, DESC);
|
|
||||||
if (service_register(SVC_TYPE_SERVICE, line, global_rlimit, NULL))
|
|
||||||
_pe("Failed registering %s", DAEMON);
|
|
||||||
free(cmd);
|
|
||||||
|
|
||||||
|
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);
|
umask(prev);
|
||||||
|
|
||||||
|
/* Generate machine id for dbus */
|
||||||
|
if (whichp("dbus-uuidgen"))
|
||||||
|
run_interactive("dbus-uuidgen --ensure", "Verifying D-Bus machine UUID");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Register service with Finit
|
||||||
|
* Note: dbus drops privs after starting up.
|
||||||
|
*/
|
||||||
|
if (pidfn) {
|
||||||
|
snprintf(line, sizeof(line), "[S123456789] cgroup.system notify:none name:dbus pid:!%s %s %s -- %s",
|
||||||
|
pidfn, cmd, DBUS_ARGS, DBUS_DESC);
|
||||||
|
free(pidfn);
|
||||||
|
} else
|
||||||
|
snprintf(line, sizeof(line), "[S123456789] cgroup.system notify:none name:dbus %s %s -- %s",
|
||||||
|
cmd, DBUS_ARGS, DBUS_DESC);
|
||||||
|
|
||||||
|
conf_save_service(SVC_TYPE_SERVICE, line, "dbus.conf");
|
||||||
|
free(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
.name = __FILE__,
|
.name = __FILE__,
|
||||||
.hook[HOOK_BASEFS_UP] = {
|
.hook[HOOK_SVC_PLUGIN] = { .cb = setup },
|
||||||
.cb = setup
|
|
||||||
},
|
|
||||||
.depends = { "bootmisc", },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
|
|||||||
@@ -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,116 +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;
|
|
||||||
|
|
||||||
if (rescue) {
|
|
||||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Populate /dev and prepare for runtime events from kernel.
|
|
||||||
* Prefer udev if mdev is also available on the system.
|
|
||||||
*/
|
|
||||||
path = which("udevd");
|
|
||||||
if (!path)
|
|
||||||
path = which("/lib/systemd/systemd-udevd");
|
|
||||||
if (path) {
|
|
||||||
/* Register udevd as a monitored service */
|
|
||||||
snprintf(cmd, sizeof(cmd), "[S12345789] cgroup.system pid:udevd name:udevd log %s "
|
|
||||||
"-- Device event managing daemon", path);
|
|
||||||
if (service_register(SVC_TYPE_SERVICE, cmd, global_rlimit, NULL)) {
|
|
||||||
_pe("Failed registering %s", path);
|
|
||||||
} else {
|
|
||||||
snprintf(cmd, sizeof(cmd), "cgroup.init :1 [S] <pid/udevd> log "
|
|
||||||
"udevadm trigger -c add -t devices "
|
|
||||||
"-- Requesting device events");
|
|
||||||
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
|
||||||
|
|
||||||
snprintf(cmd, sizeof(cmd), "cgroup.init :2 [S] <pid/udevd> log "
|
|
||||||
"udevadm trigger -c add -t subsystems "
|
|
||||||
"-- Requesting subsystem events");
|
|
||||||
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(path);
|
|
||||||
|
|
||||||
/* Debian has this little script to copy generated
|
|
||||||
* rules while the system was read-only. TODO: When
|
|
||||||
* this functionality was hardcoded in finit.c, this
|
|
||||||
* call was made in crank_worker(). Now that
|
|
||||||
* filesystems are mounted earlier we should be able
|
|
||||||
* to make this call directly after the triggers have
|
|
||||||
* run, but this has not been tested AT ALL. */
|
|
||||||
if (fexist("/lib/udev/udev-finish"))
|
|
||||||
run_interactive("/lib/udev/udev-finish", "Finalizing udev");
|
|
||||||
} else {
|
|
||||||
path = which("mdev");
|
|
||||||
if (path) {
|
|
||||||
/* Embedded Linux systems usually have BusyBox mdev */
|
|
||||||
if (debug)
|
|
||||||
touch("/dev/mdev.log");
|
|
||||||
|
|
||||||
snprintf(cmd, sizeof(cmd), "%s -s", path);
|
|
||||||
free(path);
|
|
||||||
|
|
||||||
run_interactive(cmd, "Populating device tree");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static plugin_t plugin = {
|
|
||||||
.name = __FILE__,
|
|
||||||
.hook[HOOK_BASEFS_UP] = {
|
|
||||||
.cb = setup
|
|
||||||
},
|
|
||||||
.depends = { "bootmisc" },
|
|
||||||
};
|
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
|
||||||
{
|
|
||||||
plugin_register(&plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
|
||||||
{
|
|
||||||
plugin_unregister(&plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Local Variables:
|
|
||||||
* indent-tabs-mode: t
|
|
||||||
* c-file-style: "linux"
|
|
||||||
* End:
|
|
||||||
*/
|
|
||||||
+72
-13
@@ -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-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -71,14 +71,14 @@ static int modprobe(char *alias)
|
|||||||
pid = fork();
|
pid = fork();
|
||||||
switch (pid) {
|
switch (pid) {
|
||||||
case -1:
|
case -1:
|
||||||
_pe("Failed forking modprobe child");
|
err(1, "Failed forking modprobe child");
|
||||||
return 1;
|
return 1;
|
||||||
case 0:
|
case 0:
|
||||||
execvp(args[0], args);
|
execvp(args[0], args);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (!complete(args[0], pid))
|
if (!complete(args[0], pid))
|
||||||
_d("Successful modprobe of %s", alias);
|
dbg("Successful modprobe of %s", alias);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ static void alias_remove(struct module *m)
|
|||||||
TAILQ_REMOVE(&modules, m, link);
|
TAILQ_REMOVE(&modules, m, link);
|
||||||
free(m->alias);
|
free(m->alias);
|
||||||
free(m);
|
free(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int alias_exist(char *alias)
|
static int alias_exist(char *alias)
|
||||||
{
|
{
|
||||||
@@ -120,27 +120,86 @@ 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 = basenm(path);
|
||||||
|
if (!strcmp(basename, path))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|||||||
+164
-48
@@ -21,6 +21,29 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 preceding one!
|
||||||
|
*/
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
@@ -39,65 +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 \
|
||||||
"cgroup.init :%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], *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)
|
||||||
{
|
{
|
||||||
struct dirent *d;
|
struct dirent **dentry;
|
||||||
char line[256];
|
|
||||||
int index = 1;
|
int index = 1;
|
||||||
FILE *fp;
|
int i, num;
|
||||||
DIR *dir;
|
|
||||||
|
|
||||||
_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);
|
||||||
dir = opendir(MODULES_LOAD_PATH);
|
if (num > 0) {
|
||||||
if (!dir)
|
for (i = 0; i < num; i++) {
|
||||||
return;
|
index += modules_load(dentry[i]->d_name, index);
|
||||||
|
free(dentry[i]);
|
||||||
while ((d = readdir(dir))) {
|
|
||||||
char module_path[PATH_MAX];
|
|
||||||
|
|
||||||
strlcpy(module_path, MODULES_LOAD_PATH "/", sizeof(module_path));
|
|
||||||
strlcat(module_path, d->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);
|
|
||||||
if (!mod)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
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(dir);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
|||||||
+38
-36
@@ -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-2024 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
|
||||||
@@ -61,7 +62,7 @@ static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
int la;
|
int la;
|
||||||
|
|
||||||
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg))) {
|
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg))) {
|
||||||
_e("Packet too small or truncated!");
|
errx(1, "Packet too small or truncated!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,18 +80,18 @@ static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
switch (a->rta_type) {
|
switch (a->rta_type) {
|
||||||
case RTA_GATEWAY:
|
case RTA_GATEWAY:
|
||||||
gw = *((int *)data);
|
gw = *((int *)data);
|
||||||
//_d("GW: 0x%04x", gw);
|
//dbg("GW: 0x%04x", gw);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTA_DST:
|
case RTA_DST:
|
||||||
dst = *((int *)data);
|
dst = *((int *)data);
|
||||||
plen = r->rtm_dst_len;
|
plen = r->rtm_dst_len;
|
||||||
//_d("Prefix LEN: 0x%04x", plen);
|
//dbg("Prefix LEN: 0x%04x", plen);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTA_OIF:
|
case RTA_OIF:
|
||||||
idx = *((int *)data);
|
idx = *((int *)data);
|
||||||
//_d("IDX: 0x%04x", idx);
|
//dbg("IDX: 0x%04x", idx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +102,7 @@ static void nl_route(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
ing.s_addr = gw;
|
ing.s_addr = gw;
|
||||||
inet_ntop(AF_INET, &ind, daddr, sizeof(daddr));
|
inet_ntop(AF_INET, &ind, daddr, sizeof(daddr));
|
||||||
inet_ntop(AF_INET, &ing, gaddr, sizeof(gaddr));
|
inet_ntop(AF_INET, &ing, gaddr, sizeof(gaddr));
|
||||||
_d("Got gw %s dst/len %s/%d ifindex %d", gaddr, daddr, plen, idx);
|
dbg("Got gw %s dst/len %s/%d ifindex %d", gaddr, daddr, plen, idx);
|
||||||
|
|
||||||
if ((!dst && !plen) && (gw || idx)) {
|
if ((!dst && !plen) && (gw || idx)) {
|
||||||
if (nlmsg->nlmsg_type == RTM_DELROUTE) {
|
if (nlmsg->nlmsg_type == RTM_DELROUTE) {
|
||||||
@@ -166,7 +167,7 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
int la;
|
int la;
|
||||||
|
|
||||||
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) {
|
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) {
|
||||||
_e("Packet too small or truncated!");
|
errx(1, "Packet too small or truncated!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,7 +195,7 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
* New interface has appeared, or interface flags has changed.
|
* New interface has appeared, or interface flags has changed.
|
||||||
* Check ifi_flags here to see if the interface is UP/DOWN
|
* Check ifi_flags here to see if the interface is UP/DOWN
|
||||||
*/
|
*/
|
||||||
_d("%s: New link, flags 0x%x, change 0x%x", ifname, i->ifi_flags, i->ifi_change);
|
dbg("%s: New link, flags 0x%x, change 0x%x", ifname, i->ifi_flags, i->ifi_change);
|
||||||
net_cond_set(ifname, "exist", 1);
|
net_cond_set(ifname, "exist", 1);
|
||||||
net_cond_set(ifname, "up", i->ifi_flags & IFF_UP);
|
net_cond_set(ifname, "up", i->ifi_flags & IFF_UP);
|
||||||
net_cond_set(ifname, "running", i->ifi_flags & IFF_RUNNING);
|
net_cond_set(ifname, "running", i->ifi_flags & IFF_RUNNING);
|
||||||
@@ -204,7 +205,7 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
|
|
||||||
case RTM_DELLINK:
|
case RTM_DELLINK:
|
||||||
/* NOTE: Interface has disappeared, not link down ... */
|
/* NOTE: Interface has disappeared, not link down ... */
|
||||||
_d("%s: Delete link", ifname);
|
dbg("%s: Delete link", ifname);
|
||||||
net_cond_set(ifname, "exist", 0);
|
net_cond_set(ifname, "exist", 0);
|
||||||
net_cond_set(ifname, "up", 0);
|
net_cond_set(ifname, "up", 0);
|
||||||
net_cond_set(ifname, "running", 0);
|
net_cond_set(ifname, "running", 0);
|
||||||
@@ -212,15 +213,15 @@ static void nl_link(struct nlmsghdr *nlmsg, ssize_t len)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case RTM_NEWADDR:
|
case RTM_NEWADDR:
|
||||||
_d("%s: New Address", ifname);
|
dbg("%s: New Address", ifname);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTM_DELADDR:
|
case RTM_DELADDR:
|
||||||
_d("%s: Deconfig Address", ifname);
|
dbg("%s: Deconfig Address", ifname);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_d("%s: Msg 0x%x", ifname, nlmsg->nlmsg_type);
|
dbg("%s: Msg 0x%x", ifname, nlmsg->nlmsg_type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -245,46 +246,46 @@ static int nl_parse(int sd)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_pe("recv()");
|
err(1, "recv()");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("recv %lld bytes", len);
|
// dbg("recv %zd bytes", len);
|
||||||
l = (size_t)len;
|
l = (size_t)len;
|
||||||
for (nh = (struct nlmsghdr *)nl_buf; NLMSG_OK(nh, l); nh = NLMSG_NEXT(nh, l)) {
|
for (nh = (struct nlmsghdr *)nl_buf; NLMSG_OK(nh, l); nh = NLMSG_NEXT(nh, l)) {
|
||||||
struct nlmsgerr *nle;
|
struct nlmsgerr *nle;
|
||||||
|
|
||||||
switch (nh->nlmsg_type) {
|
switch (nh->nlmsg_type) {
|
||||||
case NLMSG_DONE:
|
case NLMSG_DONE:
|
||||||
_d("Done with netlink messages.");
|
// dbg("Done with netlink messages.");
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case NLMSG_ERROR:
|
case NLMSG_ERROR:
|
||||||
_d("Kernel netlink comm. error.");
|
// dbg("Kernel netlink comm. error.");
|
||||||
nle = NLMSG_DATA(nh);
|
nle = NLMSG_DATA(nh);
|
||||||
if (nle) {
|
if (nle) {
|
||||||
errno = -nle->error;
|
errno = -nle->error;
|
||||||
_pe("Kernel netlink error %d", errno);
|
err(1, "Kernel netlink error %d", errno);
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
case RTM_NEWROUTE:
|
case RTM_NEWROUTE:
|
||||||
case RTM_DELROUTE:
|
case RTM_DELROUTE:
|
||||||
_d("Netlink route ...");
|
// dbg("Netlink route ...");
|
||||||
nl_route(nh, len);
|
nl_route(nh, len);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTM_NEWLINK:
|
case RTM_NEWLINK:
|
||||||
case RTM_DELLINK:
|
case RTM_DELLINK:
|
||||||
_d("Netlink link ...");
|
// dbg("Netlink link ...");
|
||||||
nl_link(nh, len);
|
nl_link(nh, len);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_w("unhandled netlink message, type %d", nh->nlmsg_type);
|
warnx("unhandled netlink message, type %d", nh->nlmsg_type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -303,21 +304,21 @@ static int nl_request(int sd, unsigned int seq, int type)
|
|||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case RTM_GETROUTE:
|
case RTM_GETROUTE:
|
||||||
_d("RTM_GETROUTE");
|
// dbg("RTM_GETROUTE");
|
||||||
nlr->rtm.rtm_family = AF_INET;
|
nlr->rtm.rtm_family = AF_INET;
|
||||||
nlr->rtm.rtm_table = RT_TABLE_MAIN;
|
nlr->rtm.rtm_table = RT_TABLE_MAIN;
|
||||||
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTM_GETLINK:
|
case RTM_GETLINK:
|
||||||
_d("RTM_GETLINK");
|
// dbg("RTM_GETLINK");
|
||||||
nlr->ifi.ifi_family = AF_UNSPEC;
|
nlr->ifi.ifi_family = AF_UNSPEC;
|
||||||
nlr->ifi.ifi_change = 0xFFFFFFFF;
|
nlr->ifi.ifi_change = 0xFFFFFFFF;
|
||||||
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
nlr->nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_w("Cannot resync, unhandled message type %d", type);
|
warnx("Cannot resync, unhandled message type %d", type);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,13 +331,13 @@ static int nl_request(int sd, unsigned int seq, int type)
|
|||||||
static void nl_resync_routes(int sd, unsigned int seq)
|
static void nl_resync_routes(int sd, unsigned int seq)
|
||||||
{
|
{
|
||||||
if (nl_request(sd, seq, RTM_GETROUTE))
|
if (nl_request(sd, seq, RTM_GETROUTE))
|
||||||
_pe("Failed netlink route request");
|
err(1, "Failed netlink route request");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nl_resync_ifaces(int sd, unsigned int seq)
|
static void nl_resync_ifaces(int sd, unsigned int seq)
|
||||||
{
|
{
|
||||||
if (nl_request(sd, seq, RTM_GETLINK))
|
if (nl_request(sd, seq, RTM_GETLINK))
|
||||||
_pe("Failed netlink link request");
|
err(1, "Failed netlink link request");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -349,12 +350,12 @@ static void nl_resync(int all)
|
|||||||
|
|
||||||
sd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
|
sd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
|
||||||
if (sd < 0) {
|
if (sd < 0) {
|
||||||
_pe("netlink socket");
|
err(1, "netlink socket");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (all) {
|
if (all) {
|
||||||
_d("============================ RESYNC =================================");
|
dbg("============================ RESYNC =================================");
|
||||||
/* this doesn't update conditions, and thus does not stop services */
|
/* this doesn't update conditions, and thus does not stop services */
|
||||||
cond_deassert("net/");
|
cond_deassert("net/");
|
||||||
|
|
||||||
@@ -363,7 +364,7 @@ static void nl_resync(int all)
|
|||||||
|
|
||||||
/* delayed update after we've corrected things */
|
/* delayed update after we've corrected things */
|
||||||
service_step_all(SVC_TYPE_ANY);
|
service_step_all(SVC_TYPE_ANY);
|
||||||
_d("=========================== RESYNCED ================================");
|
dbg("=========================== RESYNCED ================================");
|
||||||
} else
|
} else
|
||||||
nl_resync_routes(sd, seq++);
|
nl_resync_routes(sd, seq++);
|
||||||
|
|
||||||
@@ -374,7 +375,7 @@ static void nl_callback(void *arg, int sd, int events)
|
|||||||
{
|
{
|
||||||
if (nl_parse(sd) < 0) {
|
if (nl_parse(sd) < 0) {
|
||||||
if (errno == ENOBUFS) { /* netlink(7) */
|
if (errno == ENOBUFS) { /* netlink(7) */
|
||||||
_w("busy system, resynchronizing with kernel.");
|
warnx("busy system, resynchronizing with kernel.");
|
||||||
nl_resync(1);
|
nl_resync(1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -385,7 +386,7 @@ static void nl_callback(void *arg, int sd, int events)
|
|||||||
* we need to check ourselves, e.g. for loss of default route.
|
* we need to check ourselves, e.g. for loss of default route.
|
||||||
*/
|
*/
|
||||||
if (nl_ifdown) {
|
if (nl_ifdown) {
|
||||||
_d("interface down, checking default route.");
|
dbg("interface down, checking default route.");
|
||||||
if (nl_defidx > 0) {
|
if (nl_defidx > 0) {
|
||||||
nl_defidx = 0;
|
nl_defidx = 0;
|
||||||
nl_resync(0);
|
nl_resync(0);
|
||||||
@@ -420,7 +421,7 @@ PLUGIN_INIT(plugin_init)
|
|||||||
|
|
||||||
sd = socket(AF_NETLINK, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, NETLINK_ROUTE);
|
sd = socket(AF_NETLINK, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, NETLINK_ROUTE);
|
||||||
if (sd < 0) {
|
if (sd < 0) {
|
||||||
_pe("socket()");
|
err(1, "socket()");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -430,14 +431,14 @@ PLUGIN_INIT(plugin_init)
|
|||||||
sa.nl_pid = getpid();
|
sa.nl_pid = getpid();
|
||||||
|
|
||||||
if (bind(sd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
if (bind(sd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
||||||
_pe("bind()");
|
err(1, "bind()");
|
||||||
close(sd);
|
close(sd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nl_buf = malloc(NL_BUFSZ);
|
nl_buf = malloc(NL_BUFSZ);
|
||||||
if (!nl_buf) {
|
if (!nl_buf) {
|
||||||
_pe("malloc()");
|
err(1, "malloc()");
|
||||||
close(sd);
|
close(sd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -449,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+61
-28
@@ -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-2024 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 %s", path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,48 +66,78 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
|
|||||||
char cond[MAX_COND_LEN];
|
char cond[MAX_COND_LEN];
|
||||||
char fn[PATH_MAX];
|
char fn[PATH_MAX];
|
||||||
svc_t *svc;
|
svc_t *svc;
|
||||||
|
char *nm;
|
||||||
|
|
||||||
paste(fn, sizeof(fn), dir, name);
|
paste(fn, sizeof(fn), dir, name);
|
||||||
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);
|
/* Service condistion to set/clear */
|
||||||
|
|
||||||
mkcond(svc, cond, sizeof(cond));
|
mkcond(svc, cond, sizeof(cond));
|
||||||
|
|
||||||
|
nm = svc_ident(svc, NULL, 0);
|
||||||
|
dbg("Found svc %s for %s with pid %d", nm, fn, svc->pid);
|
||||||
|
if (svc_is_stopping(svc)) {
|
||||||
|
dbg("Ignoring pidfile death rattles while service %s is %s", nm, svc_status(svc));
|
||||||
|
goto sneaky_zebra;
|
||||||
|
}
|
||||||
|
|
||||||
if (mask & (IN_CLOSE_WRITE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) {
|
if (mask & (IN_CLOSE_WRITE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) {
|
||||||
svc_started(svc);
|
/*
|
||||||
|
* only mark native services as started, the s6 and
|
||||||
|
* systemd style services rely on their respective
|
||||||
|
* readiness notification. Issue #343
|
||||||
|
*/
|
||||||
|
if (svc->notify == SVC_NOTIFY_PID)
|
||||||
|
svc_started(svc);
|
||||||
|
|
||||||
if (!svc_has_pidfile(svc)) {
|
if (!svc_has_pidfile(svc)) {
|
||||||
_d("Setting %s PID file to %s", svc->name, fn);
|
dbg("Setting %s PID file to %s", svc->name, fn);
|
||||||
pid_file_set(svc, fn, 1);
|
pid_file_set(svc, fn, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (svc_is_forking(svc)) {
|
if (svc_is_forking(svc)) {
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
pid = pid_file_read(pid_file(svc));
|
pid = pid_file_read(fn);
|
||||||
if (pid == -1) {
|
if (pid == -1) {
|
||||||
cond_clear(cond);
|
/* handle case when service dies immediately */
|
||||||
|
if (!fexist(fn))
|
||||||
|
cond_clear(cond);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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);
|
if (svc->notify == SVC_NOTIFY_PID)
|
||||||
} else if (mask & IN_DELETE)
|
cond_set(cond);
|
||||||
|
if (svc->notify == SVC_NOTIFY_PID || svc->notify == SVC_NOTIFY_NONE)
|
||||||
|
service_ready(svc, 1);
|
||||||
|
} else if (mask & IN_DELETE) {
|
||||||
|
sneaky_zebra:
|
||||||
cond_clear(cond);
|
cond_clear(cond);
|
||||||
|
if (svc->notify == SVC_NOTIFY_PID)
|
||||||
|
service_ready(svc, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* synthesize events in case of new run dirs */
|
/* synthesize events in case of new run dirs */
|
||||||
@@ -129,7 +159,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);
|
||||||
@@ -144,7 +174,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);
|
||||||
|
|
||||||
@@ -168,7 +198,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;
|
||||||
@@ -220,6 +250,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 == SVC_NOTIFY_PID)
|
||||||
|
service_ready(svc, 1);
|
||||||
|
|
||||||
mkcond(svc, cond, sizeof(cond));
|
mkcond(svc, cond, sizeof(cond));
|
||||||
if (cond_get(cond) == COND_ON)
|
if (cond_get(cond) == COND_ON)
|
||||||
continue;
|
continue;
|
||||||
@@ -228,9 +261,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);
|
||||||
@@ -242,7 +275,7 @@ static void pidfile_init(void *arg)
|
|||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
if (mkpath(pid_runpath(_PATH_CONDPID, piddir, sizeof(piddir)), 0755) && errno != EEXIST) {
|
if (mkpath(pid_runpath(_PATH_CONDPID, piddir, sizeof(piddir)), 0755) && errno != EEXIST) {
|
||||||
_pe("Failed creating %s condition directory, %s", COND_PID, _PATH_CONDPID);
|
err(1, "Failed creating %s condition directory, %s", COND_PID, _PATH_CONDPID);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,10 +286,10 @@ static void pidfile_init(void *arg)
|
|||||||
*/
|
*/
|
||||||
path = realpath(_PATH_VARRUN, NULL);
|
path = realpath(_PATH_VARRUN, NULL);
|
||||||
if (!path) {
|
if (!path) {
|
||||||
_d("Failed querying realpath(%s): %s", _PATH_VARRUN, strerror(errno));
|
dbg("Failed querying realpath(%s): %s", _PATH_VARRUN, strerror(errno));
|
||||||
path = realpath("/run", NULL);
|
path = realpath("/run", NULL);
|
||||||
if (!path) {
|
if (!path) {
|
||||||
_e("System does not have %s or /run, aborting.", _PATH_VARRUN);
|
errx(1, "System does not have %s or /run, aborting.", _PATH_VARRUN);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -277,15 +310,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)
|
||||||
@@ -305,8 +338,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+12
-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-2024 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
|
||||||
@@ -32,14 +32,16 @@
|
|||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
|
||||||
|
#ifndef SYSCTL_PATH
|
||||||
|
#define SYSCTL_PATH "/sbin/sysctl"
|
||||||
|
#endif
|
||||||
|
|
||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
{
|
{
|
||||||
size_t i;
|
|
||||||
glob_t gl;
|
glob_t gl;
|
||||||
char buf[160];
|
|
||||||
|
|
||||||
if (rescue) {
|
if (rescue) {
|
||||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,9 +53,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), "%s -e -p %s >/dev/null", SYSCTL_PATH, 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-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
*/
|
*/
|
||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
{
|
{
|
||||||
_d("Setting up the resolver ...");
|
dbg("Setting up the resolver ...");
|
||||||
mkpath("/etc/resolvconf", 0755);
|
mkpath("/etc/resolvconf", 0755);
|
||||||
mkpath("/etc/resolvconf/run", 0755);
|
mkpath("/etc/resolvconf/run", 0755);
|
||||||
mkpath("/var/run/resolvconf", 0755);
|
mkpath("/var/run/resolvconf", 0755);
|
||||||
@@ -45,7 +45,7 @@ static void setup(void *arg)
|
|||||||
|
|
||||||
touch("/etc/resolvconf/run/enable-updates");
|
touch("/etc/resolvconf/run/enable-updates");
|
||||||
chdir("/etc/resolvconf/run/interface");
|
chdir("/etc/resolvconf/run/interface");
|
||||||
run_parts("/etc/resolvconf/update.d", "-i");
|
run_parts("/etc/resolvconf/update.d", "-i", NULL, 0, 0);
|
||||||
chdir("/");
|
chdir("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+196
-61
@@ -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-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -21,6 +21,8 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <linux/rtc.h>
|
#include <linux/rtc.h>
|
||||||
@@ -34,8 +36,25 @@
|
|||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
|
||||||
/* Kernel RTC driver validates against this date for sanity check */
|
/*
|
||||||
#define RTC_TIMESTAMP_BEGIN_2000 946684800LL /* 2000-01-01 00:00:00 */
|
* Kernel RTC driver validates against this date for sanity check. The
|
||||||
|
* on NTP sync the driver can also update the RTC every 11 mins. We use
|
||||||
|
* the same update interval to handle manual time set and file save.
|
||||||
|
*/
|
||||||
|
#define RTC_TIMESTAMP_BEGIN_2000 "2000-01-01 00:00:00"
|
||||||
|
#define RTC_FMT "%Y-%m-%d %H:%M:%S"
|
||||||
|
#define RTC_PERIOD (11 * 60 * 1000)
|
||||||
|
|
||||||
|
#ifdef RTC_TIMESTAMP_CUSTOM
|
||||||
|
static char *rtc_timestamp = RTC_TIMESTAMP_CUSTOM;
|
||||||
|
#else
|
||||||
|
static char *rtc_timestamp = RTC_TIMESTAMP_BEGIN_2000;
|
||||||
|
#endif
|
||||||
|
static time_t rtc_date_fallback = 946684800LL;
|
||||||
|
|
||||||
|
static char *rtc_file = RTC_FILE;
|
||||||
|
static uev_t rtc_timer;
|
||||||
|
|
||||||
|
|
||||||
static void tz_set(char *tz, size_t len)
|
static void tz_set(char *tz, size_t len)
|
||||||
{
|
{
|
||||||
@@ -60,6 +79,125 @@ static void tz_restore(char *tz)
|
|||||||
tzset();
|
tzset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int time_set(struct tm *tm)
|
||||||
|
{
|
||||||
|
struct tm fallback = { 0 };
|
||||||
|
struct timeval tv = { 0 };
|
||||||
|
char tz[128];
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
tz_set(tz, sizeof(tz));
|
||||||
|
|
||||||
|
if (!tm) {
|
||||||
|
logit(LOG_NOTICE, "Resetting system clock to kernel default, %s.", rtc_timestamp);
|
||||||
|
tm = &fallback;
|
||||||
|
|
||||||
|
/* Attempt to set RTC to a sane value ... */
|
||||||
|
tv.tv_sec = rtc_date_fallback;
|
||||||
|
if (!gmtime_r(&tv.tv_sec, tm)) {
|
||||||
|
rc = 1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tm->tm_isdst = -1; /* Use tzdata to figure it out, please. */
|
||||||
|
tv.tv_sec = mktime(tm);
|
||||||
|
if (tv.tv_sec == (time_t)-1 || tv.tv_sec < rtc_date_fallback) {
|
||||||
|
errno = EINVAL;
|
||||||
|
rc = 2;
|
||||||
|
} else {
|
||||||
|
if (settimeofday(&tv, NULL) == -1)
|
||||||
|
rc = 1;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
tz_restore(tz);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int time_get(struct tm *tm)
|
||||||
|
{
|
||||||
|
struct timeval tv = { 0 };
|
||||||
|
char tz[128];
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
tz_set(tz, sizeof(tz));
|
||||||
|
|
||||||
|
rc = gettimeofday(&tv, NULL);
|
||||||
|
if (rc < 0 || tv.tv_sec < rtc_date_fallback)
|
||||||
|
rc = 2;
|
||||||
|
else
|
||||||
|
gmtime_r(&tv.tv_sec, tm);
|
||||||
|
|
||||||
|
tz_restore(tz);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void file_save(void *arg)
|
||||||
|
{
|
||||||
|
struct tm tm = { 0 };
|
||||||
|
int rc = 0;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
if (!rtc_file)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fp = fopen(rtc_file, "w");
|
||||||
|
if (!fp) {
|
||||||
|
logit(LOG_WARNING, "Failed saving system clock to %s, code %d: %s",
|
||||||
|
rtc_file, errno, strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((rc = time_get(&tm))) {
|
||||||
|
logit(LOG_WARNING, "System clock invalid, before %s, not saving", rtc_timestamp);
|
||||||
|
print_desc(NULL, "System clock invalid, skipping");
|
||||||
|
} else {
|
||||||
|
char buf[32] = { 0 };
|
||||||
|
|
||||||
|
print_desc(NULL, "Saving system clock to file");
|
||||||
|
strftime(buf, sizeof(buf), RTC_FMT, &tm);
|
||||||
|
fprintf(fp, "%s\n", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
print(rc, NULL);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void file_restore(void *arg)
|
||||||
|
{
|
||||||
|
struct tm tm = { 0 };
|
||||||
|
int rc = 1;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
if (!rtc_file) {
|
||||||
|
logit(LOG_NOTICE, "System has no RTC (missing driver?), skipping restore.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_desc(NULL, "Restoring system clock from backup");
|
||||||
|
|
||||||
|
fp = fopen(rtc_file, "r");
|
||||||
|
if (fp) {
|
||||||
|
char buf[32];
|
||||||
|
|
||||||
|
if (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
chomp(buf);
|
||||||
|
strptime(buf, RTC_FMT, &tm);
|
||||||
|
rc = time_set(&tm);
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
} else
|
||||||
|
logit(LOG_WARNING, "Missing %s", rtc_file);
|
||||||
|
|
||||||
|
if (rc) {
|
||||||
|
time_set(NULL);
|
||||||
|
rc = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
print(rc, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static int rtc_open(void)
|
static int rtc_open(void)
|
||||||
{
|
{
|
||||||
char *alt[] = {
|
char *alt[] = {
|
||||||
@@ -83,13 +221,11 @@ static int rtc_open(void)
|
|||||||
|
|
||||||
static void rtc_save(void *arg)
|
static void rtc_save(void *arg)
|
||||||
{
|
{
|
||||||
struct timeval tv = { 0 };
|
|
||||||
struct tm tm = { 0 };
|
struct tm tm = { 0 };
|
||||||
int fd, rc = 0;
|
int fd, rc = 0;
|
||||||
char tz[128];
|
|
||||||
|
|
||||||
if (rescue) {
|
if (rescue) {
|
||||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,113 +233,112 @@ static void rtc_save(void *arg)
|
|||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
tz_set(tz, sizeof(tz));
|
if ((rc = time_get(&tm))) {
|
||||||
rc = gettimeofday(&tv, NULL);
|
|
||||||
if (rc < 0 || tv.tv_sec < RTC_TIMESTAMP_BEGIN_2000) {
|
|
||||||
print_desc(NULL, "System clock invalid, not saving to RTC");
|
print_desc(NULL, "System clock invalid, not saving to RTC");
|
||||||
invalid:
|
} else {
|
||||||
logit(LOG_ERR, "System clock invalid, before 2000-01-01 00:00, not saving to RTC");
|
print_desc(NULL, "Saving system clock (UTC) to RTC");
|
||||||
|
rc = ioctl(fd, RTC_SET_TIME, &tm);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc && errno == EINVAL) {
|
||||||
|
logit(LOG_WARNING, "System clock invalid, before %s, not saving to RTC", rtc_timestamp);
|
||||||
rc = 2;
|
rc = 2;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
print_desc(NULL, "Saving system time (UTC) to RTC");
|
|
||||||
|
|
||||||
gmtime_r(&tv.tv_sec, &tm);
|
|
||||||
if (ioctl(fd, RTC_SET_TIME, &tm) < 0) {
|
|
||||||
if (EINVAL == errno)
|
|
||||||
goto invalid;
|
|
||||||
rc = 1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
tz_restore(tz);
|
|
||||||
print(rc, NULL);
|
print(rc, NULL);
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtc_restore(void *arg)
|
static void rtc_restore(void *arg)
|
||||||
{
|
{
|
||||||
struct timeval tv = { 0 };
|
|
||||||
struct tm tm = { 0 };
|
struct tm tm = { 0 };
|
||||||
int fd, rc = 0;
|
int fd, rc = 0;
|
||||||
char tz[128];
|
|
||||||
|
|
||||||
if (rescue) {
|
if (rescue) {
|
||||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = rtc_open();
|
fd = rtc_open();
|
||||||
if (fd < 0)
|
if (fd < 0) {
|
||||||
|
file_restore(arg);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
tz_set(tz, sizeof(tz));
|
if ((rc = ioctl(fd, RTC_RD_TIME, &tm)) < 0) {
|
||||||
if (ioctl(fd, RTC_RD_TIME, &tm) < 0) {
|
|
||||||
char msg[120];
|
char msg[120];
|
||||||
|
|
||||||
snprintf(msg, sizeof(msg), "Failed restoring system clock, %s",
|
snprintf(msg, sizeof(msg), "Failed restoring system clock, %s",
|
||||||
EINVAL == errno ? "RTC time is too old" :
|
EINVAL == errno ? "RTC time is too old" :
|
||||||
ENOENT == errno ? "RTC has no saved time" : "see log for details");
|
ENOENT == errno ? "RTC has no saved time" : "see log for details");
|
||||||
print_desc(NULL, msg);
|
print_desc(NULL, msg);
|
||||||
|
} else {
|
||||||
|
print_desc(NULL, "Restoring system clock (UTC) from RTC");
|
||||||
|
rc = time_set(&tm);
|
||||||
|
}
|
||||||
|
|
||||||
invalid:
|
if (rc) {
|
||||||
logit(LOG_ERR, "Failed restoring system clock from RTC.");
|
logit(LOG_WARNING, "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_WARNING, "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_WARNING, "RTC has no previously saved (valid) time.");
|
||||||
else
|
else
|
||||||
logit(LOG_ERR, "RTC error code %d: %s", errno, strerror(errno));
|
logit(LOG_WARNING, "RTC error code %d: %s", errno, strerror(errno));
|
||||||
|
|
||||||
/* Been here already? */
|
print(2, NULL);
|
||||||
if (rc)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* Attempt to set RTC to a sane value ... */
|
/* Try restoring from last save game */
|
||||||
tv.tv_sec = RTC_TIMESTAMP_BEGIN_2000;
|
if (rtc_file)
|
||||||
if (!gmtime_r(&tv.tv_sec, &tm))
|
file_restore(arg);
|
||||||
goto out;
|
} else
|
||||||
|
print(0, NULL);
|
||||||
|
|
||||||
logit(LOG_NOTICE, "Resetting RTC to kernel default, 2000-01-01 00:00.");
|
|
||||||
rc = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
print_desc(NULL, "Restoring system clock (UTC) from RTC");
|
|
||||||
tm.tm_isdst = -1; /* Use tzdata to figure it out, please. */
|
|
||||||
tv.tv_sec = mktime(&tm);
|
|
||||||
if (tv.tv_sec < RTC_TIMESTAMP_BEGIN_2000) {
|
|
||||||
errno = EINVAL;
|
|
||||||
goto invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (settimeofday(&tv, NULL) == -1)
|
|
||||||
rc = 1;
|
|
||||||
|
|
||||||
out:
|
|
||||||
tz_restore(tz);
|
|
||||||
print(rc, NULL);
|
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void save(void *arg)
|
||||||
|
{
|
||||||
|
rtc_save(arg);
|
||||||
|
file_save(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update(uev_t *w, void *arg, int events)
|
||||||
|
{
|
||||||
|
save(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
.name = __FILE__,
|
.name = __FILE__,
|
||||||
.hook[HOOK_BASEFS_UP] = {
|
.hook[HOOK_BASEFS_UP] = {
|
||||||
.cb = rtc_restore
|
.cb = rtc_restore
|
||||||
},
|
},
|
||||||
.hook[HOOK_SHUTDOWN] = {
|
.hook[HOOK_SHUTDOWN] = {
|
||||||
.cb = rtc_save
|
.cb = save
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
{
|
{
|
||||||
|
struct tm tm = { 0 };
|
||||||
|
|
||||||
|
if (!strptime(rtc_timestamp, RTC_FMT, &tm)) {
|
||||||
|
logit(LOG_WARNING, "Invalid restore date '%s', reverting to '%s'",
|
||||||
|
rtc_timestamp, RTC_TIMESTAMP_BEGIN_2000);
|
||||||
|
rtc_timestamp = RTC_TIMESTAMP_BEGIN_2000;
|
||||||
|
} else
|
||||||
|
rtc_date_fallback = mktime(&tm);
|
||||||
|
|
||||||
|
uev_timer_init(ctx, &rtc_timer, update, NULL, RTC_PERIOD, RTC_PERIOD);
|
||||||
|
|
||||||
plugin_register(&plugin);
|
plugin_register(&plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(plugin_exit)
|
||||||
{
|
{
|
||||||
|
uev_timer_stop(&rtc_timer);
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-9
@@ -1,6 +1,6 @@
|
|||||||
/* System condition event monitor for the Finit condition engine
|
/* System condition event monitor for the Finit condition engine
|
||||||
*
|
*
|
||||||
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2021-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -63,7 +63,7 @@ static void sys_update_conds(char *dir, char *name, uint32_t mask)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
cond += strlen(COND_BASE) + 1;
|
cond += strlen(COND_BASE) + 1;
|
||||||
_d("cond: %s set: %d", cond, mask & IN_CREATE ? 1 : 0);
|
dbg("cond: %s set: %d", cond, (mask & IN_CREATE) ? 1 : 0);
|
||||||
if (!cond_update(cond))
|
if (!cond_update(cond))
|
||||||
unlink(path);
|
unlink(path);
|
||||||
}
|
}
|
||||||
@@ -82,7 +82,7 @@ static void sys_scandir(struct iwatch *iw, char *dir, int len)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
for (i = 0; i < gl.gl_pathc; i++) {
|
for (i = 0; i < gl.gl_pathc; i++) {
|
||||||
_d("scan found %s", gl.gl_pathv[i]);
|
dbg("scan found %s", gl.gl_pathv[i]);
|
||||||
sys_update_conds(dir, gl.gl_pathv[i], IN_CREATE);
|
sys_update_conds(dir, gl.gl_pathv[i], IN_CREATE);
|
||||||
}
|
}
|
||||||
globfree(&gl);
|
globfree(&gl);
|
||||||
@@ -97,7 +97,7 @@ static void sys_handle_dir(struct iwatch *iw, char *dir, char *name, int mask)
|
|||||||
struct iwatch_path *iwp;
|
struct iwatch_path *iwp;
|
||||||
|
|
||||||
paste(path, sizeof(path), dir, name);
|
paste(path, sizeof(path), dir, name);
|
||||||
_d("path: %s", path);
|
dbg("path: %s", path);
|
||||||
|
|
||||||
iwp = iwatch_find_by_path(iw, path);
|
iwp = iwatch_find_by_path(iw, path);
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ static void sys_callback(void *arg, int fd, int events)
|
|||||||
|
|
||||||
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
||||||
if (sz <= 0) {
|
if (sz <= 0) {
|
||||||
_pe("invalid inotify event");
|
err(1, "invalid inotify event");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ev_buf[sz] = 0;
|
ev_buf[sz] = 0;
|
||||||
@@ -136,7 +136,7 @@ static void sys_callback(void *arg, int fd, int events)
|
|||||||
if (off + sizeof(*ev) + ev->len > (size_t)sz)
|
if (off + sizeof(*ev) + ev->len > (size_t)sz)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
_d("name %s, event: 0x%08x", ev->name, ev->mask);
|
dbg("name %s, event: 0x%08x", ev->name, ev->mask);
|
||||||
if (!ev->mask)
|
if (!ev->mask)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -160,24 +160,28 @@ static void sys_init(void *arg)
|
|||||||
char sysdir[MAX_ARG_LEN];
|
char sysdir[MAX_ARG_LEN];
|
||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
|
mkpath(_PATH_COND, 0755);
|
||||||
if (mkpath(pid_runpath(_PATH_CONDSYS, sysdir, sizeof(sysdir)), 0755) && errno != EEXIST) {
|
if (mkpath(pid_runpath(_PATH_CONDSYS, sysdir, sizeof(sysdir)), 0755) && errno != EEXIST) {
|
||||||
_pe("Failed creating %s condition directory, %s", COND_SYS, _PATH_CONDSYS);
|
err(1, "Failed creating %s condition directory, %s", COND_SYS, _PATH_CONDSYS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
path = realpath(_PATH_CONDSYS, NULL);
|
path = realpath(_PATH_CONDSYS, NULL);
|
||||||
if (!path) {
|
if (!path) {
|
||||||
_pe("Cannot figure out real path to %s, aborting", _PATH_CONDSYS);
|
err(1, "Cannot figure out real path to %s, aborting", _PATH_CONDSYS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iwatch_add(&iw_sys, path, IN_ONLYDIR))
|
if (iwatch_add(&iw_sys, path, IN_ONLYDIR))
|
||||||
iwatch_exit(&iw_sys);
|
iwatch_exit(&iw_sys);
|
||||||
|
|
||||||
|
free(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
.name = __FILE__,
|
.name = __FILE__,
|
||||||
.hook[HOOK_BASEFS_UP] = { .cb = sys_init },
|
.hook[HOOK_BASEFS_UP] = { .cb = sys_init },
|
||||||
|
.depends = { "bootmisc", },
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
@@ -197,8 +201,8 @@ PLUGIN_INIT(plugin_init)
|
|||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(plugin_exit)
|
||||||
{
|
{
|
||||||
iwatch_exit(&iw_sys);
|
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
|
iwatch_exit(&iw_sys);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+7
-8
@@ -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-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -55,7 +55,7 @@ static void setup(void)
|
|||||||
|
|
||||||
plugin.io.fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
plugin.io.fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
||||||
if (-1 == plugin.io.fd || inotify_add_watch(plugin.io.fd, "/dev", IN_CREATE | IN_DELETE) < 0)
|
if (-1 == plugin.io.fd || inotify_add_watch(plugin.io.fd, "/dev", IN_CREATE | IN_DELETE) < 0)
|
||||||
_pe("Failed starting TTY watcher");
|
err(1, "Failed starting TTY watcher");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_tty(char *tty, size_t len, int creat)
|
static void do_tty(char *tty, size_t len, int creat)
|
||||||
@@ -67,10 +67,10 @@ static void do_tty(char *tty, size_t len, int creat)
|
|||||||
svc = svc_find_by_tty(name);
|
svc = svc_find_by_tty(name);
|
||||||
if (svc) {
|
if (svc) {
|
||||||
if (svc_is_blocked(svc) && creat) {
|
if (svc_is_blocked(svc) && creat) {
|
||||||
_d("%s: blocked, re-enabling", svc_ident(svc, NULL, 0));
|
dbg("%s: blocked, re-enabling", svc_ident(svc, NULL, 0));
|
||||||
svc_start(svc);
|
svc_start(svc);
|
||||||
} else if (svc->pid) {
|
} else if (svc->pid) {
|
||||||
_d("%s: missing ...", svc_ident(svc, NULL, 0));
|
dbg("%s: missing ...", svc_ident(svc, NULL, 0));
|
||||||
svc_missing(svc);
|
svc_missing(svc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ static void tty_watcher(void *arg, int fd, int events)
|
|||||||
|
|
||||||
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
||||||
if (sz <= 0) {
|
if (sz <= 0) {
|
||||||
_pe("invalid inotify event");
|
err(1, "invalid inotify event");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ev_buf[sz] = 0;
|
ev_buf[sz] = 0;
|
||||||
@@ -103,7 +103,7 @@ static void tty_watcher(void *arg, int fd, int events)
|
|||||||
if (!ev->mask)
|
if (!ev->mask)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_d("tty %s, event: 0x%08x", ev->name, ev->mask);
|
dbg("tty %s, event: 0x%08x", ev->name, ev->mask);
|
||||||
do_tty(ev->name, ev->len, ev->mask & IN_CREATE);
|
do_tty(ev->name, ev->len, ev->mask & IN_CREATE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+53
-14
@@ -1,6 +1,6 @@
|
|||||||
/* Setup and save random seed at boot/shutdown
|
/* Setup and save random seed at boot/shutdown
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2012-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* 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
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
#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 <sys/resource.h> /* getrusage() */
|
||||||
#ifdef _LIBITE_LITE
|
#ifdef _LIBITE_LITE
|
||||||
# include <libite/lite.h>
|
# include <libite/lite.h>
|
||||||
#else
|
#else
|
||||||
@@ -42,20 +43,52 @@
|
|||||||
#define RANDOM_BYTES (32*1024)
|
#define RANDOM_BYTES (32*1024)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef RANDOMSEED
|
||||||
|
/*
|
||||||
|
* This is the fallback seed function, please make sure you have drivers
|
||||||
|
* enabling /dev/hwrng instead.
|
||||||
|
*/
|
||||||
|
static void fallback(FILE *fp)
|
||||||
|
{
|
||||||
|
unsigned long seed;
|
||||||
|
struct timeval tv;
|
||||||
|
struct rusage ru;
|
||||||
|
int iter = 128;
|
||||||
|
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
getrusage(RUSAGE_SELF, &ru);
|
||||||
|
|
||||||
|
/* Mix multiple sources of "randomness" */
|
||||||
|
seed = tv.tv_sec ^ (tv.tv_usec << 16);
|
||||||
|
seed ^= ru.ru_utime.tv_sec ^ (ru.ru_utime.tv_usec << 16);
|
||||||
|
seed ^= ru.ru_stime.tv_sec ^ (ru.ru_stime.tv_usec << 16);
|
||||||
|
seed ^= getpid() << 8;
|
||||||
|
|
||||||
|
srandom(seed);
|
||||||
|
while (iter--) {
|
||||||
|
uint32_t i, prng = random();
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(prng); i++)
|
||||||
|
fputc((prng >> (i * CHAR_BIT)) & UCHAR_MAX, fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
{
|
{
|
||||||
#ifdef RANDOMSEED
|
#ifdef RANDOMSEED
|
||||||
struct rand_pool_info *rpi;
|
struct rand_pool_info *rpi;
|
||||||
ssize_t len = 0;
|
ssize_t len = 0;
|
||||||
|
struct stat st;
|
||||||
int rc = -1;
|
int rc = -1;
|
||||||
int fd, err;
|
int fd, err;
|
||||||
|
|
||||||
if (rescue) {
|
if (rescue) {
|
||||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fexist(RANDOMSEED)) {
|
if (stat(RANDOMSEED, &st) || st.st_size < 512) {
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
mode_t prev;
|
mode_t prev;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
@@ -64,16 +97,22 @@ static void setup(void *arg)
|
|||||||
prev = umask(077);
|
prev = umask(077);
|
||||||
fp = fopen(RANDOMSEED, "w");
|
fp = fopen(RANDOMSEED, "w");
|
||||||
if (fp) {
|
if (fp) {
|
||||||
int iter = 128;
|
const char *hwrng = "/dev/hwrng";
|
||||||
struct timeval tv;
|
FILE *hw;
|
||||||
|
|
||||||
gettimeofday(&tv, NULL);
|
hw = fopen(hwrng, "r");
|
||||||
srandom(tv.tv_sec % 3600);
|
if (hw) {
|
||||||
while (iter--) {
|
char buf[512];
|
||||||
uint32_t i, prng = random();
|
size_t len;
|
||||||
|
|
||||||
for (i = 0; i < sizeof(prng); i++)
|
len = fread(buf, sizeof(buf[0]), sizeof(buf), hw);
|
||||||
fputc((prng >> (i * CHAR_BIT)) & UCHAR_MAX, fp);
|
if (len == 0)
|
||||||
|
fallback(fp);
|
||||||
|
else
|
||||||
|
len = fwrite(buf, sizeof(buf[0]), len, fp);
|
||||||
|
fclose(hw);
|
||||||
|
} else {
|
||||||
|
fallback(fp);
|
||||||
}
|
}
|
||||||
ret = fclose(fp);
|
ret = fclose(fp);
|
||||||
}
|
}
|
||||||
@@ -81,7 +120,7 @@ static void setup(void *arg)
|
|||||||
umask(prev);
|
umask(prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
print_desc("Initializing random number generator", NULL);
|
print_desc("Seeding random number generator", NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Simply copying our saved entropy to /dev/urandom doesn't
|
* Simply copying our saved entropy to /dev/urandom doesn't
|
||||||
@@ -130,7 +169,7 @@ static void setup(void *arg)
|
|||||||
close(fd);
|
close(fd);
|
||||||
free(rpi);
|
free(rpi);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
logit(LOG_ERR, "Failed adding entropy to kernel random pool: %s", strerror(err));
|
logit(LOG_WARNING, "Failed adding entropy to kernel random pool: %s", strerror(err));
|
||||||
print_result(rc < 0);
|
print_result(rc < 0);
|
||||||
return;
|
return;
|
||||||
fallback:
|
fallback:
|
||||||
@@ -144,7 +183,7 @@ static void save(void *arg)
|
|||||||
mode_t prev;
|
mode_t prev;
|
||||||
|
|
||||||
if (rescue) {
|
if (rescue) {
|
||||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-6
@@ -1,6 +1,6 @@
|
|||||||
/* User-defined condition event monitor for the Finit condition engine
|
/* User-defined condition event monitor for the Finit condition engine
|
||||||
*
|
*
|
||||||
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2021-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -52,7 +52,7 @@ static void usr_callback(void *arg, int fd, int events)
|
|||||||
|
|
||||||
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
||||||
if (sz <= 0) {
|
if (sz <= 0) {
|
||||||
_pe("invalid inotify event");
|
err(1, "invalid inotify event");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ev_buf[sz] = 0;
|
ev_buf[sz] = 0;
|
||||||
@@ -65,7 +65,7 @@ static void usr_callback(void *arg, int fd, int events)
|
|||||||
if (off + sizeof(*ev) + ev->len > (size_t)sz)
|
if (off + sizeof(*ev) + ev->len > (size_t)sz)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
_d("name %s, event: 0x%08x", ev->name, ev->mask);
|
dbg("name %s, event: 0x%08x", ev->name, ev->mask);
|
||||||
if (!ev->mask)
|
if (!ev->mask)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -84,14 +84,15 @@ static void usr_init(void *arg)
|
|||||||
char usrdir[MAX_ARG_LEN];
|
char usrdir[MAX_ARG_LEN];
|
||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
|
mkpath(_PATH_COND, 0755);
|
||||||
if (mkpath(pid_runpath(_PATH_CONDUSR, usrdir, sizeof(usrdir)), 0755) && errno != EEXIST) {
|
if (mkpath(pid_runpath(_PATH_CONDUSR, usrdir, sizeof(usrdir)), 0755) && errno != EEXIST) {
|
||||||
_pe("Failed creating %s condition directory, %s", COND_USR, _PATH_CONDUSR);
|
err(1, "Failed creating %s condition directory, %s", COND_USR, _PATH_CONDUSR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
path = realpath(_PATH_CONDUSR, NULL);
|
path = realpath(_PATH_CONDUSR, NULL);
|
||||||
if (!path) {
|
if (!path) {
|
||||||
_pe("Cannot figure out real path to %s, aborting", _PATH_CONDUSR);
|
err(1, "Cannot figure out real path to %s, aborting", _PATH_CONDUSR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,6 +105,7 @@ static void usr_init(void *arg)
|
|||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
.name = __FILE__,
|
.name = __FILE__,
|
||||||
.hook[HOOK_BASEFS_UP] = { .cb = usr_init },
|
.hook[HOOK_BASEFS_UP] = { .cb = usr_init },
|
||||||
|
.depends = { "bootmisc", },
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
@@ -123,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+5
-34
@@ -1,6 +1,6 @@
|
|||||||
/* Console setup (for X)
|
/* Console setup (for X)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2012-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -36,47 +36,18 @@
|
|||||||
|
|
||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
{
|
{
|
||||||
const char *username = "nobody";
|
|
||||||
char line[LINE_SIZE];
|
|
||||||
mode_t prev;
|
|
||||||
#ifdef PAM_CONSOLE
|
|
||||||
int fd;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (rescue) {
|
if (rescue) {
|
||||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
dbg("Skipping %s plugin in rescue mode.", __FILE__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
prev = umask(0);
|
if (fexist("/var/run/console/console.lock") && which("pam_console_apply"))
|
||||||
|
run("pam_console_apply", "pam-console");
|
||||||
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);
|
|
||||||
makedir("/tmp/.ICE-unix", 01777);
|
|
||||||
|
|
||||||
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)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ initctl
|
|||||||
keventd
|
keventd
|
||||||
logit
|
logit
|
||||||
reboot
|
reboot
|
||||||
|
runparts
|
||||||
sulogin
|
sulogin
|
||||||
watchdogd
|
watchdogd
|
||||||
Makefile
|
Makefile
|
||||||
|
|||||||
+19
-4
@@ -8,7 +8,10 @@ AM_LDFLAGS = -export-dynamic
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
sbin_PROGRAMS = finit initctl
|
sbin_PROGRAMS = finit initctl
|
||||||
pkglibexec_PROGRAMS = getty logit sulogin
|
pkglibexec_PROGRAMS = getty logit runparts
|
||||||
|
if SULOGIN
|
||||||
|
pkglibexec_PROGRAMS += sulogin
|
||||||
|
endif
|
||||||
if KEVENTD
|
if KEVENTD
|
||||||
pkglibexec_PROGRAMS += keventd
|
pkglibexec_PROGRAMS += keventd
|
||||||
endif
|
endif
|
||||||
@@ -16,6 +19,8 @@ if WATCHDOGD
|
|||||||
pkglibexec_PROGRAMS += watchdogd
|
pkglibexec_PROGRAMS += watchdogd
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
dist_pkglibexec_SCRIPTS = coldplug
|
||||||
|
|
||||||
finit_pkglibdir = $(pkglibdir)
|
finit_pkglibdir = $(pkglibdir)
|
||||||
finit_pkglib_SCRIPTS = rescue.conf sample.conf
|
finit_pkglib_SCRIPTS = rescue.conf sample.conf
|
||||||
|
|
||||||
@@ -29,6 +34,11 @@ keventd_CFLAGS = -W -Wall -Wextra -std=gnu99
|
|||||||
keventd_CFLAGS += $(lite_CFLAGS)
|
keventd_CFLAGS += $(lite_CFLAGS)
|
||||||
keventd_LDADD = $(lite_LIBS)
|
keventd_LDADD = $(lite_LIBS)
|
||||||
|
|
||||||
|
runparts_SOURCES = runparts.c
|
||||||
|
runparts_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||||
|
runparts_CFLAGS += $(lite_CFLAGS)
|
||||||
|
runparts_LDADD = $(lite_LIBS)
|
||||||
|
|
||||||
sulogin_SOURCES = sulogin.c
|
sulogin_SOURCES = sulogin.c
|
||||||
sulogin_CFLAGS = -W -Wall -Wextra -std=gnu99
|
sulogin_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||||
sulogin_LDADD = -lcrypt
|
sulogin_LDADD = -lcrypt
|
||||||
@@ -39,8 +49,10 @@ logit_CFLAGS += $(lite_CFLAGS)
|
|||||||
logit_LDADD = $(lite_LIBS)
|
logit_LDADD = $(lite_LIBS)
|
||||||
|
|
||||||
finit_SOURCES = api.c cgroup.c cgroup.h \
|
finit_SOURCES = api.c cgroup.c cgroup.h \
|
||||||
|
client.c client.h \
|
||||||
cond.c cond-w.c cond.h \
|
cond.c cond-w.c cond.h \
|
||||||
conf.c conf.h \
|
conf.c conf.h \
|
||||||
|
devmon.c devmon.h \
|
||||||
exec.c finit.c finit.h \
|
exec.c finit.c finit.h \
|
||||||
stty.c \
|
stty.c \
|
||||||
helpers.c helpers.h \
|
helpers.c helpers.h \
|
||||||
@@ -49,11 +61,12 @@ finit_SOURCES = api.c cgroup.c cgroup.h \
|
|||||||
mdadm.c mount.c \
|
mdadm.c mount.c \
|
||||||
pid.c pid.h \
|
pid.c pid.h \
|
||||||
plugin.c plugin.h private.h \
|
plugin.c plugin.h private.h \
|
||||||
schedule.c schedule.h \
|
runparts.c schedule.c schedule.h \
|
||||||
service.c service.h \
|
service.c service.h \
|
||||||
sig.c sig.h \
|
sig.c sig.h \
|
||||||
sm.c sm.h \
|
sm.c sm.h \
|
||||||
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
|
||||||
@@ -61,8 +74,10 @@ if LOGROTATE
|
|||||||
finit_SOURCES += logrotate.c
|
finit_SOURCES += logrotate.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
pkginclude_HEADERS = cgroup.h cond.h finit.h helpers.h log.h plugin.h svc.h
|
pkginclude_HEADERS = cgroup.h cond.h conf.h finit.h helpers.h log.h \
|
||||||
|
plugin.h svc.h service.h
|
||||||
|
|
||||||
|
finit_CPPFLAGS = $(AM_CPPFLAGS) -D__FINIT__
|
||||||
finit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
finit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||||
finit_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
|
finit_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
|
||||||
finit_LDADD = $(lite_LIBS) $(uev_LIBS)
|
finit_LDADD = $(lite_LIBS) $(uev_LIBS)
|
||||||
@@ -74,7 +89,7 @@ endif
|
|||||||
|
|
||||||
initctl_SOURCES = initctl.c initctl.h cgutil.c cgutil.h \
|
initctl_SOURCES = initctl.c initctl.h cgutil.c cgutil.h \
|
||||||
client.c client.h cond.c cond.h reboot.c \
|
client.c client.h cond.c cond.h reboot.c \
|
||||||
serv.c serv.h svc.h util.c util.h
|
serv.c serv.h svc.h util.c util.h log.h
|
||||||
initctl_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
initctl_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||||
initctl_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
|
initctl_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
|
||||||
initctl_LDADD = $(lite_LIBS) $(uev_LIBS)
|
initctl_LDADD = $(lite_LIBS) $(uev_LIBS)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* External client API, using UNIX domain socket.
|
/* External client API, using UNIX domain socket.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2015-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* 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>
|
||||||
@@ -36,7 +38,6 @@
|
|||||||
#endif
|
#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"
|
||||||
@@ -44,36 +45,40 @@
|
|||||||
#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;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -83,25 +88,30 @@ static int start(svc_t *svc)
|
|||||||
* responsibility of initctl to do. Otherwise we'd block PID 1,
|
* responsibility of initctl to do. Otherwise we'd block PID 1,
|
||||||
* or introduce some nasty race conditions.
|
* or introduce some nasty race conditions.
|
||||||
*/
|
*/
|
||||||
static int restart(svc_t *svc)
|
static int restart(svc_t *svc, void *user_data)
|
||||||
{
|
{
|
||||||
if (!svc)
|
if (!svc)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
svc_mark_dirty(svc);
|
if (!svc_is_running(svc))
|
||||||
svc_start(svc);
|
return start(svc, user_data);
|
||||||
|
|
||||||
|
service_timeout_cancel(svc);
|
||||||
|
service_stop(svc);
|
||||||
service_step(svc);
|
service_step(svc);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int reload(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);
|
||||||
@@ -114,8 +124,28 @@ static int do_start (char *buf, size_t len) { return call(start, buf, len); }
|
|||||||
static int do_restart(char *buf, size_t len) { return call(restart, buf, len); }
|
static int do_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_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];
|
||||||
|
|
||||||
@@ -133,7 +163,7 @@ 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)
|
||||||
{
|
{
|
||||||
query_buf[0] = 0;
|
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;
|
||||||
}
|
}
|
||||||
@@ -177,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,7 +322,7 @@ static void send_svc(int sd, svc_t *svc)
|
|||||||
|
|
||||||
len = write(sd, svc, sizeof(*svc));
|
len = write(sd, svc, sizeof(*svc));
|
||||||
if (len != sizeof(*svc))
|
if (len != sizeof(*svc))
|
||||||
_d("Failed sending svc_t to client");
|
dbg("Failed sending svc_t to client");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void api_cb(uev_t *w, void *arg, int events)
|
static void api_cb(uev_t *w, void *arg, int events)
|
||||||
@@ -279,9 +332,14 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
int sd, lvl;
|
int sd, lvl;
|
||||||
svc_t *svc;
|
svc_t *svc;
|
||||||
|
|
||||||
|
if (UEV_ERROR == events) {
|
||||||
|
dbg("%s(): api socket %d invalid.", __func__, w->fd);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,19 +356,51 @@ 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_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)) {
|
||||||
|
strterm(rq.data, sizeof(rq.data));
|
||||||
|
warnx("Unsupported command (cmd: %d, data: %s) in runlevel S and 6/0.",
|
||||||
|
rq.cmd, rq.data);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (rq.cmd) {
|
switch (rq.cmd) {
|
||||||
case INIT_CMD_RUNLVL:
|
case INIT_CMD_RUNLVL:
|
||||||
|
/* Allow changing cfglevel in runlevel S */
|
||||||
|
if (IS_RESERVED_RUNLEVEL(runlevel)) {
|
||||||
|
if (runlevel != INIT_LEVEL) {
|
||||||
|
warnx("Cannot abort runlevel 6/0.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (rq.runlevel) {
|
switch (rq.runlevel) {
|
||||||
case 's':
|
case 's':
|
||||||
case 'S':
|
case 'S':
|
||||||
@@ -318,57 +408,70 @@ 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;
|
||||||
if (lvl == 6)
|
if (lvl == 6)
|
||||||
halt = SHUT_REBOOT;
|
halt = SHUT_REBOOT;
|
||||||
service_runlevel(lvl);
|
|
||||||
|
/* User requested change in next runlevel */
|
||||||
|
if (runlevel == INIT_LEVEL)
|
||||||
|
cfglevel = lvl;
|
||||||
|
else
|
||||||
|
service_runlevel(lvl);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_d("Unsupported runlevel: %d", rq.runlevel);
|
dbg("Unsupported runlevel: %d", rq.runlevel);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_DEBUG:
|
case INIT_CMD_DEBUG:
|
||||||
_d("debug");
|
dbg("debug");
|
||||||
log_debug();
|
log_debug();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_RELOAD: /* 'init q' and 'initctl reload' */
|
case INIT_CMD_RELOAD: /* 'init q' and 'initctl reload' */
|
||||||
_d("reload");
|
dbg("reload");
|
||||||
service_reload_dynamic();
|
service_reload_dynamic();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_START_SVC:
|
case INIT_CMD_START_SVC:
|
||||||
_d("start %s", rq.data);
|
dbg("start %s", rq.data);
|
||||||
strterm(rq.data, sizeof(rq.data));
|
strterm(rq.data, sizeof(rq.data));
|
||||||
result = do_start(rq.data, sizeof(rq.data));
|
result = do_start(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_RESTART_SVC:
|
case INIT_CMD_RESTART_SVC:
|
||||||
_d("restart %s", rq.data);
|
dbg("restart %s", rq.data);
|
||||||
strterm(rq.data, sizeof(rq.data));
|
strterm(rq.data, sizeof(rq.data));
|
||||||
result = do_restart(rq.data, sizeof(rq.data));
|
result = do_restart(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_STOP_SVC:
|
case INIT_CMD_STOP_SVC:
|
||||||
_d("stop %s", rq.data);
|
dbg("stop %s", rq.data);
|
||||||
strterm(rq.data, sizeof(rq.data));
|
strterm(rq.data, sizeof(rq.data));
|
||||||
result = do_stop(rq.data, sizeof(rq.data));
|
result = do_stop(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_RELOAD_SVC:
|
case INIT_CMD_RELOAD_SVC:
|
||||||
_d("reload %s", rq.data);
|
dbg("reload %s", rq.data);
|
||||||
strterm(rq.data, sizeof(rq.data));
|
strterm(rq.data, sizeof(rq.data));
|
||||||
result = do_reload(rq.data, sizeof(rq.data));
|
result = do_reload(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case INIT_CMD_GET_PLUGINS:
|
||||||
|
result = plugin_list(rq.data, sizeof(rq.data));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INIT_CMD_PLUGIN_DEPS:
|
||||||
|
result = plugin_deps(rq.data, sizeof(rq.data));
|
||||||
|
break;
|
||||||
|
|
||||||
case INIT_CMD_GET_RUNLEVEL:
|
case INIT_CMD_GET_RUNLEVEL:
|
||||||
_d("get runlevel");
|
dbg("get runlevel");
|
||||||
rq.runlevel = runlevel;
|
rq.runlevel = runlevel;
|
||||||
rq.sleeptime = prevlevel;
|
rq.sleeptime = prevlevel;
|
||||||
break;
|
break;
|
||||||
@@ -377,21 +480,21 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
case INIT_CMD_HALT:
|
case INIT_CMD_HALT:
|
||||||
case INIT_CMD_POWEROFF:
|
case INIT_CMD_POWEROFF:
|
||||||
case INIT_CMD_SUSPEND:
|
case INIT_CMD_SUSPEND:
|
||||||
result = do_reboot(rq.cmd, rq.data, sizeof(rq.data));
|
result = do_reboot(rq.cmd, rq.sleeptime, rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_ACK:
|
case INIT_CMD_ACK:
|
||||||
_d("Client failed reading ACK");
|
dbg("Client failed reading ACK");
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
case INIT_CMD_WDOG_HELLO:
|
case INIT_CMD_WDOG_HELLO:
|
||||||
_d("wdog hello");
|
dbg("wdog hello");
|
||||||
if (rq.runlevel <= 0) {
|
if (rq.runlevel <= 0) {
|
||||||
result = 1;
|
result = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("Request to hand-over wdog ... to PID %d", rq.runlevel);
|
dbg("Request to hand-over wdog ... to PID %d", rq.runlevel);
|
||||||
svc = svc_find_by_pid(rq.runlevel);
|
svc = svc_find_by_pid(rq.runlevel);
|
||||||
if (!svc) {
|
if (!svc) {
|
||||||
logit(LOG_ERR, "Cannot find PID %d, not registered.", rq.runlevel);
|
logit(LOG_ERR, "Cannot find PID %d, not registered.", rq.runlevel);
|
||||||
@@ -407,7 +510,7 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
|
|
||||||
if (wdog->protect) {
|
if (wdog->protect) {
|
||||||
logit(LOG_NOTICE, "Stopping and deleting built-in watchdog.");
|
logit(LOG_NOTICE, "Stopping and deleting built-in watchdog.");
|
||||||
stop(wdog);
|
stop(wdog, NULL);
|
||||||
svc_del(wdog);
|
svc_del(wdog);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -415,7 +518,7 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_SVC_ITER:
|
case INIT_CMD_SVC_ITER:
|
||||||
// _d("svc iter, first: %d", rq.runlevel);
|
// dbg("svc iter, first: %d", rq.runlevel);
|
||||||
/*
|
/*
|
||||||
* XXX: This severely limits the number of
|
* XXX: This severely limits the number of
|
||||||
* simultaneous client connections, but will
|
* simultaneous client connections, but will
|
||||||
@@ -426,25 +529,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, "Failed 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,18 +578,16 @@ 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:
|
||||||
close(sd);
|
close(sd);
|
||||||
if (UEV_ERROR == events)
|
|
||||||
goto error;
|
|
||||||
return;
|
return;
|
||||||
error:
|
error:
|
||||||
api_exit();
|
api_exit();
|
||||||
if (api_init(w->ctx))
|
if (api_init(w->ctx))
|
||||||
_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)
|
||||||
@@ -478,10 +600,10 @@ int api_init(uev_ctx_t *ctx)
|
|||||||
int uid, gid;
|
int uid, gid;
|
||||||
int sd;
|
int sd;
|
||||||
|
|
||||||
_d("Setting up external API socket ...");
|
dbg("Setting up external API socket ...");
|
||||||
sd = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
|
sd = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
|
||||||
if (-1 == sd) {
|
if (-1 == sd) {
|
||||||
_pe("Failed starting external API socket");
|
err(1, "Failed starting external API socket");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -497,14 +619,14 @@ int api_init(uev_ctx_t *ctx)
|
|||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (chown(INIT_SOCKET, uid, gid))
|
if (chown(INIT_SOCKET, uid, gid))
|
||||||
_pe("Failed setting group %s on %s", DEFGROUP, INIT_SOCKET);
|
err(1, "Failed setting group %s on %s", DEFGROUP, INIT_SOCKET);
|
||||||
|
|
||||||
umask(oldmask);
|
umask(oldmask);
|
||||||
if (!uev_io_init(ctx, &api_watcher, api_cb, NULL, sd, UEV_READ))
|
if (!uev_io_init(ctx, &api_watcher, api_cb, NULL, sd, UEV_READ))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
_pe("Failed initializing API socket");
|
err(1, "Failed initializing API socket");
|
||||||
umask(oldmask);
|
umask(oldmask);
|
||||||
close(sd);
|
close(sd);
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
+67
-36
@@ -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-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -63,16 +63,16 @@ static void cgset(const char *path, char *ctrl, char *prop)
|
|||||||
{
|
{
|
||||||
char *val;
|
char *val;
|
||||||
|
|
||||||
_d("path %s, ctrl %s, prop %s", path ?: "NIL", ctrl ?: "NIL", prop ?: "NIL");
|
dbg("path %s, ctrl %s, prop %s", path ?: "NIL", ctrl ?: "NIL", prop ?: "NIL");
|
||||||
if (!path || !ctrl) {
|
if (!path || !ctrl) {
|
||||||
_e("Missing path or controller, skipping!");
|
errx(1, "Missing path or controller, skipping!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!prop) {
|
if (!prop) {
|
||||||
prop = strchr(ctrl, '.');
|
prop = strchr(ctrl, '.');
|
||||||
if (!prop) {
|
if (!prop) {
|
||||||
_e("Invalid cgroup ctrl syntax: %s", ctrl);
|
errx(1, "Invalid cgroup ctrl syntax: %s", ctrl);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,20 +81,20 @@ static void cgset(const char *path, char *ctrl, char *prop)
|
|||||||
|
|
||||||
val = strchr(prop, ':');
|
val = strchr(prop, ':');
|
||||||
if (!val) {
|
if (!val) {
|
||||||
_e("Missing cgroup ctrl value, prop %s", prop);
|
errx(1, "Missing cgroup ctrl value, prop %s", prop);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*val++ = 0;
|
*val++ = 0;
|
||||||
|
|
||||||
/* disallow sneaky relative paths */
|
/* disallow sneaky relative paths */
|
||||||
if (strstr(ctrl, "..") || strstr(prop, "..")) {
|
if (strstr(ctrl, "..") || strstr(prop, "..")) {
|
||||||
_e("Possible security violation; '..' not allowed in cgroup config!");
|
errx(1, "Possible security violation; '..' not allowed in cgroup config!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("%s/%s.%s <= %s", path, ctrl, prop, val);
|
dbg("%s/%s.%s <= %s", path, ctrl, prop, val);
|
||||||
if (fnwrite(val, "%s/%s.%s", path, ctrl, prop))
|
if (fnwrite(val, "%s/%s.%s", path, ctrl, prop))
|
||||||
_pe("Failed setting %s/%s.%s = %s", path, ctrl, prop, val);
|
err(1, "Failed setting %s/%s.%s = %s", path, ctrl, prop, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -106,16 +106,16 @@ static void group_init(char *path, int leaf, const char *cfg)
|
|||||||
{
|
{
|
||||||
char *ptr, *s;
|
char *ptr, *s;
|
||||||
|
|
||||||
_d("path %s, leaf %d, cfg %s", path, leaf, cfg ?: "NIL");
|
dbg("path %s, leaf %d, cfg %s", path, leaf, cfg ?: "NIL");
|
||||||
if (!fisdir(path)) {
|
if (!fisdir(path)) {
|
||||||
if (mkdir(path, 0755)) {
|
if (mkdir(path, 0755)) {
|
||||||
_pe("Failed creating cgroup %s", path);
|
err(1, "Failed creating cgroup %s", path);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* enable detected controllers on domain groups */
|
/* enable detected controllers on domain groups */
|
||||||
if (!leaf && fnwrite(controllers, "%s/cgroup.subtree_control", path))
|
if (!leaf && fnwrite(controllers, "%s/cgroup.subtree_control", path))
|
||||||
_pe("Failed enabling %s for %s", controllers, path);
|
err(1, "Failed enabling %s for %s", controllers, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cfg || !cfg[0])
|
if (!cfg || !cfg[0])
|
||||||
@@ -123,14 +123,14 @@ static void group_init(char *path, int leaf, const char *cfg)
|
|||||||
|
|
||||||
s = strdupa(cfg);
|
s = strdupa(cfg);
|
||||||
if (!s) {
|
if (!s) {
|
||||||
_pe("Failed activating cgroup cfg for %s", path);
|
err(1, "Failed activating cgroup cfg for %s", path);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("%s <=> %s", path, s);
|
dbg("%s <=> %s", path, s);
|
||||||
ptr = strtok(s, ",");
|
ptr = strtok(s, ",");
|
||||||
while (ptr) {
|
while (ptr) {
|
||||||
_d("ptr: %s", ptr);
|
dbg("ptr: %s", ptr);
|
||||||
if (!strncmp("mem.", ptr, 4))
|
if (!strncmp("mem.", ptr, 4))
|
||||||
cgset(path, "memory", &ptr[4]);
|
cgset(path, "memory", &ptr[4]);
|
||||||
else
|
else
|
||||||
@@ -144,7 +144,7 @@ static int cgroup_leaf_init(char *group, char *name, int pid, const char *cfg)
|
|||||||
{
|
{
|
||||||
char path[256];
|
char path[256];
|
||||||
|
|
||||||
_d("group %s, name %s, pid %d, cfg %s", group, name, pid, cfg ?: "NIL");
|
dbg("group %s, name %s, pid %d, cfg %s", group, name, pid, cfg ?: "NIL");
|
||||||
if (pid < 0 || pid == 1) {
|
if (pid < 0 || pid == 1) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return 1;
|
return 1;
|
||||||
@@ -156,7 +156,7 @@ static int cgroup_leaf_init(char *group, char *name, int pid, const char *cfg)
|
|||||||
|
|
||||||
/* move process to new group */
|
/* move process to new group */
|
||||||
if (fnwrite(str("%d", pid), "%s/cgroup.procs", path))
|
if (fnwrite(str("%d", pid), "%s/cgroup.procs", path))
|
||||||
_pe("Failed moving pid %d to group %s", pid, path);
|
err(1, "Failed moving pid %d to group %s", pid, path);
|
||||||
|
|
||||||
strlcat(path, "/cgroup.events", sizeof(path));
|
strlcat(path, "/cgroup.events", sizeof(path));
|
||||||
|
|
||||||
@@ -211,13 +211,13 @@ static void cgroup_handle_event(char *event, uint32_t mask)
|
|||||||
char *ptr;
|
char *ptr;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
_d("event: '%s', mask: %08x", event, mask);
|
dbg("event: '%s', mask: %08x", event, mask);
|
||||||
if (!(mask & IN_MODIFY))
|
if (!(mask & IN_MODIFY))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fp = fopen(event, "r");
|
fp = fopen(event, "r");
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
_d("Failed opening %s, skipping ...", event);
|
dbg("Failed opening %s, skipping ...", event);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,9 +259,14 @@ static void cgroup_events_cb(uev_t *w, void *arg, int events)
|
|||||||
ssize_t sz;
|
ssize_t sz;
|
||||||
size_t off;
|
size_t off;
|
||||||
|
|
||||||
|
if (UEV_ERROR == events) {
|
||||||
|
dbg("%s(): inotify socket %d invalid.", __func__, w->fd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
sz = read(w->fd, ev_buf, sizeof(ev_buf) - 1);
|
sz = read(w->fd, ev_buf, sizeof(ev_buf) - 1);
|
||||||
if (sz <= 0) {
|
if (sz <= 0) {
|
||||||
_pe("invalid inotify event");
|
err(1, "invalid inotify event");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ev_buf[sz] = 0;
|
ev_buf[sz] = 0;
|
||||||
@@ -287,7 +292,7 @@ static void cgroup_events_cb(uev_t *w, void *arg, int events)
|
|||||||
cgroup_handle_event(iwp->path, ev->mask);
|
cgroup_handle_event(iwp->path, ev->mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_AUTO_RELOAD
|
#ifdef AUTO_RELOAD
|
||||||
if (conf_any_change())
|
if (conf_any_change())
|
||||||
service_reload_dynamic();
|
service_reload_dynamic();
|
||||||
#endif
|
#endif
|
||||||
@@ -364,12 +369,12 @@ int cgroup_add(char *name, char *cfg, int is_protected)
|
|||||||
if (!cg) {
|
if (!cg) {
|
||||||
cg = malloc(sizeof(struct cg));
|
cg = malloc(sizeof(struct cg));
|
||||||
if (!cg) {
|
if (!cg) {
|
||||||
_pe("Failed allocating 'struct cg' for %s", name);
|
err(1, "Failed allocating 'struct cg' for %s", name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
cg->name = strdup(name);
|
cg->name = strdup(name);
|
||||||
if (!cg->name) {
|
if (!cg->name) {
|
||||||
_pe("Failed setting cgroup name %s", name);
|
err(1, "Failed setting cgroup name %s", name);
|
||||||
free(cg);
|
free(cg);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -379,7 +384,7 @@ int cgroup_add(char *name, char *cfg, int is_protected)
|
|||||||
|
|
||||||
cg->cfg = strdup(cfg);
|
cg->cfg = strdup(cfg);
|
||||||
if (!cg->cfg) {
|
if (!cg->cfg) {
|
||||||
_pe("Failed add/update of cgroup %s", name);
|
err(1, "Failed add/update of cgroup %s", name);
|
||||||
TAILQ_REMOVE(&cgroups, cg, link);
|
TAILQ_REMOVE(&cgroups, cg, link);
|
||||||
free(cg->name);
|
free(cg->name);
|
||||||
free(cg);
|
free(cg);
|
||||||
@@ -414,7 +419,7 @@ int cgroup_del(char *dir)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rmdir(dir) && errno != ENOENT) {
|
if (rmdir(dir) && errno != ENOENT) {
|
||||||
_d("Failed removing %s: %s", dir, strerror(errno));
|
dbg("Failed removing %s: %s", dir, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -463,11 +468,18 @@ void cgroup_init(uev_ctx_t *ctx)
|
|||||||
FILE *fp;
|
FILE *fp;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
|
#ifndef CGROUP2_ENABLED
|
||||||
|
avail = 0;
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (mount("none", FINIT_CGPATH, "cgroup2", opts, NULL)) {
|
if (mount("none", FINIT_CGPATH, "cgroup2", opts, NULL)) {
|
||||||
if (errno == ENOENT)
|
if (errno == ENOENT)
|
||||||
logit(LOG_NOTICE, "Kernel does not support cgroups v2, disabling.");
|
logit(LOG_INFO, "Kernel does not support cgroups v2, disabling.");
|
||||||
|
else if (errno == EPERM) /* Probably inside an unprivileged container */
|
||||||
|
logit(LOG_INFO, "Not allowed to mount cgroups v2, disabling.");
|
||||||
else
|
else
|
||||||
_pe("Failed mounting cgroup v2, disabling.");
|
err(1, "Failed mounting cgroup v2");
|
||||||
avail = 0;
|
avail = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -476,7 +488,8 @@ void cgroup_init(uev_ctx_t *ctx)
|
|||||||
/* Find available controllers */
|
/* Find available controllers */
|
||||||
fp = fopen(FINIT_CGPATH "/cgroup.controllers", "r");
|
fp = fopen(FINIT_CGPATH "/cgroup.controllers", "r");
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
_pe("Failed opening %s", FINIT_CGPATH "/cgroup.controllers");
|
err(1, "Failed opening %s", FINIT_CGPATH "/cgroup.controllers");
|
||||||
|
abort:
|
||||||
umount(FINIT_CGPATH);
|
umount(FINIT_CGPATH);
|
||||||
avail = 0;
|
avail = 0;
|
||||||
return;
|
return;
|
||||||
@@ -494,9 +507,29 @@ void cgroup_init(uev_ctx_t *ctx)
|
|||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
|
/* Check for cpu controller, abort if missing */
|
||||||
|
if (!strstr(controllers, "+cpu")) {
|
||||||
|
logit(LOG_NOTICE, "Missing CPU controller, disabling cgroup support.");
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
|
||||||
/* Enable all controllers */
|
/* Enable all controllers */
|
||||||
if (fnwrite(controllers, FINIT_CGPATH "/cgroup.subtree_control"))
|
if (fnwrite(controllers, FINIT_CGPATH "/cgroup.subtree_control")) {
|
||||||
_pe("Failed enabling %s for %s", controllers, FINIT_CGPATH "/cgroup.subtree_control");
|
err(1, "Failed enabling %s for %s", controllers, FINIT_CGPATH "/cgroup.subtree_control");
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 */
|
/* Default (protected) groups, PID 1, services, and user/login processes */
|
||||||
cgroup_add("init", "cpu.weight:100", 1);
|
cgroup_add("init", "cpu.weight:100", 1);
|
||||||
@@ -505,14 +538,12 @@ void cgroup_init(uev_ctx_t *ctx)
|
|||||||
cgroup_config();
|
cgroup_config();
|
||||||
|
|
||||||
/* Move ourselves to init (best effort, otherwise run in 'root' group */
|
/* Move ourselves to init (best effort, otherwise run in 'root' group */
|
||||||
if (fnwrite("1", FINIT_CGPATH "/init/cgroup.procs"))
|
if (fnwrite("1", FINIT_CGPATH "/init/cgroup.procs")) {
|
||||||
_pe("Failed moving PID 1 to cgroup ", FINIT_CGPATH "/init");
|
err(1, "Failed moving PID 1 to cgroup %s", FINIT_CGPATH "/init");
|
||||||
|
uev_io_stop(&cgw);
|
||||||
/* prepare cgroup.events watcher */
|
iwatch_exit(&iw_cgroup);
|
||||||
fd = iwatch_init(&iw_cgroup);
|
|
||||||
if (uev_io_init(ctx, &cgw, cgroup_events_cb, NULL, fd, UEV_READ)) {
|
|
||||||
_pe("Failed setting up cgroup.events watcher");
|
|
||||||
close(fd);
|
close(fd);
|
||||||
|
goto abort;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -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-2024 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
|
||||||
|
|||||||
+11
-9
@@ -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-2024 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,7 +23,6 @@
|
|||||||
|
|
||||||
#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 <signal.h>
|
||||||
@@ -39,6 +38,7 @@
|
|||||||
|
|
||||||
#include "cgutil.h"
|
#include "cgutil.h"
|
||||||
#include "initctl.h"
|
#include "initctl.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
#define CDIM plain ? "" : "\e[2m"
|
#define CDIM plain ? "" : "\e[2m"
|
||||||
#define CRST plain ? "" : "\e[0m"
|
#define CRST plain ? "" : "\e[0m"
|
||||||
@@ -244,7 +244,7 @@ static float cgroup_cpuload(struct cg *cg)
|
|||||||
snprintf(fn, sizeof(fn), "%s/cpu.stat", 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);
|
||||||
|
|
||||||
while (fgets(buf, sizeof(buf), fp)) {
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
uint64_t curr;
|
uint64_t curr;
|
||||||
@@ -280,13 +280,13 @@ static struct cg *append(char *path)
|
|||||||
if (access(fn, F_OK)) {
|
if (access(fn, F_OK)) {
|
||||||
/* older kernels, 4.19, don't have summary cpu.stat in root */
|
/* older kernels, 4.19, don't have summary cpu.stat in root */
|
||||||
if (strcmp(path, FINIT_CGPATH))
|
if (strcmp(path, FINIT_CGPATH))
|
||||||
warn("not a cgroup path with cpu controller, %s", path);
|
WARN("not a cgroup path with cpu controller, %s", path);
|
||||||
return NULL;
|
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)
|
||||||
@@ -296,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;
|
||||||
}
|
}
|
||||||
@@ -434,7 +434,6 @@ int cgroup_tree(char *path, char *pfx, int mode, int pos)
|
|||||||
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[ttcols];
|
char proc[ttcols];
|
||||||
int len;
|
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case 1:
|
case 1:
|
||||||
@@ -456,6 +455,8 @@ int cgroup_tree(char *path, char *pfx, int mode, int pos)
|
|||||||
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);
|
||||||
|
|
||||||
@@ -600,7 +601,6 @@ int show_cgtop(char *arg)
|
|||||||
uev_t timer, input, sigint, sigterm, sigquit;
|
uev_t timer, input, sigint, sigterm, sigquit;
|
||||||
char path[512];
|
char path[512];
|
||||||
uev_ctx_t ctx;
|
uev_ctx_t ctx;
|
||||||
int flags;
|
|
||||||
|
|
||||||
if (!arg)
|
if (!arg)
|
||||||
arg = FINIT_CGPATH;
|
arg = FINIT_CGPATH;
|
||||||
@@ -610,7 +610,7 @@ int show_cgtop(char *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!hcreate(ttrows + 25))
|
if (!hcreate(ttrows + 25))
|
||||||
err(1, "failed creating hash table");
|
ERR(70, "failed creating hash table");
|
||||||
|
|
||||||
sysinfo(&si);
|
sysinfo(&si);
|
||||||
total_ram = si.totalram * si.mem_unit;
|
total_ram = si.totalram * si.mem_unit;
|
||||||
@@ -619,6 +619,8 @@ int show_cgtop(char *arg)
|
|||||||
uev_timer_init(&ctx, &timer, cgtop, arg, 1, ionce ? 0 : 1000);
|
uev_timer_init(&ctx, &timer, cgtop, arg, 1, ionce ? 0 : 1000);
|
||||||
|
|
||||||
if (!ionce && !plain) {
|
if (!ionce && !plain) {
|
||||||
|
int flags;
|
||||||
|
|
||||||
atexit(cleanup);
|
atexit(cleanup);
|
||||||
ttraw();
|
ttraw();
|
||||||
hidecursor();
|
hidecursor();
|
||||||
|
|||||||
+1
-1
@@ -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-2024 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
|
||||||
|
|||||||
+74
-36
@@ -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-2024 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,13 +21,15 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <err.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <poll.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"
|
||||||
|
|
||||||
|
#define REQUEST_TIMEOUT 15000
|
||||||
|
|
||||||
static int sd = -1;
|
static int sd = -1;
|
||||||
|
|
||||||
@@ -39,11 +41,17 @@ int client_connect(void)
|
|||||||
};
|
};
|
||||||
|
|
||||||
sd = socket(AF_UNIX, SOCK_SEQPACKET, 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;
|
||||||
}
|
}
|
||||||
@@ -63,64 +71,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)
|
||||||
|
{
|
||||||
|
return sd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int client_request(struct init_request *rq, ssize_t len)
|
||||||
{
|
{
|
||||||
struct pollfd pfd = { 0 };
|
struct pollfd pfd = { 0 };
|
||||||
int sd, result = 255;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
sd = client_connect();
|
if (client_connect() == -1)
|
||||||
if (-1 == sd)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
pfd.fd = sd;
|
pfd.fd = sd;
|
||||||
pfd.events = POLLOUT;
|
pfd.events = POLLOUT;
|
||||||
if (poll(&pfd, 1, 2000) <= 0) {
|
if (poll(&pfd, 1, REQUEST_TIMEOUT) <= 0) {
|
||||||
warn("Timed out waiting for Finit, errno %d", errno);
|
warn("Timed out waiting for Finit, errno %d", errno);
|
||||||
goto exit;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (write(sd, rq, len) != len) {
|
if (write(sd, rq, len) != len) {
|
||||||
warn("Failed communicating with Finit, errno %d", errno);
|
warn("Failed communicating with Finit, errno %d", errno);
|
||||||
goto exit;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Exception, only command that don't need to wait for a
|
||||||
|
* response from Finit. Registers the client socket as a
|
||||||
|
* readiness notification socket with Finit
|
||||||
|
*/
|
||||||
|
if (rq->cmd == INIT_CMD_NOTIFY_SOCKET) {
|
||||||
|
rq->cmd = INIT_CMD_ACK;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pfd.fd = sd;
|
pfd.fd = sd;
|
||||||
pfd.events = POLLIN;
|
pfd.events = POLLIN | POLLERR | POLLHUP;
|
||||||
if ((rc = poll(&pfd, 1, 2000)) <= 0) {
|
if ((rc = poll(&pfd, 1, REQUEST_TIMEOUT)) <= 0) {
|
||||||
if (rc)
|
if (rc) {
|
||||||
|
if (errno == EINTR) /* shutdown/reboot */
|
||||||
|
return -1;
|
||||||
warn("poll(), errno %d", errno);
|
warn("poll(), errno %d", errno);
|
||||||
else
|
} else
|
||||||
warnx("Timed out waiting for reply from Finit.");
|
warnx("Timed out waiting for reply from Finit.");
|
||||||
goto exit;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read(sd, rq, len) != len) {
|
if (read(sd, rq, len) != len) {
|
||||||
warn("Failed reading reply from Finit, errno %d", errno);
|
warn("Failed reading reply from Finit, errno %d", errno);
|
||||||
goto exit;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rq->cmd == INIT_CMD_NACK)
|
if (rq->cmd == INIT_CMD_NACK)
|
||||||
result = 1;
|
return -1;
|
||||||
else
|
|
||||||
result = 0;
|
return 0;
|
||||||
exit:
|
}
|
||||||
|
|
||||||
|
int client_send(struct init_request *rq, ssize_t len)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (client_request(rq, len))
|
||||||
|
rc = 255;
|
||||||
|
|
||||||
client_disconnect();
|
client_disconnect();
|
||||||
|
|
||||||
return result;
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int client_command(int cmd)
|
||||||
|
{
|
||||||
|
struct init_request rq = {
|
||||||
|
.magic = INIT_MAGIC,
|
||||||
|
.runlevel = getpid(),
|
||||||
|
.cmd = cmd,
|
||||||
|
};
|
||||||
|
|
||||||
|
return client_request(&rq, sizeof(rq));
|
||||||
}
|
}
|
||||||
|
|
||||||
svc_t *client_svc_iterator(int first)
|
svc_t *client_svc_iterator(int first)
|
||||||
{
|
{
|
||||||
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)
|
||||||
@@ -139,24 +180,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));
|
||||||
@@ -172,20 +211,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-2024 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);
|
||||||
|
|||||||
Executable
+11
@@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# With the daemon mode ('mdev -df') we no longer need the hotplug helper
|
||||||
|
echo "" > /proc/sys/kernel/hotplug
|
||||||
|
|
||||||
|
# Wait for 'mdev -df' to set up its event queue.
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
# Trigger 'add' event for all devices and subsystems to load all modules
|
||||||
|
# and any firmware needed by the hardware.
|
||||||
|
find /sys/devices -name uevent -print | while IFS='' read X; do echo add > $X; done
|
||||||
+166
-30
@@ -21,6 +21,7 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
#include <ftw.h>
|
#include <ftw.h>
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -34,6 +35,71 @@
|
|||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
#include "pid.h"
|
#include "pid.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
|
#include "sm.h"
|
||||||
|
|
||||||
|
struct cond_boot {
|
||||||
|
TAILQ_ENTRY(cond_boot) link;
|
||||||
|
char *name;
|
||||||
|
};
|
||||||
|
static TAILQ_HEAD(, cond_boot) cond_boot_list = TAILQ_HEAD_INITIALIZER(cond_boot_list);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse finit.cond=cond[,cond[,...]] from command line. It creates a
|
||||||
|
* temporary linked list of conds which are freed when finit reaches
|
||||||
|
* cond_init(), which calls cond_boot_strap() to realize the conditions
|
||||||
|
* in the file system as regular static conditions. Policy, however,
|
||||||
|
* dictates that these are read-only and should not be possible to
|
||||||
|
* manage from initctl.
|
||||||
|
*/
|
||||||
|
void cond_boot_parse(char *arg)
|
||||||
|
{
|
||||||
|
struct cond_boot *node;
|
||||||
|
|
||||||
|
if (!arg)
|
||||||
|
return;
|
||||||
|
|
||||||
|
node = malloc(sizeof(*node));
|
||||||
|
if (!node) {
|
||||||
|
err(1, "Out of memory cannot track boot conditions");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->name = strdup(arg);
|
||||||
|
TAILQ_INSERT_HEAD(&cond_boot_list, node, link);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert all conditions read from the kernel command line (above) into
|
||||||
|
* proper finit conditions.
|
||||||
|
*/
|
||||||
|
static void cond_boot_strap(void)
|
||||||
|
{
|
||||||
|
struct cond_boot *node, *tmp;
|
||||||
|
|
||||||
|
TAILQ_FOREACH_SAFE(node, &cond_boot_list, link, tmp) {
|
||||||
|
TAILQ_REMOVE(&cond_boot_list, node, link);
|
||||||
|
if (node->name) {
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
ptr = strtok(node->name, ",");
|
||||||
|
while (ptr) {
|
||||||
|
char cond[strlen(ptr) + 6];
|
||||||
|
|
||||||
|
if (strncmp(ptr, "boot/", 5))
|
||||||
|
snprintf(cond, sizeof(cond), "boot/%s", ptr);
|
||||||
|
else
|
||||||
|
snprintf(cond, sizeof(cond), "%s", ptr);
|
||||||
|
cond_set_oneshot_noupdate(cond);
|
||||||
|
|
||||||
|
ptr = strtok(NULL, ",");
|
||||||
|
}
|
||||||
|
|
||||||
|
free(node->name);
|
||||||
|
}
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The service condition name is constructed from the 'pid/' prefix and
|
* The service condition name is constructed from the 'pid/' prefix and
|
||||||
@@ -47,7 +113,7 @@
|
|||||||
*
|
*
|
||||||
* => 'pid/' + 'teamd' + '' = condition <pid/teamd>
|
* => 'pid/' + 'teamd' + '' = condition <pid/teamd>
|
||||||
*
|
*
|
||||||
* When you add a second aggrate you need to tell Finit it's a different
|
* When you add a second aggregate you need to tell Finit it's a different
|
||||||
* instance usugin the :ID syntax:
|
* instance usugin the :ID syntax:
|
||||||
*
|
*
|
||||||
* service :lag2 teamd -f /etc/teamd/lag2.conf -- Aggregate lag2
|
* service :lag2 teamd -f /etc/teamd/lag2.conf -- Aggregate lag2
|
||||||
@@ -110,7 +176,7 @@ static void cond_bump_reconf(void)
|
|||||||
rgen++;
|
rgen++;
|
||||||
|
|
||||||
if (cond_set_gen(_PATH_RECONF, rgen))
|
if (cond_set_gen(_PATH_RECONF, rgen))
|
||||||
_pe("Failed setting %s to gen %d", _PATH_RECONF, rgen);
|
err(1, "Failed setting %s to gen %d", _PATH_RECONF, rgen);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cond_checkpath(const char *path)
|
static int cond_checkpath(const char *path)
|
||||||
@@ -120,47 +186,96 @@ static int cond_checkpath(const char *path)
|
|||||||
strlcpy(buf, path, sizeof(buf));
|
strlcpy(buf, path, sizeof(buf));
|
||||||
dir = dirname(buf);
|
dir = dirname(buf);
|
||||||
if (!dir) {
|
if (!dir) {
|
||||||
_e("Invalid path '%s' for condition", path);
|
errx(1, "Invalid path '%s' for condition", path);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mkpath(dir, 0755) && errno != EEXIST) {
|
if (mkpath(dir, 0755) && errno != EEXIST) {
|
||||||
_pe("Failed creating dir '%s' for condition '%s'", dir, path);
|
err(1, "Failed creating dir '%s' for condition '%s'", dir, path);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int do_delete(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftw)
|
||||||
|
{
|
||||||
|
const char *cond, *ptr;
|
||||||
|
|
||||||
|
if (ftw->level == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
ptr = strstr(fpath, COND_BASE);
|
||||||
|
if (!ptr) {
|
||||||
|
warnx("%s does not seem to be a Finit condition, skipping", fpath);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remove(fpath))
|
||||||
|
err(1, "Failed removing condition %s", fpath);
|
||||||
|
|
||||||
|
cond = ptr + strlen(COND_BASE) + 1;
|
||||||
|
if (sm_is_in_teardown(&sm))
|
||||||
|
cond_clear_noupdate(cond);
|
||||||
|
else
|
||||||
|
cond_update(cond);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cond_delpath(const char *path)
|
||||||
|
{
|
||||||
|
nftw(path, do_delete, 20, FTW_DEPTH);
|
||||||
|
if (remove(path)) {
|
||||||
|
switch (errno) {
|
||||||
|
case ENOENT: /* Ignore */
|
||||||
|
case ENOTEMPTY: /* Only at shutdown and for directories */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
err(1, "Failed removing condition path %s", path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int cond_set_path(const char *path, enum cond_state next)
|
int cond_set_path(const char *path, enum cond_state next)
|
||||||
{
|
{
|
||||||
enum cond_state prev;
|
enum cond_state prev;
|
||||||
unsigned int rgen;
|
unsigned int rgen;
|
||||||
|
|
||||||
_d("%s <= %d", path, next);
|
dbg("%s <= %d", path, next);
|
||||||
|
|
||||||
rgen = cond_get_gen(_PATH_RECONF);
|
|
||||||
if (!rgen) {
|
|
||||||
_e("Unable to read configuration generation (%s)", path);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
prev = cond_get_path(path);
|
prev = cond_get_path(path);
|
||||||
|
|
||||||
switch (next) {
|
switch (next) {
|
||||||
case COND_ON:
|
case COND_ON:
|
||||||
if (cond_checkpath(path))
|
if (cond_checkpath(path))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
rgen = cond_get_gen(_PATH_RECONF);
|
||||||
|
if (!rgen) {
|
||||||
|
errx(1, "Unable to read configuration generation (%s)", path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
cond_set_gen(path, rgen);
|
cond_set_gen(path, rgen);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case COND_OFF:
|
case COND_OFF:
|
||||||
if (unlink(path) && errno != ENOENT)
|
if (unlink(path)) {
|
||||||
_pe("Failed removing condition '%s'", path);
|
switch (errno) {
|
||||||
|
case ENOENT:
|
||||||
|
break;
|
||||||
|
case EISDIR:
|
||||||
|
cond_delpath(path);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
err(1, "Failed removing condition '%s'", path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_e("Invalid condition state");
|
errx(1, "Invalid condition state");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,13 +288,19 @@ int cond_update(const char *name)
|
|||||||
svc_t *svc, *iter = NULL;
|
svc_t *svc, *iter = NULL;
|
||||||
int affects = 0;
|
int affects = 0;
|
||||||
|
|
||||||
_d("%s", name);
|
// dbg("%s", name);
|
||||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
if (!svc_has_cond(svc) || !cond_affects(name, svc->cond))
|
if (!svc_has_cond(svc) || !cond_affects(name, svc->cond))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
affects++;
|
affects++;
|
||||||
_d("%s: match <%s> %s(%s)", name ?: "nil", svc->cond, svc->desc, svc->cmd);
|
dbg("%s: match <%s> %s(%s)", name ?: "nil", svc->cond, svc->desc, svc->cmd);
|
||||||
|
/* Fix bug #314: race condition between crashing services and conditions */
|
||||||
|
if (svc_is_restart(svc) && cond_get_agg(svc->cond) == COND_OFF) {
|
||||||
|
dbg("%s: cancel timer & unblock => WAITING state.", name ?: "nil");
|
||||||
|
service_timeout_cancel(svc);
|
||||||
|
svc_unblock(svc);
|
||||||
|
}
|
||||||
service_step(svc);
|
service_step(svc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,7 +309,7 @@ int cond_update(const char *name)
|
|||||||
|
|
||||||
int cond_set_noupdate(const char *name)
|
int cond_set_noupdate(const char *name)
|
||||||
{
|
{
|
||||||
_d("%s", name);
|
dbg("%s", name);
|
||||||
if (string_compare(name, "nop"))
|
if (string_compare(name, "nop"))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@@ -200,7 +321,7 @@ int cond_set_noupdate(const char *name)
|
|||||||
|
|
||||||
void cond_set(const char *name)
|
void cond_set(const char *name)
|
||||||
{
|
{
|
||||||
_d("%s", name);
|
// dbg("%s", name);
|
||||||
if (cond_set_noupdate(name))
|
if (cond_set_noupdate(name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -215,13 +336,13 @@ int cond_set_oneshot_noupdate(const char *name)
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
path = cond_path(name);
|
path = cond_path(name);
|
||||||
_d("%s => %s", name, path);
|
dbg("%s => %s", name, path);
|
||||||
|
|
||||||
if (cond_checkpath(path))
|
if (cond_checkpath(path))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (symlink(_PATH_RECONF, path) && errno != EEXIST) {
|
if (symlink(_PATH_RECONF, path) && errno != EEXIST) {
|
||||||
_pe("Failed creating onshot cond %s", name);
|
err(1, "Failed creating onshot cond %s", name);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,7 +351,7 @@ int cond_set_oneshot_noupdate(const char *name)
|
|||||||
|
|
||||||
void cond_set_oneshot(const char *name)
|
void cond_set_oneshot(const char *name)
|
||||||
{
|
{
|
||||||
_d("%s", name);
|
dbg("%s", name);
|
||||||
if (cond_set_oneshot_noupdate(name))
|
if (cond_set_oneshot_noupdate(name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -239,7 +360,7 @@ void cond_set_oneshot(const char *name)
|
|||||||
|
|
||||||
int cond_clear_noupdate(const char *name)
|
int cond_clear_noupdate(const char *name)
|
||||||
{
|
{
|
||||||
_d("%s", name);
|
dbg("%s", name);
|
||||||
if (string_compare(name, "nop"))
|
if (string_compare(name, "nop"))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@@ -251,7 +372,7 @@ int cond_clear_noupdate(const char *name)
|
|||||||
|
|
||||||
void cond_clear(const char *name)
|
void cond_clear(const char *name)
|
||||||
{
|
{
|
||||||
_d("%s", name);
|
// dbg("%s", name);
|
||||||
if (cond_clear_noupdate(name))
|
if (cond_clear_noupdate(name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -260,7 +381,7 @@ void cond_clear(const char *name)
|
|||||||
|
|
||||||
void cond_reload(void)
|
void cond_reload(void)
|
||||||
{
|
{
|
||||||
_d("");
|
dbg("");
|
||||||
|
|
||||||
cond_bump_reconf();
|
cond_bump_reconf();
|
||||||
}
|
}
|
||||||
@@ -277,12 +398,12 @@ static int do_assert(const char *fpath, const struct stat *sb, int tflg, struct
|
|||||||
|
|
||||||
nm = strstr((char *)fpath, COND_BASE);
|
nm = strstr((char *)fpath, COND_BASE);
|
||||||
if (!nm) {
|
if (!nm) {
|
||||||
_e("Incorrect condition path %s, cannot %sassert", fpath, set ? "re" : "de");
|
errx(1, "Incorrect condition path %s, cannot %sassert", fpath, set ? "re" : "de");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
nm += strlen(COND_BASE);
|
nm += strlen(COND_BASE);
|
||||||
_d("%sasserting %s => %s", set ? "Re" : "De", fpath, nm);
|
dbg("%sasserting %s => %s", set ? "Re" : "De", fpath, nm);
|
||||||
if (set)
|
if (set)
|
||||||
cond_set(nm);
|
cond_set(nm);
|
||||||
else
|
else
|
||||||
@@ -307,7 +428,7 @@ static int deassert(const char *fpath, const struct stat *sb, int tflg, struct F
|
|||||||
*/
|
*/
|
||||||
void cond_reassert(const char *pat)
|
void cond_reassert(const char *pat)
|
||||||
{
|
{
|
||||||
_d("%s", pat);
|
dbg("%s", pat);
|
||||||
nftw(cond_path(pat), reassert, 20, FTW_DEPTH);
|
nftw(cond_path(pat), reassert, 20, FTW_DEPTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,20 +437,35 @@ void cond_reassert(const char *pat)
|
|||||||
*/
|
*/
|
||||||
void cond_deassert(const char *pat)
|
void cond_deassert(const char *pat)
|
||||||
{
|
{
|
||||||
_d("%s", pat);
|
dbg("%s", pat);
|
||||||
nftw(cond_path(pat), deassert, 20, FTW_DEPTH);
|
nftw(cond_path(pat), deassert, 20, FTW_DEPTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if we have bootstrapped enough of the system to use conditions.
|
||||||
|
* Will answer 'No' before bootstrap done *and* at shutdown/reboot.
|
||||||
|
*/
|
||||||
|
int cond_is_available(void)
|
||||||
|
{
|
||||||
|
return fisdir(_PATH_COND);
|
||||||
|
}
|
||||||
|
|
||||||
void cond_init(void)
|
void cond_init(void)
|
||||||
{
|
{
|
||||||
char path[MAX_ARG_LEN];
|
char path[MAX_ARG_LEN];
|
||||||
|
|
||||||
if (mkpath(pid_runpath(_PATH_COND, path, sizeof(path)), 0755) && errno != EEXIST) {
|
if (mkpath(pid_runpath(_PATH_COND, path, sizeof(path)), 0755) && errno != EEXIST) {
|
||||||
_pe("Failed creating condition base directory '%s'", _PATH_COND);
|
err(1, "Failed creating condition base directory '%s'", _PATH_COND);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cond_bump_reconf();
|
cond_bump_reconf();
|
||||||
|
cond_boot_strap();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cond_exit(void)
|
||||||
|
{
|
||||||
|
cond_delpath(_PATH_COND);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+1
-1
@@ -112,7 +112,7 @@ enum cond_state cond_get_agg(const char *names)
|
|||||||
|
|
||||||
int cond_affects(const char *name, const char *names)
|
int cond_affects(const char *name, const char *names)
|
||||||
{
|
{
|
||||||
static char conds[MAX_COND_LEN];
|
char conds[MAX_COND_LEN];
|
||||||
char *cond;
|
char *cond;
|
||||||
|
|
||||||
if (!name || !names)
|
if (!name || !names)
|
||||||
|
|||||||
+9
-3
@@ -6,11 +6,13 @@
|
|||||||
#include "svc.h"
|
#include "svc.h"
|
||||||
|
|
||||||
#define COND_BASE "finit/cond"
|
#define COND_BASE "finit/cond"
|
||||||
|
#define COND_DEV "dev/"
|
||||||
#define COND_PID "pid/"
|
#define COND_PID "pid/"
|
||||||
#define COND_SYS "sys/"
|
#define COND_SYS "sys/"
|
||||||
#define COND_USR "usr/"
|
#define COND_USR "usr/"
|
||||||
|
|
||||||
#define _PATH_COND _PATH_VARRUN COND_BASE "/"
|
#define _PATH_COND _PATH_VARRUN COND_BASE "/"
|
||||||
|
#define _PATH_CONDDEV _PATH_COND COND_DEV
|
||||||
#define _PATH_CONDPID _PATH_COND COND_PID
|
#define _PATH_CONDPID _PATH_COND COND_PID
|
||||||
#define _PATH_CONDSYS _PATH_COND COND_SYS
|
#define _PATH_CONDSYS _PATH_COND COND_SYS
|
||||||
#define _PATH_CONDUSR _PATH_COND COND_USR
|
#define _PATH_CONDUSR _PATH_COND COND_USR
|
||||||
@@ -31,6 +33,7 @@ enum cond_state cond_get (const char *name);
|
|||||||
enum cond_state cond_get_agg (const char *names);
|
enum cond_state cond_get_agg (const char *names);
|
||||||
int cond_affects (const char *name, const char *names);
|
int cond_affects (const char *name, const char *names);
|
||||||
|
|
||||||
|
void cond_boot_parse (char *arg);
|
||||||
int cond_update (const char *name);
|
int cond_update (const char *name);
|
||||||
int cond_set_path (const char *path, enum cond_state new);
|
int cond_set_path (const char *path, enum cond_state new);
|
||||||
void cond_set (const char *name);
|
void cond_set (const char *name);
|
||||||
@@ -38,14 +41,17 @@ void cond_set_oneshot (const char *name);
|
|||||||
void cond_clear (const char *name);
|
void cond_clear (const char *name);
|
||||||
void cond_reload (void);
|
void cond_reload (void);
|
||||||
|
|
||||||
int cond_set_noupdate (const char *name);
|
int cond_set_noupdate(const char *name);
|
||||||
int cond_set_oneshot_noupdate(const char *name);
|
int cond_set_oneshot_noupdate(const char *name);
|
||||||
int cond_clear_noupdate(const char *name);
|
int cond_clear_noupdate(const char *name);
|
||||||
|
|
||||||
void cond_reassert (const char *pat);
|
void cond_reassert (const char *pat);
|
||||||
void cond_deassert (const char *pat);
|
void cond_deassert (const char *pat);
|
||||||
|
|
||||||
|
int cond_is_available(void);
|
||||||
|
|
||||||
void cond_init (void);
|
void cond_init (void);
|
||||||
|
void cond_exit (void);
|
||||||
|
|
||||||
#endif /* FINIT_COND_H_ */
|
#endif /* FINIT_COND_H_ */
|
||||||
|
|
||||||
|
|||||||
+798
-144
File diff suppressed because it is too large
Load Diff
+5
-1
@@ -1,6 +1,6 @@
|
|||||||
/* Parser for /etc/finit.conf and /etc/finit.d/<SVC>.conf
|
/* Parser for /etc/finit.conf and /etc/finit.d/<SVC>.conf
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2012-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -42,6 +42,10 @@ int conf_any_change (void);
|
|||||||
int conf_changed (char *file);
|
int conf_changed (char *file);
|
||||||
int conf_monitor (void);
|
int conf_monitor (void);
|
||||||
|
|
||||||
|
void conf_reset_env (void);
|
||||||
|
void conf_saverc (void);
|
||||||
|
void conf_save_exec_order (svc_t *svc, char *cmdline, int result);
|
||||||
|
void conf_save_service (int type, char *cfg, char *file);
|
||||||
void conf_parse_cmdline (int argc, char *argv[]);
|
void conf_parse_cmdline (int argc, char *argv[]);
|
||||||
int conf_parse_runlevels (char *runlevels);
|
int conf_parse_runlevels (char *runlevels);
|
||||||
void conf_parse_cond (svc_t *svc, char *cond);
|
void conf_parse_cond (svc_t *svc, char *cond);
|
||||||
|
|||||||
+275
@@ -0,0 +1,275 @@
|
|||||||
|
/* Device node monitor for the Finit condition engine
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fnmatch.h>
|
||||||
|
#include <glob.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <paths.h>
|
||||||
|
|
||||||
|
#include "finit.h"
|
||||||
|
#include "cond.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
#include "pid.h"
|
||||||
|
#include "plugin.h"
|
||||||
|
#include "service.h"
|
||||||
|
#include "iwatch.h"
|
||||||
|
|
||||||
|
static struct iwatch iw_devmon;
|
||||||
|
static uev_t devw;
|
||||||
|
static int fd;
|
||||||
|
|
||||||
|
struct dev_node {
|
||||||
|
TAILQ_ENTRY(dev_node) link;
|
||||||
|
char *name;
|
||||||
|
size_t refcnt;
|
||||||
|
};
|
||||||
|
|
||||||
|
static TAILQ_HEAD(, dev_node) dev_node_list = TAILQ_HEAD_INITIALIZER(dev_node_list);
|
||||||
|
|
||||||
|
static struct dev_node *find_node(const char *cond)
|
||||||
|
{
|
||||||
|
struct dev_node *node, *tmp;
|
||||||
|
|
||||||
|
TAILQ_FOREACH_SAFE(node, &dev_node_list, link, tmp) {
|
||||||
|
if (string_compare(node->name, cond))
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void drop_node(struct dev_node *node)
|
||||||
|
{
|
||||||
|
if (!node)
|
||||||
|
return;
|
||||||
|
|
||||||
|
node->refcnt--;
|
||||||
|
if (node->refcnt)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TAILQ_REMOVE(&dev_node_list, node, link);
|
||||||
|
free(node->name);
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void devmon_add_cond(const char *cond)
|
||||||
|
{
|
||||||
|
struct dev_node *node;
|
||||||
|
|
||||||
|
if (!cond || strncmp(cond, "dev/", 4)) {
|
||||||
|
dbg("no match");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dbg("%s", cond);
|
||||||
|
node = find_node(cond);
|
||||||
|
if (node) {
|
||||||
|
node->refcnt++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = malloc(sizeof(*node));
|
||||||
|
if (!node) {
|
||||||
|
fail:
|
||||||
|
warn("failed allocating node %s", cond);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->name = strdup(cond);
|
||||||
|
if (!node->name) {
|
||||||
|
free(node);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
node->refcnt = 1;
|
||||||
|
|
||||||
|
TAILQ_INSERT_TAIL(&dev_node_list, node, link);
|
||||||
|
}
|
||||||
|
|
||||||
|
void devmon_del_cond(const char *cond)
|
||||||
|
{
|
||||||
|
if (!cond || strcmp(cond, "dev/"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
drop_node(find_node(cond));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int devmon_add_path(struct iwatch *iw, char *path)
|
||||||
|
{
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
ptr = strstr(path, "dev/");
|
||||||
|
if (ptr) {
|
||||||
|
char *slash;
|
||||||
|
|
||||||
|
ptr += 4;
|
||||||
|
slash = strchr(ptr, '/');
|
||||||
|
if (slash) {
|
||||||
|
ptr = slash++;
|
||||||
|
slash = strchr(ptr, '/');
|
||||||
|
if (slash) {
|
||||||
|
dbg("Path too deep, skipping.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return iwatch_add1(iw, path, IN_CREATE | IN_DELETE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void devmon_update_conds(char *dir, char *name, uint32_t mask)
|
||||||
|
{
|
||||||
|
char fn[PATH_MAX];
|
||||||
|
char *cond;
|
||||||
|
|
||||||
|
paste(fn, sizeof(fn), dir, name);
|
||||||
|
cond = &fn[1];
|
||||||
|
|
||||||
|
// dbg("path: %s, mask: %08x, cond: %s", fn, mask, cond);
|
||||||
|
if (!find_node(cond)) {
|
||||||
|
// dbg("unregistered, skipping %s", cond);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mask & IN_CREATE)
|
||||||
|
cond_set(cond);
|
||||||
|
else if (mask & IN_DELETE)
|
||||||
|
cond_clear(cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* synthesize events in case of new run dirs */
|
||||||
|
static void devmon_scandir(struct iwatch *iw, char *dir, int len)
|
||||||
|
{
|
||||||
|
char path[len + 6];
|
||||||
|
glob_t gl;
|
||||||
|
size_t i;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "%s/*", dir);
|
||||||
|
rc = glob(path, GLOB_NOSORT, NULL, &gl);
|
||||||
|
if (rc && rc != GLOB_NOMATCH)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < gl.gl_pathc; i++) {
|
||||||
|
// dbg("scan found %s", gl.gl_pathv[i]);
|
||||||
|
devmon_update_conds(dir, gl.gl_pathv[i], IN_CREATE);
|
||||||
|
}
|
||||||
|
globfree(&gl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* create/remove sub-directory in monitored directory
|
||||||
|
*/
|
||||||
|
static void devmon_handle_dir(struct iwatch *iw, char *dir, char *name, int mask)
|
||||||
|
{
|
||||||
|
char path[strlen(dir) + strlen(name) + 2];
|
||||||
|
struct iwatch_path *iwp;
|
||||||
|
|
||||||
|
paste(path, sizeof(path), dir, name);
|
||||||
|
dbg("path: %s", path);
|
||||||
|
|
||||||
|
iwp = iwatch_find_by_path(iw, path);
|
||||||
|
|
||||||
|
if (mask & IN_CREATE) {
|
||||||
|
if (!iwp) {
|
||||||
|
if (!devmon_add_path(iw, path))
|
||||||
|
devmon_scandir(iw, path, sizeof(path));
|
||||||
|
}
|
||||||
|
} else if (mask & IN_DELETE) {
|
||||||
|
if (iwp)
|
||||||
|
iwatch_del(&iw_devmon, iwp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void devmon_cb(uev_t *w, void *arg, int events)
|
||||||
|
{
|
||||||
|
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
||||||
|
struct inotify_event *ev;
|
||||||
|
ssize_t sz;
|
||||||
|
size_t off;
|
||||||
|
|
||||||
|
sz = read(w->fd, ev_buf, sizeof(ev_buf) - 1);
|
||||||
|
if (sz <= 0) {
|
||||||
|
err(1, "invalid inotify event");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ev_buf[sz] = 0;
|
||||||
|
|
||||||
|
for (off = 0; off < (size_t)sz; off += sizeof(*ev) + ev->len) {
|
||||||
|
struct iwatch_path *iwp;
|
||||||
|
|
||||||
|
if (off + sizeof(*ev) > (size_t)sz)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ev = (struct inotify_event *)&ev_buf[off];
|
||||||
|
if (off + sizeof(*ev) + ev->len > (size_t)sz)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!ev->mask)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Find base path for this event */
|
||||||
|
iwp = iwatch_find_by_wd(&iw_devmon, ev->wd);
|
||||||
|
if (!iwp)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ev->mask & IN_ISDIR) {
|
||||||
|
devmon_handle_dir(&iw_devmon, iwp->path, ev->name, ev->mask);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dbg("Got %s", ev->name);
|
||||||
|
if (ev->mask & (IN_CREATE | IN_DELETE))
|
||||||
|
devmon_update_conds(iwp->path, ev->name, ev->mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void devmon_init(uev_ctx_t *ctx)
|
||||||
|
{
|
||||||
|
char dir[MAX_ARG_LEN];
|
||||||
|
|
||||||
|
fd = iwatch_init(&iw_devmon);
|
||||||
|
if (fd < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mkpath(pid_runpath(_PATH_CONDDEV, dir, sizeof(dir)), 0755) && errno != EEXIST) {
|
||||||
|
err(1, "Failed creating %s condition directory, %s", COND_DEV, _PATH_CONDDEV);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uev_io_init(ctx, &devw, devmon_cb, NULL, fd, UEV_READ)) {
|
||||||
|
err(1, "Failed setting up I/O callback for /dev watcher");
|
||||||
|
close(fd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
strlcpy(dir, _PATH_DEV, sizeof(dir));
|
||||||
|
if (devmon_add_path(&iw_devmon, dir))
|
||||||
|
iwatch_exit(&iw_devmon);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Variables:
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/* Device node monitor for the Finit condition engine
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FINIT_DEVMON_H_
|
||||||
|
#define FINIT_DEVMON_H_
|
||||||
|
|
||||||
|
void devmon_add_cond(const char *cond);
|
||||||
|
void devmon_del_cond(const char *cond);
|
||||||
|
|
||||||
|
void devmon_init(uev_ctx_t *ctx);
|
||||||
|
|
||||||
|
#endif /* FINIT_DEVMON_H_ */
|
||||||
+115
-129
@@ -1,7 +1,7 @@
|
|||||||
/* Functions for exec'ing processes
|
/* Functions for exec'ing processes
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||||
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* 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,10 +24,9 @@
|
|||||||
|
|
||||||
#include "config.h" /* Generated by configure script */
|
#include "config.h" /* Generated by configure script */
|
||||||
|
|
||||||
#include <ctype.h> /* isdigit() */
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <sysexits.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
@@ -58,11 +57,11 @@ int complete(char *cmd, int pid)
|
|||||||
|
|
||||||
if (waitpid(pid, &status, 0) == -1) {
|
if (waitpid(pid, &status, 0) == -1) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
_e("Caught unblocked signal waiting for %s, aborting", cmd);
|
warnx("Caught unblocked signal waiting for %s, aborting", cmd);
|
||||||
else if (errno == ECHILD)
|
else if (errno == ECHILD)
|
||||||
_e("Caught SIGCHLD waiting for %s, aborting", cmd);
|
warnx("Caught SIGCHLD waiting for %s, aborting", cmd);
|
||||||
else
|
else
|
||||||
_e("Failed starting %s, error %d: %s", cmd, errno, strerror (errno));
|
warnx("Failed starting %s, error %d: %s", cmd, errno, strerror(errno));
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -70,89 +69,129 @@ int complete(char *cmd, int pid)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
int run(char *cmd)
|
static int do_redirect(void)
|
||||||
{
|
{
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopen("/dev/null", "w");
|
||||||
|
if (fp) {
|
||||||
|
int fd = fileno(fp);
|
||||||
|
|
||||||
|
dup2(fd, STDIN_FILENO);
|
||||||
|
dup2(fd, STDOUT_FILENO);
|
||||||
|
dup2(fd, STDERR_FILENO);
|
||||||
|
|
||||||
|
return fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Run 'cmd' and wait for completion. If 'log' is not NULL any output
|
||||||
|
* from the command is logged with the given string as prefix, use "" to
|
||||||
|
* skip. If 'log' is NULL all output is redirected to /dev/null, which
|
||||||
|
* is what this function originally did.
|
||||||
|
*/
|
||||||
|
int run(char *cmd, char *log)
|
||||||
|
{
|
||||||
|
char *args[NUM_ARGS + 1] = { 0 };
|
||||||
int status, result, i = 0;
|
int status, result, i = 0;
|
||||||
char *args[NUM_ARGS + 1], *arg, *backup;
|
char *backup = NULL;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
/* We must create a copy that is possible to modify. */
|
if (!log) {
|
||||||
backup = arg = strdup(cmd);
|
char *arg;
|
||||||
if (!arg)
|
|
||||||
return 1; /* Failed allocating a string to be modified. */
|
|
||||||
|
|
||||||
/* Split command line into tokens of an argv[] array. */
|
/* We must create a copy that is possible to modify. */
|
||||||
args[i++] = strsep(&arg, "\t ");
|
backup = arg = strdup(cmd);
|
||||||
while (arg && i < NUM_ARGS) {
|
if (!arg)
|
||||||
/* Handle run("su -c \"dbus-daemon --system\" messagebus");
|
return 1;
|
||||||
* => "su", "-c", "\"dbus-daemon --system\"", "messagebus" */
|
|
||||||
if (*arg == '\'' || *arg == '"') {
|
|
||||||
char *p, delim[2] = " ";
|
|
||||||
|
|
||||||
delim[0] = arg[0];
|
/* Split command line into tokens of an argv[] array. */
|
||||||
args[i++] = arg++;
|
args[i++] = strsep(&arg, "\t ");
|
||||||
strsep(&arg, delim);
|
while (arg && i < NUM_ARGS) {
|
||||||
p = arg - 1;
|
/* Handle run("su -c \"dbus-daemon --system\" messagebus");
|
||||||
*p = *delim;
|
* => "su", "-c", "\"dbus-daemon --system\"", "messagebus" */
|
||||||
*arg++ = 0;
|
if (*arg == '\'' || *arg == '"') {
|
||||||
} else {
|
char *p, delim[2] = " ";
|
||||||
args[i++] = strsep(&arg, "\t ");
|
|
||||||
|
delim[0] = arg[0];
|
||||||
|
args[i++] = arg++;
|
||||||
|
strsep(&arg, delim);
|
||||||
|
p = arg - 1;
|
||||||
|
*p = *delim;
|
||||||
|
*arg++ = 0;
|
||||||
|
} else {
|
||||||
|
args[i++] = strsep(&arg, "\t ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
args[i] = NULL;
|
||||||
args[i] = NULL;
|
|
||||||
|
|
||||||
if (i == NUM_ARGS && arg) {
|
if (i == NUM_ARGS && arg) {
|
||||||
_e("Command too long: %s", cmd);
|
errx(1, "Command too long: %s", cmd);
|
||||||
free(backup);
|
free(backup);
|
||||||
errno = EOVERFLOW;
|
errno = EOVERFLOW;
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if (0 == pid) {
|
if (0 == pid) {
|
||||||
FILE *fp;
|
char *pfx, buf[256];
|
||||||
|
FILE *pp;
|
||||||
|
int rc;
|
||||||
|
|
||||||
setsid();
|
setsid();
|
||||||
|
sig_unblock();
|
||||||
/* Always redirect stdio for run() */
|
if (!log) {
|
||||||
fp = fopen("/dev/null", "w");
|
do_redirect();
|
||||||
if (fp) {
|
execvp(args[0], args);
|
||||||
int fd = fileno(fp);
|
_exit(EX_OSERR);
|
||||||
|
|
||||||
dup2(fd, STDIN_FILENO);
|
|
||||||
dup2(fd, STDOUT_FILENO);
|
|
||||||
dup2(fd, STDERR_FILENO);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sig_unblock();
|
pp = popen(cmd, "r");
|
||||||
execvp(args[0], args);
|
if (!pp)
|
||||||
|
_exit(EX_OSERR);
|
||||||
|
|
||||||
_exit(1); /* Only if execv() fails. */
|
pfx = *log ? ": " : "";
|
||||||
|
while (fgets(buf, sizeof(buf), pp)) {
|
||||||
|
chomp(buf);
|
||||||
|
logit(LOG_NOTICE, "%s%s%s", log, pfx, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = pclose(pp);
|
||||||
|
if (rc == -1)
|
||||||
|
_exit(EX_OSERR);
|
||||||
|
_exit(WEXITSTATUS(rc));
|
||||||
} else if (-1 == pid) {
|
} else if (-1 == pid) {
|
||||||
_pe("%s", args[0]);
|
err(1, "%s", !log ? args[0] : cmd);
|
||||||
free(backup);
|
if (backup)
|
||||||
|
free(backup);
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = complete(args[0], pid);
|
status = complete(args[0], pid);
|
||||||
if (-1 == status) {
|
if (-1 == status) {
|
||||||
free(backup);
|
if (backup)
|
||||||
|
free(backup);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = WEXITSTATUS(status);
|
result = WEXITSTATUS(status);
|
||||||
if (WIFEXITED(status)) {
|
if (WIFEXITED(status)) {
|
||||||
_d("Started %s and ended OK: %d", args[0], result);
|
dbg("Started '%s' and exit without signal, status: %d", cmd, result);
|
||||||
} else if (WIFSIGNALED(status)) {
|
} else if (WIFSIGNALED(status)) {
|
||||||
_d("Process %s terminated by signal %d", args[0], WTERMSIG(status));
|
dbg("Process '%s' terminated by signal %d", cmd, WTERMSIG(status));
|
||||||
if (!result)
|
if (!result)
|
||||||
result = 1; /* Must alert callee that the command did complete successfully.
|
result = 1; /* Must alert callee the command did not complete successfully.
|
||||||
* This is necessary since not all programs trap signals and
|
* This is necessary since not all programs trap signals and
|
||||||
* change their return code accordingly. --Jocke */
|
* change their return code accordingly. --Jocke */
|
||||||
}
|
}
|
||||||
|
|
||||||
free(backup);
|
if (backup)
|
||||||
|
free(backup);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -160,7 +199,6 @@ int run(char *cmd)
|
|||||||
int run_interactive(char *cmd, char *fmt, ...)
|
int run_interactive(char *cmd, char *fmt, ...)
|
||||||
{
|
{
|
||||||
int status, oldout = 1, olderr = 2;
|
int status, oldout = 1, olderr = 2;
|
||||||
char line[LINE_SIZE];
|
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
if (!cmd) {
|
if (!cmd) {
|
||||||
@@ -186,7 +224,7 @@ int run_interactive(char *cmd, char *fmt, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Run cmd ... */
|
/* Run cmd ... */
|
||||||
status = run(cmd);
|
status = run(cmd, "");
|
||||||
|
|
||||||
/* Restore stderr/stdout */
|
/* Restore stderr/stdout */
|
||||||
if (fp && !debug) {
|
if (fp && !debug) {
|
||||||
@@ -205,6 +243,7 @@ int run_interactive(char *cmd, char *fmt, ...)
|
|||||||
|
|
||||||
/* Dump any results of cmd on stderr after we've printed [ OK ] or [FAIL] */
|
/* Dump any results of cmd on stderr after we've printed [ OK ] or [FAIL] */
|
||||||
if (fp && !debug) {
|
if (fp && !debug) {
|
||||||
|
char line[LINE_SIZE];
|
||||||
size_t len, written;
|
size_t len, written;
|
||||||
|
|
||||||
rewind(fp);
|
rewind(fp);
|
||||||
@@ -222,7 +261,6 @@ int run_interactive(char *cmd, char *fmt, ...)
|
|||||||
|
|
||||||
int exec_runtask(char *cmd, char *args[])
|
int exec_runtask(char *cmd, char *args[])
|
||||||
{
|
{
|
||||||
size_t i;
|
|
||||||
char buf[1024] = "";
|
char buf[1024] = "";
|
||||||
char *argv[4] = {
|
char *argv[4] = {
|
||||||
"sh",
|
"sh",
|
||||||
@@ -230,19 +268,20 @@ int exec_runtask(char *cmd, char *args[])
|
|||||||
buf,
|
buf,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
size_t i;
|
||||||
|
|
||||||
strlcat(buf, cmd, sizeof(buf));
|
strlcat(buf, cmd, sizeof(buf));
|
||||||
for (i = 1; args[i]; i++) {
|
for (i = 1; args && args[i]; i++) {
|
||||||
strlcat(buf, " ", sizeof(buf));
|
strlcat(buf, " ", sizeof(buf));
|
||||||
strlcat(buf, args[i], sizeof(buf));
|
strlcat(buf, args[i], sizeof(buf));
|
||||||
}
|
}
|
||||||
logit(LOG_DEBUG, "Calling %s %s", _PATH_BSHELL, buf);
|
logit(LOG_DEBUG, "Calling %s %s", _PATH_BSHELL, buf);
|
||||||
_d("Calling %s %s", _PATH_BSHELL, buf);
|
dbg("Calling %s %s", _PATH_BSHELL, buf);
|
||||||
|
|
||||||
return execvp(_PATH_BSHELL, argv);
|
return execvp(_PATH_BSHELL, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit rlimit[])
|
static void prepare_tty(char *tty, speed_t speed, const char *procname, struct rlimit rlimit[])
|
||||||
{
|
{
|
||||||
char name[80];
|
char name[80];
|
||||||
int fd, dummy;
|
int fd, dummy;
|
||||||
@@ -289,7 +328,7 @@ static int activate_console(int noclear, int nowait)
|
|||||||
static const char clr[] = "\r\e[K";
|
static const char clr[] = "\r\e[K";
|
||||||
static const char cup[] = "\e[A";
|
static const char cup[] = "\e[A";
|
||||||
struct termios orig;
|
struct termios orig;
|
||||||
char c;
|
char ch;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (nowait || rescue)
|
if (nowait || rescue)
|
||||||
@@ -311,8 +350,8 @@ static int activate_console(int noclear, int nowait)
|
|||||||
|
|
||||||
dprint(STDERR_FILENO, clr, strlen(clr));
|
dprint(STDERR_FILENO, clr, strlen(clr));
|
||||||
dprint(STDERR_FILENO, msg, strlen(msg));
|
dprint(STDERR_FILENO, msg, strlen(msg));
|
||||||
while ((rc = read(STDIN_FILENO, &c, 1)) > 0 && c != '\r' && c != '\n')
|
while ((rc = read(STDIN_FILENO, &ch, 1)) > 0 && ch != '\r' && ch != '\n')
|
||||||
continue;
|
;
|
||||||
|
|
||||||
/* On any error (likely EINTR), we avoid starting getty */
|
/* On any error (likely EINTR), we avoid starting getty */
|
||||||
if (rc == -1)
|
if (rc == -1)
|
||||||
@@ -379,8 +418,10 @@ int sh(char *tty)
|
|||||||
/* Start /bin/sh as a login shell, i.e. with a prefix '-' */
|
/* Start /bin/sh as a login shell, i.e. with a prefix '-' */
|
||||||
len = strlen(_PATH_BSHELL) + 2;
|
len = strlen(_PATH_BSHELL) + 2;
|
||||||
arg0 = malloc(len);
|
arg0 = malloc(len);
|
||||||
if (!arg0)
|
if (!arg0) {
|
||||||
err(1, "Failed allocating memory");
|
err(1, "Failed allocating memory");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
snprintf(arg0, len, "-%s", _PATH_BSHELL);
|
snprintf(arg0, len, "-%s", _PATH_BSHELL);
|
||||||
args[0] = arg0;
|
args[0] = arg0;
|
||||||
|
|
||||||
@@ -401,75 +442,20 @@ pid_t run_sh(char *tty, int noclear, int nowait, struct rlimit rlimit[])
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int run_parts(char *dir, char *cmd)
|
pid_t run_bg(char *cmd, char *args[])
|
||||||
{
|
{
|
||||||
struct dirent **e;
|
pid_t pid;
|
||||||
int i, num;
|
|
||||||
|
|
||||||
num = scandir(dir, &e, NULL, alphasort);
|
if (access(cmd, X_OK))
|
||||||
if (num < 0) {
|
return 0;
|
||||||
_d("No files found in %s, skipping ...", dir);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < num; i++) {
|
print(-1, "Calling %s in the background", cmd);
|
||||||
const char *name = e[i]->d_name;
|
pid = fork();
|
||||||
char path[strlen(dir) + strlen(name) + 2];
|
if (!pid)
|
||||||
struct stat st;
|
_exit(exec_runtask(cmd, args));
|
||||||
char *argv[4] = {
|
print_result(pid == -1);
|
||||||
"sh",
|
|
||||||
"-c",
|
|
||||||
path,
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
pid_t pid = 0;
|
|
||||||
int status;
|
|
||||||
int exit_status;
|
|
||||||
|
|
||||||
paste(path, sizeof(path), dir, name);
|
return pid;
|
||||||
if (stat(path, &st)) {
|
|
||||||
_d("Failed stat(%s): %s", path, strerror(errno));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!S_ISEXEC(st.st_mode) || S_ISDIR(st.st_mode)) {
|
|
||||||
_d("Skipping %s ...", path);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the callee didn't supply a run_parts() argument */
|
|
||||||
if (!cmd) {
|
|
||||||
/* Check if S<NUM>service or K<NUM>service notation is used */
|
|
||||||
_d("Checking if %s is a sysvinit startstop script ...", name);
|
|
||||||
if (name[0] == 'S' && isdigit(name[1]))
|
|
||||||
strlcat(path, " start", sizeof(path));
|
|
||||||
else if (name[0] == 'K' && isdigit(name[1]))
|
|
||||||
strlcat(path, " stop", sizeof(path));
|
|
||||||
} else {
|
|
||||||
strlcat(path, cmd, sizeof(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
print_desc("Calling ", path);
|
|
||||||
pid = fork();
|
|
||||||
if (!pid) {
|
|
||||||
sig_unblock();
|
|
||||||
return execvp(_PATH_BSHELL, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
status = complete(path, pid);
|
|
||||||
exit_status = WEXITSTATUS(status);
|
|
||||||
if (WIFEXITED(status) && exit_status)
|
|
||||||
_w("%s exited with status %d", path, exit_status);
|
|
||||||
else if (WIFSIGNALED(status))
|
|
||||||
_w("%s terminated by signad %d", path, WTERMSIG(status));
|
|
||||||
print_result(status);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (num--)
|
|
||||||
free(e[num]);
|
|
||||||
free(e);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+291
-253
@@ -1,7 +1,7 @@
|
|||||||
/* Finit - Fast /sbin/init replacement w/ I/O, hook & service plugins
|
/* Finit - Fast /sbin/init replacement w/ I/O, hook & service plugins
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||||
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* 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
|
||||||
@@ -26,16 +26,18 @@
|
|||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#ifdef HAVE_FSTAB_H
|
|
||||||
#include <fstab.h>
|
|
||||||
#endif
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#ifdef HAVE_MNTENT_H
|
||||||
#include <mntent.h>
|
#include <mntent.h>
|
||||||
|
#endif
|
||||||
#include <time.h> /* tzet() */
|
#include <time.h> /* tzet() */
|
||||||
#include <sys/klog.h>
|
#include <sys/klog.h>
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#include <sys/stat.h> /* umask(), mkdir() */
|
#include <sys/stat.h> /* umask(), mkdir() */
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
#ifdef HAVE_SYS_SYSMACROS_H
|
||||||
|
#include <sys/sysmacros.h>
|
||||||
|
#endif
|
||||||
#ifdef _LIBITE_LITE
|
#ifdef _LIBITE_LITE
|
||||||
# include <libite/lite.h>
|
# include <libite/lite.h>
|
||||||
#else
|
#else
|
||||||
@@ -46,6 +48,7 @@
|
|||||||
#include "cgroup.h"
|
#include "cgroup.h"
|
||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
#include "devmon.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "private.h"
|
#include "private.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
@@ -55,22 +58,24 @@
|
|||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "utmp-api.h"
|
#include "utmp-api.h"
|
||||||
#include "schedule.h"
|
|
||||||
#include "watchdog.h"
|
|
||||||
|
|
||||||
int runlevel = 0; /* Bootstrap 'S' */
|
int runlevel = INIT_LEVEL; /* Bootstrap 'S' */
|
||||||
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
|
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
|
||||||
|
int cmdlevel = 0; /* runlevel override from cmdline */
|
||||||
int prevlevel = -1;
|
int prevlevel = -1;
|
||||||
int debug = 0; /* debug mode from kernel cmdline */
|
int debug = 0; /* debug mode from kernel cmdline */
|
||||||
int rescue = 0; /* rescue mode from kernel cmdline */
|
int rescue = 0; /* rescue mode from kernel cmdline */
|
||||||
int single = 0; /* single user mode from kernel cmdline */
|
int single = 0; /* single user mode from kernel cmdline */
|
||||||
int bootstrap = 1; /* set while bootrapping (for TTYs) */
|
int bootstrap = 1; /* set while bootstrapping (for TTYs) */
|
||||||
int kerndebug = 0; /* set if /proc/sys/kernel/printk > 7 */
|
int kerndebug = 0; /* set if /proc/sys/kernel/printk > 7 */
|
||||||
|
int syncsec = 0; /* reboot delay */
|
||||||
|
int readiness = SVC_NOTIFY_PID;
|
||||||
|
char *finit_conf= NULL;
|
||||||
|
char *finit_rcsd= NULL;
|
||||||
|
char *fstab = NULL;
|
||||||
char *sdown = NULL;
|
char *sdown = NULL;
|
||||||
char *network = NULL;
|
char *network = NULL;
|
||||||
char *hostname = NULL;
|
char *hostname = NULL;
|
||||||
char *rcsd = FINIT_RCSD;
|
|
||||||
char *runparts = NULL;
|
|
||||||
char *osheading = NULL;
|
char *osheading = NULL;
|
||||||
|
|
||||||
uev_ctx_t *ctx = NULL; /* Main loop context */
|
uev_ctx_t *ctx = NULL; /* Main loop context */
|
||||||
@@ -82,14 +87,22 @@ svc_t *wdog = NULL; /* No watchdog by default */
|
|||||||
*/
|
*/
|
||||||
static void banner(void)
|
static void banner(void)
|
||||||
{
|
{
|
||||||
|
#ifndef KERNEL_LOGGING
|
||||||
/*
|
/*
|
||||||
* Silence kernel logs, assuming users have sysklogd or
|
* Silence kernel logs, assuming users have sysklogd or
|
||||||
* similar enabled to start emptying /dev/kmsg, but for
|
* similar enabled to start emptying /dev/kmsg.
|
||||||
* our progress we want to own the console.
|
*
|
||||||
|
* Instead of using `configure --disable-kernel-logging`, we
|
||||||
|
* recommend adjusting the kernel log level in the kernel's
|
||||||
|
* menuconfig, or using sysctl kernel.printk, or setting the
|
||||||
|
* desired log level, on the kernel cmdline, e.g. 'quiet'.
|
||||||
|
*
|
||||||
|
* By default KERNEL_LOGGING is enabled so you can see any
|
||||||
|
* warnings/errors or higher on your system console.
|
||||||
*/
|
*/
|
||||||
if (!debug && !kerndebug)
|
if (!debug && !kerndebug)
|
||||||
klogctl(6, NULL, 0);
|
klogctl(6, NULL, 0);
|
||||||
|
#endif
|
||||||
/*
|
/*
|
||||||
* First level hooks, if you want to run here, you're
|
* First level hooks, if you want to run here, you're
|
||||||
* pretty much on your own. Nothing's up yet ...
|
* pretty much on your own. Nothing's up yet ...
|
||||||
@@ -106,70 +119,171 @@ static void banner(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int sulogin(int do_reboot)
|
||||||
|
{
|
||||||
|
int rc = EX_OSFILE;
|
||||||
|
char *cmd[] = {
|
||||||
|
"sulogin",
|
||||||
|
_PATH_SULOGIN,
|
||||||
|
};
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < NELEMS(cmd); i++) {
|
||||||
|
char *path = which(cmd[i]);
|
||||||
|
|
||||||
|
if (!path)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (access(path, X_OK)) {
|
||||||
|
free(path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = systemf("%s", path);
|
||||||
|
free(path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (do_reboot) {
|
||||||
|
do_shutdown(SHUT_REBOOT);
|
||||||
|
exit(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *fs_root_dev(char *real, size_t len)
|
||||||
|
{
|
||||||
|
struct dirent *d;
|
||||||
|
struct stat st;
|
||||||
|
int found = 0;
|
||||||
|
dev_t dev;
|
||||||
|
DIR *dir;
|
||||||
|
|
||||||
|
if (stat("/", &st))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (S_ISBLK(st.st_mode))
|
||||||
|
dev = st.st_rdev;
|
||||||
|
else
|
||||||
|
dev = st.st_dev;
|
||||||
|
|
||||||
|
dir = opendir("/sys/block");
|
||||||
|
if (!dir)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while ((d = readdir(dir))) {
|
||||||
|
char buf[10];
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
if (fnread(buf, sizeof(buf), "/sys/block/%s/dev", d->d_name) == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ptr = strchr(buf, ':');
|
||||||
|
if (!ptr)
|
||||||
|
continue;
|
||||||
|
*ptr++ = 0;
|
||||||
|
|
||||||
|
if (atoi(buf) == (int)major(dev) && atoi(ptr) == (int)minor(dev)) {
|
||||||
|
/* Guess name, assume no renaming */
|
||||||
|
snprintf(real, len, "/dev/%s", d->d_name);
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
if (!found)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return real;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check all filesystems in /etc/fstab with a fs_passno > 0
|
* Check all filesystems in /etc/fstab with a fs_passno > 0
|
||||||
*/
|
*/
|
||||||
static int fsck(int pass)
|
static int fsck(int pass)
|
||||||
{
|
{
|
||||||
struct fstab *fs;
|
struct mntent mount;
|
||||||
|
struct mntent *mnt;
|
||||||
|
char real[192];
|
||||||
|
char buf[256];
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
if (!setfsent()) {
|
fp = setmntent(fstab, "r");
|
||||||
_pe("Failed opening fstab");
|
if (!fp) {
|
||||||
return 1;
|
logit(LOG_CONSOLE | LOG_ALERT, "Failed opening fstab: %s", fstab);
|
||||||
|
sulogin(1);
|
||||||
}
|
}
|
||||||
|
dbg("Opened %s, pass %d", fstab, pass);
|
||||||
while ((fs = getfsent())) {
|
while ((mnt = getmntent_r(fp, &mount, buf, sizeof(buf)))) {
|
||||||
char cmd[80];
|
|
||||||
struct stat st;
|
|
||||||
int fsck_rc = 0;
|
int fsck_rc = 0;
|
||||||
|
struct stat st;
|
||||||
|
char cmd[256];
|
||||||
|
char *dev;
|
||||||
|
|
||||||
if (fs->fs_passno != pass)
|
dbg("got: fsname '%s' dir '%s' type '%s' opts '%s' freq '%d' passno '%d'",
|
||||||
|
mnt->mnt_fsname, mnt->mnt_dir, mnt->mnt_type, mnt->mnt_opts,
|
||||||
|
mnt->mnt_freq, mnt->mnt_passno);
|
||||||
|
|
||||||
|
if (mnt->mnt_passno == 0 || mnt->mnt_passno != pass)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* Device to maybe fsck, */
|
||||||
|
dev = mnt->mnt_fsname;
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
if (stat(fs->fs_spec, &st) || !S_ISBLK(st.st_mode)) {
|
if (stat(dev, &st) || !S_ISBLK(st.st_mode)) {
|
||||||
if (!string_match(fs->fs_spec, "UUID=") && !string_match(fs->fs_spec, "LABEL=")) {
|
int skip = 1;
|
||||||
_d("Cannot fsck %s, not a block device: %s", fs->fs_spec, strerror(errno));
|
|
||||||
|
if (string_match(dev, "UUID=") || string_match(dev, "LABEL="))
|
||||||
|
skip = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Kernel short form for root= device, figure out
|
||||||
|
* actual device since we cannot rely on symlinks
|
||||||
|
* https://bugs.busybox.net/show_bug.cgi?id=8891
|
||||||
|
*/
|
||||||
|
else if (string_compare(dev, "/dev/root")) {
|
||||||
|
if (fs_root_dev(real, sizeof(real))) {
|
||||||
|
dev = real;
|
||||||
|
skip = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skip) {
|
||||||
|
dbg("Cannot fsck %s, not a block device: %s", dev, strerror(errno));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ismnt("/proc/mounts", fs->fs_file, "rw")) {
|
if (ismnt("/proc/mounts", mnt->mnt_dir, "rw")) {
|
||||||
_d("Skipping fsck of %s, already mounted rw on %s.", fs->fs_spec, fs->fs_file);
|
dbg("Skipping fsck of %s, already mounted rw on %s.", dev, mnt->mnt_dir);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FSCK_FIX
|
snprintf(cmd, sizeof(cmd), "fsck %s %s %s", fsck_mode, fsck_repair, dev);
|
||||||
snprintf(cmd, sizeof(cmd), "fsck -yf %s", fs->fs_spec);
|
dbg("Running pass %d fsck command %s", pass, cmd);
|
||||||
#else
|
fsck_rc = run_interactive(cmd, "Checking filesystem %s", dev);
|
||||||
snprintf(cmd, sizeof(cmd), "fsck -a %s", fs->fs_spec);
|
|
||||||
#endif
|
|
||||||
fsck_rc = run_interactive(cmd, "Checking filesystem %.13s", fs->fs_spec);
|
|
||||||
/*
|
/*
|
||||||
* "failure" is defined as exiting with a return code of
|
* "failure" is defined as exiting with a return code of
|
||||||
* 2 or larger. A return code of 1 indicates that filesystem
|
* 2 or larger. A return code of 1 indicates that filesystem
|
||||||
* errors were corrected but that the boot may proceed.
|
* errors were corrected but that the boot may proceed.
|
||||||
*/
|
*/
|
||||||
if (fsck_rc > 1) {
|
if (fsck_rc > 1) {
|
||||||
char *sulogin[] = {
|
if (hasmntopt(mnt,"nofail")) {
|
||||||
_PATH_SULOGIN,
|
logit(LOG_CONSOLE | LOG_WARNING, "Ignoring failed fsck %s because of nofail option", dev);
|
||||||
"sulogin",
|
fsck_rc = 0;
|
||||||
};
|
} else {
|
||||||
size_t i;
|
logit(LOG_CONSOLE | LOG_ALERT, "Failed fsck %s, attempting sulogin ...", dev);
|
||||||
|
sulogin(1);
|
||||||
for (i = 0; i < NELEMS(sulogin); i++) {
|
|
||||||
if (systemf(sulogin[i]))
|
|
||||||
continue;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
do_shutdown(SHUT_REBOOT);
|
|
||||||
}
|
}
|
||||||
rc += fsck_rc;
|
rc |= fsck_rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
endfsent();
|
endmntent(fp);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -177,15 +291,17 @@ static int fsck(int pass)
|
|||||||
static int fsck_all(void)
|
static int fsck_all(void)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
#ifndef FAST_BOOT
|
|
||||||
int pass;
|
int pass;
|
||||||
|
|
||||||
|
if (!fsck_mode)
|
||||||
|
return 0;
|
||||||
|
|
||||||
for (pass = 1; pass < 10; pass++) {
|
for (pass = 1; pass < 10; pass++) {
|
||||||
rc = fsck(pass);
|
rc = fsck(pass);
|
||||||
if (rc)
|
if (rc)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,42 +314,26 @@ static void fs_mount(const char *src, const char *tgt, const char *fstype,
|
|||||||
|
|
||||||
rc = mount(src, tgt, fstype, flags, data);
|
rc = mount(src, tgt, fstype, flags, data);
|
||||||
if (rc && errno != EBUSY)
|
if (rc && errno != EBUSY)
|
||||||
_pe("Failed %s %s on %s", msg, src, tgt);
|
err(1, "Failed %s %s on %s", msg, src, tgt);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SYSROOT
|
#ifndef SYSROOT
|
||||||
/* If / is not listed in fstab, or listed as 'ro', leave it alone */
|
|
||||||
static int fs_readonly_root(struct fstab *fs)
|
|
||||||
{
|
|
||||||
char *tok, *str;
|
|
||||||
|
|
||||||
if (!fs)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
str = fs->fs_mntops;
|
|
||||||
while ((tok = strtok(str, ","))) {
|
|
||||||
if (!strcmp(tok, "ro"))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
str = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void fs_remount_root(int fsckerr)
|
static void fs_remount_root(int fsckerr)
|
||||||
{
|
{
|
||||||
struct fstab *fs;
|
struct mntent *mnt;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
if (!setfsent())
|
fp = setmntent(fstab, "r");
|
||||||
|
if (!fp)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
while ((fs = getfsent())) {
|
while ((mnt = getmntent(fp))) {
|
||||||
if (!strcmp(fs->fs_file, "/"))
|
if (!strcmp(mnt->mnt_dir, "/"))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fs_readonly_root(fs))
|
/* If / is not listed in fstab, or listed as 'ro', leave it alone */
|
||||||
|
if (!mnt || hasmntopt(mnt, "ro"))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (fsckerr)
|
if (fsckerr)
|
||||||
@@ -243,7 +343,7 @@ static void fs_remount_root(int fsckerr)
|
|||||||
"Remounting / as read-write");
|
"Remounting / as read-write");
|
||||||
|
|
||||||
out:
|
out:
|
||||||
endfsent();
|
endmntent(fp);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static void fs_remount_root(int fsckerr)
|
static void fs_remount_root(int fsckerr)
|
||||||
@@ -268,6 +368,8 @@ static void fs_remount_root(int fsckerr)
|
|||||||
*/
|
*/
|
||||||
static void fs_finalize(void)
|
static void fs_finalize(void)
|
||||||
{
|
{
|
||||||
|
int flags = MS_NOEXEC | MS_NOSUID;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some systems rely on us to both create /dev/shm and, to mount
|
* Some systems rely on us to both create /dev/shm and, to mount
|
||||||
* a tmpfs there. Any system with dbus needs shared memory, so
|
* a tmpfs there. Any system with dbus needs shared memory, so
|
||||||
@@ -275,8 +377,8 @@ static void fs_finalize(void)
|
|||||||
* the /etc/fstab file already.
|
* the /etc/fstab file already.
|
||||||
*/
|
*/
|
||||||
if (!fismnt("/dev/shm")) {
|
if (!fismnt("/dev/shm")) {
|
||||||
makedir("/dev/shm", 0777);
|
makedir("/dev/shm", 1777);
|
||||||
fs_mount("shm", "/dev/shm", "tmpfs", 0, "mode=0777");
|
fs_mount("shm", "/dev/shm", "tmpfs", flags | MS_NODEV, "mode=1777");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Modern systems use /dev/pts */
|
/* Modern systems use /dev/pts */
|
||||||
@@ -294,7 +396,13 @@ static void fs_finalize(void)
|
|||||||
snprintf(opts, sizeof(opts), "gid=%d,mode=%d,ptmxmode=0666", gid, mode);
|
snprintf(opts, sizeof(opts), "gid=%d,mode=%d,ptmxmode=0666", gid, mode);
|
||||||
|
|
||||||
makedir("/dev/pts", 0755);
|
makedir("/dev/pts", 0755);
|
||||||
fs_mount("devpts", "/dev/pts", "devpts", MS_NOSUID | MS_NOEXEC, opts);
|
fs_mount("devpts", "/dev/pts", "devpts", flags, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Needed on systems like Alpine Linux */
|
||||||
|
if (!fismnt("/dev/mqueue")) {
|
||||||
|
makedir("/dev/mqueue", 1777);
|
||||||
|
fs_mount("mqueue", "/dev/mqueue", "tmpfs", flags | MS_NODEV, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -306,7 +414,7 @@ static void fs_finalize(void)
|
|||||||
* To override any of this behavior, add entries to /etc/fstab
|
* To override any of this behavior, add entries to /etc/fstab
|
||||||
* for /run (and optionally /run/lock).
|
* for /run (and optionally /run/lock).
|
||||||
*/
|
*/
|
||||||
if (fisdir("/run") && !fismnt("/run")) {
|
if (fisdir("/run") && !fismnt("/run") && !fistmpfs("/run")) {
|
||||||
fs_mount("tmpfs", "/run", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME, "mode=0755,size=10%");
|
fs_mount("tmpfs", "/run", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME, "mode=0755,size=10%");
|
||||||
|
|
||||||
/* This prevents user DoS of /run by filling /run/lock at the expense of another tmpfs, max 5MiB */
|
/* This prevents user DoS of /run by filling /run/lock at the expense of another tmpfs, max 5MiB */
|
||||||
@@ -315,28 +423,79 @@ static void fs_finalize(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Modern systems use tmpfs for /tmp */
|
/* Modern systems use tmpfs for /tmp */
|
||||||
if (!fismnt("/tmp"))
|
if (!fismnt("/tmp") && !fistmpfs("/tmp"))
|
||||||
fs_mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_NODEV, "mode=1777");
|
fs_mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_NODEV, "mode=1777");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fs_swapon(char *cmd, size_t len)
|
||||||
|
{
|
||||||
|
struct mntent *mnt;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
if (!whichp("swapon"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
fp = setmntent(fstab, "r");
|
||||||
|
if (!fp)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while ((mnt = getmntent(fp))) {
|
||||||
|
if (strcmp(mnt->mnt_type, MNTTYPE_SWAP))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
snprintf(cmd, len, "swapon %s", mnt->mnt_fsname);
|
||||||
|
run_interactive(cmd, "Enabling swap %s", mnt->mnt_fsname);
|
||||||
|
}
|
||||||
|
|
||||||
|
endmntent(fp);
|
||||||
|
}
|
||||||
|
|
||||||
static void fs_mount_all(void)
|
static void fs_mount_all(void)
|
||||||
{
|
{
|
||||||
|
char cmd[256] = "mount -na";
|
||||||
|
|
||||||
|
if (!fstab || !fexist(fstab)) {
|
||||||
|
logit(LOG_CONSOLE | LOG_NOTICE, "%s system fstab %s, trying fallback ...",
|
||||||
|
!fstab ? "Missing" : "Cannot find", fstab ?: "\b");
|
||||||
|
fstab = FINIT_FSTAB;
|
||||||
|
}
|
||||||
|
if (!fstab || !fexist(fstab)) {
|
||||||
|
logit(LOG_CONSOLE | LOG_EMERG, "%s system fstab %s, attempting sulogin ...",
|
||||||
|
!fstab ? "Missing" : "Cannot find", fstab ?: "\b");
|
||||||
|
sulogin(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Needed by fsck, both BusyBox and util-linux support this.
|
||||||
|
* We leave it set in the env. for the benefit of any mount
|
||||||
|
* helpers and other system tools that the user expects to
|
||||||
|
* behave even if we've booted with a different fstab.
|
||||||
|
*/
|
||||||
|
setenv("FSTAB_FILE", fstab, 1);
|
||||||
|
|
||||||
if (!rescue)
|
if (!rescue)
|
||||||
fs_remount_root(fsck_all());
|
fs_remount_root(fsck_all());
|
||||||
|
|
||||||
_d("Root FS up, calling hooks ...");
|
dbg("Root FS up, calling hooks ...");
|
||||||
plugin_run_hooks(HOOK_ROOTFS_UP);
|
plugin_run_hooks(HOOK_ROOTFS_UP);
|
||||||
|
|
||||||
if (run_interactive("mount -na", "Mounting filesystems"))
|
if (fstab && strcmp(fstab, "/etc/fstab"))
|
||||||
|
snprintf(cmd, sizeof(cmd), "mount -na -T %s", fstab);
|
||||||
|
|
||||||
|
if (run_interactive(cmd, "Mounting filesystems from %s", fstab))
|
||||||
plugin_run_hooks(HOOK_MOUNT_ERROR);
|
plugin_run_hooks(HOOK_MOUNT_ERROR);
|
||||||
|
|
||||||
_d("Calling extra mount hook, after mount -a ...");
|
dbg("Calling extra mount hook, after mount -a ...");
|
||||||
plugin_run_hooks(HOOK_MOUNT_POST);
|
plugin_run_hooks(HOOK_MOUNT_POST);
|
||||||
|
|
||||||
run("swapon -ea");
|
dbg("Enable any swap ...");
|
||||||
|
fs_swapon(cmd, sizeof(cmd));
|
||||||
|
|
||||||
_d("Finalize, ensure common file systems are available ...");
|
dbg("Finalize, ensure common file systems are available ...");
|
||||||
fs_finalize();
|
fs_finalize();
|
||||||
|
|
||||||
|
dbg("Base FS up, calling hooks ...");
|
||||||
|
plugin_run_hooks(HOOK_BASEFS_UP);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -377,102 +536,6 @@ static void fs_init(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Handle bootstrap transition to configured runlevel, start TTYs
|
|
||||||
*
|
|
||||||
* This is the final stage of bootstrap. It changes to the default
|
|
||||||
* (configured) runlevel, calls all external start scripts and final
|
|
||||||
* bootstrap hooks before bringing up TTYs.
|
|
||||||
*
|
|
||||||
* We must ensure that all declared `task [S]` and `run [S]` jobs in
|
|
||||||
* finit.conf, or *.conf in finit.d/, run to completion before we
|
|
||||||
* finalize the bootstrap process by calling this function.
|
|
||||||
*/
|
|
||||||
static void finalize(void *unused)
|
|
||||||
{
|
|
||||||
/* Clean up bootstrap-only tasks/services that never started */
|
|
||||||
_d("Clean up all bootstrap-only tasks/services ...");
|
|
||||||
svc_prune_bootstrap();
|
|
||||||
|
|
||||||
/* All services/tasks/etc. in configure runlevel have started */
|
|
||||||
_d("Running svc up hooks ...");
|
|
||||||
plugin_run_hooks(HOOK_SVC_UP);
|
|
||||||
service_step_all(SVC_TYPE_ANY);
|
|
||||||
|
|
||||||
/* Convenient SysV compat for when you just don't care ... */
|
|
||||||
if (!access(FINIT_RC_LOCAL, X_OK) && !rescue)
|
|
||||||
run_interactive(FINIT_RC_LOCAL, "Calling %s", FINIT_RC_LOCAL);
|
|
||||||
|
|
||||||
/* Hooks that should run at the very end */
|
|
||||||
_d("Calling all system up hooks ...");
|
|
||||||
plugin_run_hooks(HOOK_SYSTEM_UP);
|
|
||||||
service_step_all(SVC_TYPE_ANY);
|
|
||||||
|
|
||||||
/* Disable progress output at normal runtime */
|
|
||||||
enable_progress(0);
|
|
||||||
|
|
||||||
/* System bootrapped, launch TTYs et al */
|
|
||||||
bootstrap = 0;
|
|
||||||
service_step_all(SVC_TYPE_RESPAWN);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Start cranking the big state machine
|
|
||||||
*/
|
|
||||||
static void crank_worker(void *unused)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Initialize state machine and start all bootstrap tasks
|
|
||||||
* NOTE: no network available!
|
|
||||||
*/
|
|
||||||
sm_init(&sm);
|
|
||||||
sm_step(&sm);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Wait for system bootstrap to complete, all SVC_TYPE_RUNTASK must be
|
|
||||||
* allowed to complete their work in [S], or timeout, before we switch
|
|
||||||
* to the configured runlevel and call finalize(), should not take more
|
|
||||||
* than 120 sec.
|
|
||||||
*/
|
|
||||||
static void bootstrap_worker(void *work)
|
|
||||||
{
|
|
||||||
static int cnt = 120;
|
|
||||||
static struct wq final = {
|
|
||||||
.cb = finalize,
|
|
||||||
.delay = 10
|
|
||||||
};
|
|
||||||
|
|
||||||
_d("Step all services ...");
|
|
||||||
service_step_all(SVC_TYPE_ANY);
|
|
||||||
|
|
||||||
if (cnt-- > 0 && !service_completed()) {
|
|
||||||
_d("Not all bootstrap run/tasks have completed yet ... %d", cnt);
|
|
||||||
schedule_work(work);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cnt > 0)
|
|
||||||
_d("All run/task have completed, resuming bootstrap.");
|
|
||||||
else
|
|
||||||
_d("Timeout, resuming bootstrap.");
|
|
||||||
|
|
||||||
_d("Starting runlevel change finalize ...");
|
|
||||||
schedule_work(&final);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Run startup scripts in the runparts directory, if any.
|
|
||||||
*/
|
|
||||||
if (runparts && fisdir(runparts) && !rescue)
|
|
||||||
run_parts(runparts, NULL);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Start all tasks/services in the configured runlevel
|
|
||||||
*/
|
|
||||||
_d("Change to default runlevel(%d), starting all services ...", cfglevel);
|
|
||||||
service_runlevel(cfglevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int version(int rc)
|
static int version(int rc)
|
||||||
{
|
{
|
||||||
puts(PACKAGE_STRING);
|
puts(PACKAGE_STRING);
|
||||||
@@ -503,7 +566,7 @@ static int usage(int rc)
|
|||||||
" 2-9 Change runlevel\n"
|
" 2-9 Change runlevel\n"
|
||||||
" q, Q Reload /etc/finit.conf and/or any *.conf in /etc/finit.d/\n"
|
" q, Q Reload /etc/finit.conf and/or any *.conf in /etc/finit.d/\n"
|
||||||
" if modified, same as initctl reload or SIGHUP to PID 1\n"
|
" if modified, same as initctl reload or SIGHUP to PID 1\n"
|
||||||
" 1, s, S Enter system rescue mode, runlevel 1\n"
|
" 1, s, S Enter single user mode, no networking, runlevel 1\n"
|
||||||
"\n", prognm);
|
"\n", prognm);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
@@ -548,30 +611,26 @@ static int telinit(int argc, char *argv[])
|
|||||||
return systemf("initctl -b runlevel %c", req);
|
return systemf("initctl -b runlevel %c", req);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: add non-pid1 process monitor here
|
|
||||||
*
|
|
||||||
* finit -f ~/.config/finit.conf &
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
return usage(1);
|
return usage(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct wq crank_work = {
|
|
||||||
.cb = crank_worker,
|
|
||||||
.delay = 10
|
|
||||||
};
|
|
||||||
struct wq bootstrap_work = {
|
|
||||||
.cb = bootstrap_worker,
|
|
||||||
.delay = 100
|
|
||||||
};
|
|
||||||
uev_ctx_t loop;
|
uev_ctx_t loop;
|
||||||
|
|
||||||
/* telinit or stand-alone process monitor */
|
/* user calling telinit or init */
|
||||||
if (getpid() != 1)
|
if (getpid() != 1) {
|
||||||
return telinit(argc, argv);
|
if (geteuid() == 0)
|
||||||
|
return telinit(argc, argv);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Issue #301: add non-pid1 process monitor here.
|
||||||
|
* Default to read ~/.config/finit.conf with the
|
||||||
|
* API socket in /run/user/$UID/. Lot of things
|
||||||
|
* to refactor before then though.
|
||||||
|
*/
|
||||||
|
return EX_NOPERM;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Need /dev, /proc, and /sys for console=, remount and cgroups
|
* Need /dev, /proc, and /sys for console=, remount and cgroups
|
||||||
@@ -580,12 +639,12 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse /proc/cmdline (debug, rescue, console=, etc.)
|
* Parse /proc/cmdline (debug, rescue, console=, etc.)
|
||||||
* Also calls log_init() to set correct log level
|
|
||||||
*/
|
*/
|
||||||
conf_parse_cmdline(argc, argv);
|
conf_parse_cmdline(argc, argv);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Figure out system console(s)
|
* Figure out system console(s) and call log_init() to set
|
||||||
|
* correct log level, possibly finit.debug enabled.
|
||||||
*/
|
*/
|
||||||
console_init();
|
console_init();
|
||||||
|
|
||||||
@@ -598,32 +657,18 @@ int main(int argc, char *argv[])
|
|||||||
/*
|
/*
|
||||||
* Set PATH, SHELL, and PWD early to something sane
|
* Set PATH, SHELL, and PWD early to something sane
|
||||||
*/
|
*/
|
||||||
setenv("PATH", _PATH_STDPATH, 1);
|
conf_reset_env();
|
||||||
setenv("SHELL", _PATH_BSHELL, 1);
|
|
||||||
setenv("LOGNAME", "root", 1);
|
|
||||||
setenv("USER", "root", 1);
|
|
||||||
|
|
||||||
if (chdir("/"))
|
if (chdir("/"))
|
||||||
_pe("Failed cd /");
|
err(1, "Failed cd /");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In case of emergency.
|
* In case of emergency.
|
||||||
*/
|
*/
|
||||||
if (rescue) {
|
#ifdef RESCUE_MODE
|
||||||
char *sulogin[] = {
|
if (rescue)
|
||||||
_PATH_SULOGIN,
|
rescue = sulogin(0);
|
||||||
"sulogin",
|
#endif
|
||||||
};
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for (i = 0; i < NELEMS(sulogin); i++) {
|
|
||||||
if (systemf(sulogin[i]))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
rescue = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Load plugins early, the first hook is in banner(), so we
|
* Load plugins early, the first hook is in banner(), so we
|
||||||
@@ -652,10 +697,17 @@ int main(int argc, char *argv[])
|
|||||||
*/
|
*/
|
||||||
cgroup_init(&loop);
|
cgroup_init(&loop);
|
||||||
|
|
||||||
/* Check and mount filesystems. */
|
/*
|
||||||
|
* Check custom fstab from cmdline, including fallback, then run
|
||||||
|
* fsck before mounting all filesystems, on error call sulogin.
|
||||||
|
*/
|
||||||
fs_mount_all();
|
fs_mount_all();
|
||||||
|
|
||||||
/* Bootstrap conditions, needed for hooks */
|
/*
|
||||||
|
* Base FS up, enable standard SysV init signals and
|
||||||
|
* Bootstrap conditions, needed for hooks
|
||||||
|
*/
|
||||||
|
sig_setup(&loop);
|
||||||
cond_init();
|
cond_init();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -665,30 +717,17 @@ int main(int argc, char *argv[])
|
|||||||
cond_set_oneshot(plugin_hook_str(HOOK_BANNER));
|
cond_set_oneshot(plugin_hook_str(HOOK_BANNER));
|
||||||
cond_set_oneshot(plugin_hook_str(HOOK_ROOTFS_UP));
|
cond_set_oneshot(plugin_hook_str(HOOK_ROOTFS_UP));
|
||||||
|
|
||||||
|
/* Some bootstrap tasks may need to know if we're in a container. */
|
||||||
|
if (in_container())
|
||||||
|
cond_set_oneshot("int/container");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize .conf system and load static /etc/finit.conf.
|
* Initialize .conf system and load static /etc/finit.conf then
|
||||||
|
* tell the world what we used.
|
||||||
*/
|
*/
|
||||||
|
devmon_init(&loop);
|
||||||
conf_init(&loop);
|
conf_init(&loop);
|
||||||
|
conf_saverc();
|
||||||
/*
|
|
||||||
* Start built-in watchdogd as soon as possible, if enabled
|
|
||||||
*/
|
|
||||||
if (whichp(FINIT_LIBPATH_ "/watchdogd") && fexist(WDT_DEVNODE)) {
|
|
||||||
service_register(SVC_TYPE_SERVICE, "[123456789] cgroup.init name:watchdog :finit " FINIT_LIBPATH_ "/watchdogd -- Finit watchdog daemon", global_rlimit, NULL);
|
|
||||||
wdog = svc_find_by_nameid("watchdog", "finit");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Start kernel event daemon as soon as possible, if enabled
|
|
||||||
*/
|
|
||||||
if (whichp(FINIT_LIBPATH_ "/keventd"))
|
|
||||||
service_register(SVC_TYPE_SERVICE, "[123456789] cgroup.init " FINIT_LIBPATH_ "/keventd -- Finit kernel event daemon", global_rlimit, NULL);
|
|
||||||
|
|
||||||
/* Base FS up, enable standard SysV init signals */
|
|
||||||
sig_setup(&loop);
|
|
||||||
|
|
||||||
_d("Base FS up, calling hooks ...");
|
|
||||||
plugin_run_hooks(HOOK_BASEFS_UP);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up inotify watcher for /etc/finit.conf, /etc/finit.d, and
|
* Set up inotify watcher for /etc/finit.conf, /etc/finit.d, and
|
||||||
@@ -696,24 +735,23 @@ int main(int argc, char *argv[])
|
|||||||
*/
|
*/
|
||||||
conf_monitor();
|
conf_monitor();
|
||||||
|
|
||||||
_d("Starting initctl API responder ...");
|
dbg("Starting initctl API responder ...");
|
||||||
api_init(&loop);
|
api_init(&loop);
|
||||||
|
|
||||||
_d("Starting the big state machine ...");
|
dbg("Starting service interval monitor ...");
|
||||||
schedule_work(&crank_work);
|
service_init(&loop);
|
||||||
|
|
||||||
_d("Starting bootstrap finalize timer ...");
|
|
||||||
schedule_work(&bootstrap_work);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Background service tasks
|
* Initialize state machine and start all bootstrap tasks
|
||||||
|
* NOTE: no network available!
|
||||||
*/
|
*/
|
||||||
service_init();
|
sm_init(&sm);
|
||||||
|
sm_step(&sm);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enter main loop to monitor /dev/initctl and services
|
* Enter main loop to monitor /dev/initctl and services
|
||||||
*/
|
*/
|
||||||
_d("Entering main loop ...");
|
dbg("Entering main loop ...");
|
||||||
return uev_run(&loop, 0);
|
return uev_run(&loop, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+17
-10
@@ -1,7 +1,7 @@
|
|||||||
/* Finit - Fast /sbin/init replacement w/ I/O, hook & service plugins
|
/* Finit - Fast /sbin/init replacement w/ I/O, hook & service plugins
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||||
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -54,19 +54,21 @@
|
|||||||
#define FINIT_CGPATH "/sys/fs/cgroup"
|
#define FINIT_CGPATH "/sys/fs/cgroup"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* To use these, include config.h, or define FINIT_LIBPATH_ */
|
/* To use these, include config.h, or define FINIT_EXECPATH_ */
|
||||||
#define _PATH_LOGIT FINIT_LIBPATH_ "/logit"
|
#define _PATH_LOGIT FINIT_EXECPATH_ "/logit"
|
||||||
#define _PATH_SULOGIN FINIT_LIBPATH_ "/sulogin"
|
#define _PATH_RUNPARTS FINIT_EXECPATH_ "/runparts"
|
||||||
#define _PATH_GETTY FINIT_LIBPATH_ "/getty"
|
#define _PATH_SULOGIN FINIT_EXECPATH_ "/sulogin"
|
||||||
|
#define _PATH_GETTY FINIT_EXECPATH_ "/getty"
|
||||||
|
|
||||||
#define CMD_SIZE 256
|
#define CMD_SIZE 1024
|
||||||
#define LINE_SIZE 1024
|
#define LINE_SIZE 1024
|
||||||
#define BUF_SIZE 4096
|
#define BUF_SIZE 4096
|
||||||
|
|
||||||
/* We extend the INIT_CMD_ range for the new initctl tool. */
|
|
||||||
#define INIT_SOCKET _PATH_VARRUN "finit/socket"
|
#define INIT_SOCKET _PATH_VARRUN "finit/socket"
|
||||||
#define INIT_MAGIC 0x03091969
|
#define INIT_MAGIC 0x03091969
|
||||||
|
#define INIT_LEVEL 10
|
||||||
|
|
||||||
|
/* We extend the INIT_CMD_ range for the new initctl tool. */
|
||||||
#define INIT_CMD_START 0
|
#define INIT_CMD_START 0
|
||||||
#define INIT_CMD_RUNLVL 1
|
#define INIT_CMD_RUNLVL 1
|
||||||
#define INIT_CMD_POWERFAIL 2
|
#define INIT_CMD_POWERFAIL 2
|
||||||
@@ -83,8 +85,8 @@
|
|||||||
#define INIT_CMD_STOP_SVC 11
|
#define INIT_CMD_STOP_SVC 11
|
||||||
#define INIT_CMD_RELOAD_SVC 12 /* SIGHUP service */
|
#define INIT_CMD_RELOAD_SVC 12 /* SIGHUP service */
|
||||||
#define INIT_CMD_RESTART_SVC 13 /* START service, clearing blocks */
|
#define INIT_CMD_RESTART_SVC 13 /* START service, clearing blocks */
|
||||||
#define INIT_CMD_UNUSED2 14 /* Unused, was INIT_CMD_QUERY_INETD */
|
#define INIT_CMD_GET_PLUGINS 14 /* Fill data[] with loaded plugins */
|
||||||
#define INIT_CMD_UNUSED1 15 /* Unused, was INIT_CMD_EMIT */
|
#define INIT_CMD_PLUGIN_DEPS 15 /* Fill data[] with plugin deps */
|
||||||
#define INIT_CMD_GET_RUNLEVEL 16
|
#define INIT_CMD_GET_RUNLEVEL 16
|
||||||
#define INIT_CMD_REBOOT 20
|
#define INIT_CMD_REBOOT 20
|
||||||
#define INIT_CMD_HALT 21
|
#define INIT_CMD_HALT 21
|
||||||
@@ -95,6 +97,8 @@
|
|||||||
#define INIT_CMD_SVC_QUERY 130
|
#define INIT_CMD_SVC_QUERY 130
|
||||||
#define INIT_CMD_SVC_FIND 131
|
#define INIT_CMD_SVC_FIND 131
|
||||||
#define INIT_CMD_SVC_FIND_BYC 132
|
#define INIT_CMD_SVC_FIND_BYC 132
|
||||||
|
#define INIT_CMD_SIGNAL 133
|
||||||
|
#define INIT_CMD_NOTIFY_SOCKET 200 /* For readiness notification socket */
|
||||||
#define INIT_CMD_NACK 254
|
#define INIT_CMD_NACK 254
|
||||||
#define INIT_CMD_ACK 255
|
#define INIT_CMD_ACK 255
|
||||||
|
|
||||||
@@ -109,13 +113,16 @@ struct init_request {
|
|||||||
|
|
||||||
extern int runlevel;
|
extern int runlevel;
|
||||||
extern int cfglevel;
|
extern int cfglevel;
|
||||||
|
extern int cmdlevel;
|
||||||
extern int prevlevel;
|
extern int prevlevel;
|
||||||
extern int debug;
|
extern int debug;
|
||||||
extern int rescue;
|
extern int rescue;
|
||||||
extern int single;
|
extern int single;
|
||||||
extern int bootstrap;
|
extern int bootstrap;
|
||||||
extern int kerndebug;
|
extern int kerndebug;
|
||||||
extern char *rcsd;
|
extern int syncsec;
|
||||||
|
extern int readiness;
|
||||||
|
extern char *fstab;
|
||||||
extern char *sdown;
|
extern char *sdown;
|
||||||
extern char *network;
|
extern char *network;
|
||||||
extern char *hostname;
|
extern char *hostname;
|
||||||
|
|||||||
+152
-20
@@ -1,6 +1,6 @@
|
|||||||
/* Initialize and serve a login terminal
|
/* Initialize and serve a login terminal
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2016-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* 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,7 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h" /* Generated by configure script */
|
||||||
|
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -34,6 +34,7 @@
|
|||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
|
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
|
#include <time.h>
|
||||||
#include <unistd.h> /* sysconf() */
|
#include <unistd.h> /* sysconf() */
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
@@ -48,7 +49,83 @@
|
|||||||
#define LOGIN_NAME_MIN 64
|
#define LOGIN_NAME_MIN 64
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct osrel {
|
||||||
|
char name[32];
|
||||||
|
char pretty[64];
|
||||||
|
char id[32];
|
||||||
|
char version[32];
|
||||||
|
char version_id[32];
|
||||||
|
char home_url[128];
|
||||||
|
char doc_url[128];
|
||||||
|
char bug_url[128];
|
||||||
|
char support_url[128];
|
||||||
|
};
|
||||||
|
|
||||||
static long logname_len = 32; /* useradd(1) limit at 32 chars */
|
static long logname_len = 32; /* useradd(1) limit at 32 chars */
|
||||||
|
static int passenv = 0; /* Set /bin/login -p or not */
|
||||||
|
|
||||||
|
static void get_val(char *line, const char *key, char *buf, size_t len)
|
||||||
|
{
|
||||||
|
char *val;
|
||||||
|
|
||||||
|
if ((val = fgetval(line, key, "="))) {
|
||||||
|
strlcpy(buf, val, len);
|
||||||
|
free(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse os-release
|
||||||
|
*/
|
||||||
|
static int osrel(struct osrel *rel)
|
||||||
|
{
|
||||||
|
char codename[30];
|
||||||
|
char *line;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopen("/etc/os-release", "r");
|
||||||
|
if (!fp) {
|
||||||
|
fp = fopen("/usr/lib/os-release", "r");
|
||||||
|
if (!fp)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(rel->version, 0, sizeof(rel->version));
|
||||||
|
memset(codename, 0, sizeof(codename));
|
||||||
|
|
||||||
|
while ((line = fparseln(fp, NULL, NULL, NULL, 0))) {
|
||||||
|
get_val(line, "NAME", rel->name, sizeof(rel->name));
|
||||||
|
get_val(line, "PRETTY_NAME", rel->pretty, sizeof(rel->pretty));
|
||||||
|
get_val(line, "ID", rel->id, sizeof(rel->id));
|
||||||
|
get_val(line, "VERSION", rel->version, sizeof(rel->version));
|
||||||
|
get_val(line, "VERSION_ID", rel->version_id, sizeof(rel->version_id));
|
||||||
|
get_val(line, "VERSION_CODENAME", codename, sizeof(codename));
|
||||||
|
get_val(line, "HOME_URL", rel->home_url, sizeof(rel->home_url));
|
||||||
|
get_val(line, "DOCUMENTATION_URL", rel->doc_url, sizeof(rel->doc_url));
|
||||||
|
get_val(line, "SUPPORT_URL", rel->support_url, sizeof(rel->support_url));
|
||||||
|
get_val(line, "BUG_REPORT_URL", rel->bug_url, sizeof(rel->bug_url));
|
||||||
|
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Many distros don't set VERSION or VERSION_ID for their
|
||||||
|
* rolling, or unstable, branches. However, most set the
|
||||||
|
* version code name, so we use that as VERSION.
|
||||||
|
*/
|
||||||
|
if (!rel->version[0] && codename[0]) {
|
||||||
|
if (codename[0] == '(')
|
||||||
|
strlcpy(rel->version, codename, sizeof(rel->version));
|
||||||
|
else
|
||||||
|
snprintf(rel->version, sizeof(rel->version), "(%s)", codename);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rel->id[0] && !strcmp(rel->id, "alpine"))
|
||||||
|
return 1; /* compat mode for \r et al. */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read one character from stdin.
|
* Read one character from stdin.
|
||||||
@@ -67,10 +144,19 @@ static int readch(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse and display a line from /etc/issue
|
* Parse and display a line from /etc/issue
|
||||||
|
*
|
||||||
|
* Includes Finit-specific extensions to display information from
|
||||||
|
* /etc/os-release instead of relying on legacy uname. Activated
|
||||||
|
* only if /etc/os-release or /usr/lib/os-release exist.
|
||||||
|
*
|
||||||
|
* https://www.unix.com/man-page/Linux/8/getty/
|
||||||
|
* https://www.systutorials.com/docs/linux/man/8-mingetty/
|
||||||
*/
|
*/
|
||||||
static void do_parse(char *line, struct utsname *uts, char *tty)
|
static void parseln(char *line, struct utsname *uts, struct osrel *rel, char *tty, int compat)
|
||||||
{
|
{
|
||||||
|
char buf[32] = { 0 };
|
||||||
char *s, *s0;
|
char *s, *s0;
|
||||||
|
time_t now;
|
||||||
|
|
||||||
s0 = line;
|
s0 = line;
|
||||||
for (s = line; *s != 0; s++) {
|
for (s = line; *s != 0; s++) {
|
||||||
@@ -79,12 +165,32 @@ static void do_parse(char *line, struct utsname *uts, char *tty)
|
|||||||
dprint(STDOUT_FILENO, s0, s - s0);
|
dprint(STDOUT_FILENO, s0, s - s0);
|
||||||
s0 = s + 2;
|
s0 = s + 2;
|
||||||
switch (*++s) {
|
switch (*++s) {
|
||||||
|
case 'B':
|
||||||
|
if (!compat)
|
||||||
|
dprint(STDOUT_FILENO, rel->bug_url, 0);
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
if (!compat)
|
||||||
|
dprint(STDOUT_FILENO, rel->doc_url, 0);
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
if (!compat)
|
||||||
|
dprint(STDOUT_FILENO, rel->home_url, 0);
|
||||||
|
break;
|
||||||
|
case 'I':
|
||||||
|
if (!compat)
|
||||||
|
dprint(STDOUT_FILENO, rel->id, 0);
|
||||||
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
dprint(STDOUT_FILENO, tty, 0);
|
dprint(STDOUT_FILENO, tty, 0);
|
||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
dprint(STDOUT_FILENO, uts->machine, 0);
|
dprint(STDOUT_FILENO, uts->machine, 0);
|
||||||
break;
|
break;
|
||||||
|
case 'N':
|
||||||
|
if (!compat)
|
||||||
|
dprint(STDOUT_FILENO, rel->name, 0);
|
||||||
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
dprint(STDOUT_FILENO, uts->nodename, 0);
|
dprint(STDOUT_FILENO, uts->nodename, 0);
|
||||||
break;
|
break;
|
||||||
@@ -94,13 +200,31 @@ static void do_parse(char *line, struct utsname *uts, char *tty)
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case 'r':
|
case 'r':
|
||||||
dprint(STDOUT_FILENO, uts->release, 0);
|
if (compat)
|
||||||
|
dprint(STDOUT_FILENO, uts->release, 0);
|
||||||
|
else
|
||||||
|
dprint(STDOUT_FILENO, rel->version_id, 0);
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
if (!compat)
|
||||||
|
dprint(STDOUT_FILENO, rel->support_url, 0);
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
dprint(STDOUT_FILENO, uts->sysname, 0);
|
if (compat)
|
||||||
|
dprint(STDOUT_FILENO, uts->sysname, 0);
|
||||||
|
else
|
||||||
|
dprint(STDOUT_FILENO, rel->pretty, 0);
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
now = time(NULL);
|
||||||
|
ctime_r(&now, buf);
|
||||||
|
dprint(STDOUT_FILENO, chomp(buf), 0);
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
dprint(STDOUT_FILENO, uts->version, 0);
|
if (compat)
|
||||||
|
dprint(STDOUT_FILENO, uts->version, 0);
|
||||||
|
else
|
||||||
|
dprint(STDOUT_FILENO, rel->version, 0);
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
goto leave;
|
goto leave;
|
||||||
@@ -118,28 +242,31 @@ leave:
|
|||||||
/*
|
/*
|
||||||
* Parse and display /etc/issue
|
* Parse and display /etc/issue
|
||||||
*/
|
*/
|
||||||
static void do_issue(char *tty)
|
static void issue(char *tty)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
|
||||||
char buf[BUFSIZ] = "Welcome to \\s \\v \\n \\l\n\n";
|
char buf[BUFSIZ] = "Welcome to \\s \\v \\n \\l\n\n";
|
||||||
struct utsname uts;
|
struct utsname uts;
|
||||||
|
struct osrel rel;
|
||||||
|
int compat;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get data about this machine.
|
* Get data about this machine.
|
||||||
*/
|
*/
|
||||||
uname(&uts);
|
uname(&uts);
|
||||||
|
compat = osrel(&rel);
|
||||||
|
|
||||||
fp = fopen("/etc/issue", "r");
|
fp = fopen("/etc/issue", "r");
|
||||||
if (fp) {
|
if (fp) {
|
||||||
while (fgets(buf, sizeof(buf), fp))
|
while (fgets(buf, sizeof(buf), fp))
|
||||||
do_parse(buf, &uts, tty);
|
parseln(buf, &uts, &rel, tty, compat);
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
} else {
|
} else {
|
||||||
do_parse(buf, &uts, tty);
|
parseln(buf, &uts, &rel, tty, compat);
|
||||||
}
|
}
|
||||||
|
|
||||||
do_parse("\\n login: ", &uts, tty);
|
parseln("\\n login: ", &uts, &rel, tty, compat);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -156,7 +283,7 @@ static int get_logname(char *tty, char *name, size_t len)
|
|||||||
ch = ' ';
|
ch = ' ';
|
||||||
*name = '\0';
|
*name = '\0';
|
||||||
while (ch != '\n') {
|
while (ch != '\n') {
|
||||||
do_issue(tty);
|
issue(tty);
|
||||||
|
|
||||||
np = name;
|
np = name;
|
||||||
while ((ch = readch()) != '\n') {
|
while ((ch = readch()) != '\n') {
|
||||||
@@ -177,15 +304,17 @@ static int get_logname(char *tty, char *name, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Execute the login(1) command with the current
|
* Start login(1) with the current username as its argument. It replies
|
||||||
* username as its argument. It will reply to the
|
* to the calling user by typing "Password: " ...
|
||||||
* calling user by typing "Password: "...
|
|
||||||
*/
|
*/
|
||||||
static int do_login(char *name)
|
static int exec_login(char *name)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
execl(_PATH_LOGIN, _PATH_LOGIN, name, NULL);
|
if (passenv)
|
||||||
|
execl(_PATH_LOGIN, _PATH_LOGIN, "-p", "--", name, NULL);
|
||||||
|
else
|
||||||
|
execl(_PATH_LOGIN, _PATH_LOGIN, "--", name, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Failed to exec login, should not happen on normal systems.
|
* Failed to exec login, should not happen on normal systems.
|
||||||
@@ -238,12 +367,12 @@ restart:
|
|||||||
if (term && term[0])
|
if (term && term[0])
|
||||||
setenv("TERM", term, 1);
|
setenv("TERM", term, 1);
|
||||||
|
|
||||||
return do_login(name);
|
return exec_login(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int usage(int rc)
|
static int usage(int rc)
|
||||||
{
|
{
|
||||||
warnx("usage: getty [-h?] tty [speed [term]]");
|
warnx("usage: getty [-h?p] tty [speed [term]]");
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,11 +381,14 @@ int main(int argc, char *argv[])
|
|||||||
char *tty, *speed = "0", *term = NULL;
|
char *tty, *speed = "0", *term = NULL;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, "h?")) != EOF) {
|
while ((c = getopt(argc, argv, "h?p")) != EOF) {
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case 'h':
|
case 'h':
|
||||||
case '?':
|
case '?':
|
||||||
return usage(0);
|
return usage(0);
|
||||||
|
case 'p':
|
||||||
|
passenv = 1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return usage(1);
|
return usage(1);
|
||||||
}
|
}
|
||||||
|
|||||||
+103
-52
@@ -1,7 +1,7 @@
|
|||||||
/* Misc. utility functions for finit and its plugins
|
/* Misc. utility functions for finit and its plugins
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||||
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* 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,6 +22,8 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h" /* Generated by configure script */
|
||||||
|
|
||||||
#include <ctype.h> /* isblank() */
|
#include <ctype.h> /* isblank() */
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
@@ -30,6 +32,7 @@
|
|||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <sysexits.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#ifdef _LIBITE_LITE
|
#ifdef _LIBITE_LITE
|
||||||
# include <libite/lite.h>
|
# include <libite/lite.h>
|
||||||
@@ -39,7 +42,9 @@
|
|||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
#include "log.h"
|
||||||
#include "private.h"
|
#include "private.h"
|
||||||
|
#include "sig.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "utmp-api.h"
|
#include "utmp-api.h"
|
||||||
|
|
||||||
@@ -57,7 +62,7 @@ static pstyle_t progress_style = PROGRESS_DEFAULT;
|
|||||||
#define STATUS_CLASS { \
|
#define STATUS_CLASS { \
|
||||||
CHOOSE(" OK ", " OK ", "\e[1;32m"), /* Green */ \
|
CHOOSE(" OK ", " OK ", "\e[1;32m"), /* Green */ \
|
||||||
CHOOSE("FAIL", "FAIL", "\e[1;31m"), /* Red */ \
|
CHOOSE("FAIL", "FAIL", "\e[1;31m"), /* Red */ \
|
||||||
CHOOSE("WARN", "WARN", "\e[1;31m"), /* Red */ \
|
CHOOSE("WARN", "WARN", "\e[1;33m"), /* Yellow */ \
|
||||||
CHOOSE(" \\/ ", " ⋯ ", "\e[1;33m"), /* Yellow */ \
|
CHOOSE(" \\/ ", " ⋯ ", "\e[1;33m"), /* Yellow */ \
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +84,13 @@ char *console(void)
|
|||||||
|
|
||||||
void console_init(void)
|
void console_init(void)
|
||||||
{
|
{
|
||||||
ttinit();
|
/* Enable line wrap, if disabled previously, e.g., qemu */
|
||||||
|
dprint(STDOUT_FILENO, "\033[?7h", 5);
|
||||||
|
|
||||||
|
/* Reset attributes, background and foreground color */
|
||||||
|
dprint(STDOUT_FILENO, "\033[49m\033[39m\e[2J", 14);
|
||||||
|
|
||||||
|
log_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t cprintf(const char *fmt, ...)
|
ssize_t cprintf(const char *fmt, ...)
|
||||||
@@ -98,6 +109,17 @@ ssize_t cprintf(const char *fmt, ...)
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tabstospaces(char *line)
|
||||||
|
{
|
||||||
|
if (!line)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (int i = 0; line[i]; i++) {
|
||||||
|
if (line[i] == '\t')
|
||||||
|
line[i] = ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
char *strip_line(char *line)
|
char *strip_line(char *line)
|
||||||
{
|
{
|
||||||
char *ptr;
|
char *ptr;
|
||||||
@@ -351,7 +373,8 @@ int print_result(int fail)
|
|||||||
int getuser(char *username, char **home)
|
int getuser(char *username, char **home)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_STATIC
|
#ifdef ENABLE_STATIC
|
||||||
*home = "/"; /* XXX: Fixme */
|
if (home)
|
||||||
|
*home = "/"; /* XXX: Fixme */
|
||||||
return fgetint("/etc/passwd", "x:\n", username);
|
return fgetint("/etc/passwd", "x:\n", username);
|
||||||
#else
|
#else
|
||||||
struct passwd *usr;
|
struct passwd *usr;
|
||||||
@@ -428,8 +451,10 @@ int mksubsys(const char *dir, mode_t mode, char *user, char *group)
|
|||||||
gid = 0;
|
gid = 0;
|
||||||
|
|
||||||
rc = makedir(dir, mode);
|
rc = makedir(dir, mode);
|
||||||
|
if (rc && errno == EEXIST)
|
||||||
|
rc = chmod(dir, mode);
|
||||||
if (chown(dir, uid, gid))
|
if (chown(dir, uid, gid))
|
||||||
_pe("Failed chown(%s, %d, %d)", dir, uid, gid);
|
err(1, "Failed chown(%s, %d, %d)", dir, uid, gid);
|
||||||
}
|
}
|
||||||
|
|
||||||
umask(omask);
|
umask(omask);
|
||||||
@@ -467,7 +492,7 @@ void set_hostname(char **hostname)
|
|||||||
done:
|
done:
|
||||||
if (*hostname) {
|
if (*hostname) {
|
||||||
if (sethostname(*hostname, strlen(*hostname)))
|
if (sethostname(*hostname, strlen(*hostname)))
|
||||||
_pe("Failed sethostnaem(%s)", *hostname);
|
err(1, "Failed sethostname(%s)", *hostname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -481,9 +506,9 @@ void networking(int updown)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (updown)
|
if (updown)
|
||||||
_d("Setting up networking ...");
|
dbg("Setting up networking ...");
|
||||||
else
|
else
|
||||||
_d("Taking down networking ...");
|
dbg("Taking down networking ...");
|
||||||
|
|
||||||
/* Run user network start script if enabled */
|
/* Run user network start script if enabled */
|
||||||
if (updown && network) {
|
if (updown && network) {
|
||||||
@@ -493,77 +518,103 @@ void networking(int updown)
|
|||||||
|
|
||||||
/* Debian/Ubuntu/Busybox/RH/Suse */
|
/* Debian/Ubuntu/Busybox/RH/Suse */
|
||||||
if (!whichp("ifup"))
|
if (!whichp("ifup"))
|
||||||
goto done;
|
goto fallback;
|
||||||
|
|
||||||
if (fexist("/etc/network/interfaces")) {
|
if (fexist("/etc/network/interfaces")) {
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
|
const char *cmd;
|
||||||
|
char buf[256];
|
||||||
|
FILE *pp;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
setsid();
|
||||||
|
sig_unblock();
|
||||||
|
|
||||||
if (updown)
|
if (updown)
|
||||||
run("ifup -a");
|
cmd = "ifup -a 2>&1";
|
||||||
|
else if (whichp("ifquery"))
|
||||||
|
/* Regular ifodwn supports --force but not -f */
|
||||||
|
cmd = "ifdown -a --force 2>&1";
|
||||||
else
|
else
|
||||||
run("ifdown -a");
|
/* Busybox ifdown support -f, but not --force */
|
||||||
_exit(0);
|
cmd = "ifdown -a -f 2>&1";
|
||||||
|
|
||||||
|
pp = popen(cmd, "r");
|
||||||
|
if (!pp)
|
||||||
|
_exit(EX_OSERR);
|
||||||
|
|
||||||
|
while (fgets(buf, sizeof(buf), pp))
|
||||||
|
logit(LOG_NOTICE, "network: %s", chomp(buf));
|
||||||
|
|
||||||
|
rc = pclose(pp);
|
||||||
|
if (rc == -1)
|
||||||
|
_exit(EX_OSERR);
|
||||||
|
_exit(WEXITSTATUS(rc));
|
||||||
}
|
}
|
||||||
cgroup_service("network", pid, NULL);
|
cgroup_service("network", pid, NULL);
|
||||||
|
print(pid > 0 ? 0 : 1, "%s network interfaces ...",
|
||||||
|
updown ? "Bringing up" : "Taking down");
|
||||||
|
|
||||||
print(pid > 0 ? 0 : 1, "%s networking", updown ? "Starting" : "Stopping");
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
fallback:
|
||||||
/* Fall back to bring up at least loopback */
|
/* Fall back to bring up at least loopback */
|
||||||
ifconfig("lo", "127.0.0.1", "255.0.0.0", updown);
|
ifconfig("lo", "127.0.0.1", "255.0.0.0", updown);
|
||||||
|
done:
|
||||||
|
|
||||||
/* Hooks that rely on loopback, or basic networking being up. */
|
/* Hooks that rely on loopback, or basic networking being up. */
|
||||||
if (updown) {
|
if (updown) {
|
||||||
_d("Calling all network up hooks ...");
|
dbg("Calling all network up hooks ...");
|
||||||
plugin_run_hooks(HOOK_NETWORK_UP);
|
plugin_run_hooks(HOOK_NETWORK_UP);
|
||||||
|
} else {
|
||||||
|
dbg("Calling all network down hooks ...");
|
||||||
|
plugin_run_hooks(HOOK_NETWORK_DN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef HAVE_GETFSENT
|
/*
|
||||||
static lfile_t *fstab = NULL;
|
* Very basic, and incomplete, check if we're running in a container.
|
||||||
|
*/
|
||||||
int setfsent(void)
|
int in_container(void)
|
||||||
{
|
{
|
||||||
if (fstab)
|
const char *containers[] = {
|
||||||
lfclose(fstab);
|
"lxc",
|
||||||
|
"docker",
|
||||||
|
"kubepod",
|
||||||
|
"unshare",
|
||||||
|
"systemd-nspawn"
|
||||||
|
};
|
||||||
|
const char *files[] = {
|
||||||
|
"/run/.containerenv",
|
||||||
|
"/.dockerenv"
|
||||||
|
};
|
||||||
|
static int incont = -1;
|
||||||
|
size_t i;
|
||||||
|
char *c;
|
||||||
|
|
||||||
fstab = lfopen("/etc/fstab", " \t\n");
|
if (incont > 0)
|
||||||
if (!fstab)
|
return incont;
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 1;
|
c = getenv("container");
|
||||||
|
if (c) {
|
||||||
|
for (i = 0; i < NELEMS(containers); i++) {
|
||||||
|
if (!strcmp(containers[i], c))
|
||||||
|
return incont = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < NELEMS(files); i++) {
|
||||||
|
if (!access(files[i], F_OK))
|
||||||
|
return incont = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct fstab *getfsent(void)
|
|
||||||
{
|
|
||||||
static struct fstab fs;
|
|
||||||
|
|
||||||
fs.fs_spec = lftok(fstab);
|
|
||||||
if (fs.fs_spec == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
fs.fs_file = lftok(fstab);
|
|
||||||
fs.fs_vfstype = lftok(fstab);
|
|
||||||
fs.fs_mntops = lftok(fstab);
|
|
||||||
fs.fs_type = "rw";
|
|
||||||
fs.fs_freq = atoi(lftok(fstab) ?: "0");
|
|
||||||
fs.fs_passno = atoi(lftok(fstab) ?: "0");
|
|
||||||
|
|
||||||
return &fs;
|
|
||||||
}
|
|
||||||
|
|
||||||
void endfsent(void)
|
|
||||||
{
|
|
||||||
if (fstab)
|
|
||||||
lfclose(fstab);
|
|
||||||
|
|
||||||
fstab = NULL;
|
|
||||||
}
|
|
||||||
#endif /* HAVE_GETFSENT */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
|
|||||||
+103
-27
@@ -1,7 +1,7 @@
|
|||||||
/* Misc. utility functions and C-library extensions for finit and its plugins
|
/* Misc. utility functions and C-library extensions for finit and its plugins
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||||
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -25,10 +25,12 @@
|
|||||||
#ifndef FINIT_HELPERS_H_
|
#ifndef FINIT_HELPERS_H_
|
||||||
#define FINIT_HELPERS_H_
|
#define FINIT_HELPERS_H_
|
||||||
|
|
||||||
#include <mntent.h>
|
#include <ctype.h>
|
||||||
#include <sched.h> /* sched_yield() */
|
#include <fcntl.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
|
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
@@ -47,26 +49,11 @@ typedef enum {
|
|||||||
PROGRESS_MODERN,
|
PROGRESS_MODERN,
|
||||||
} pstyle_t;
|
} pstyle_t;
|
||||||
|
|
||||||
#ifndef HAVE_GETFSENT
|
|
||||||
struct fstab {
|
|
||||||
char *fs_spec; /* block device name */
|
|
||||||
char *fs_file; /* mount point */
|
|
||||||
char *fs_vfstype; /* file-system type */
|
|
||||||
char *fs_mntops; /* mount options */
|
|
||||||
const char *fs_type; /* rw/rq/ro/sw/xx option */
|
|
||||||
int fs_freq; /* dump frequency, in days */
|
|
||||||
int fs_passno; /* pass number on parallel dump */
|
|
||||||
};
|
|
||||||
|
|
||||||
int setfsent (void);
|
|
||||||
void endfsent (void);
|
|
||||||
struct fstab *getfsent (void);
|
|
||||||
#endif /* HAVE_GETFSENT */
|
|
||||||
|
|
||||||
char *console (void);
|
char *console (void);
|
||||||
void console_init (void);
|
void console_init (void);
|
||||||
ssize_t cprintf (const char *fmt, ...);
|
ssize_t cprintf (const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
||||||
|
|
||||||
|
void tabstospaces (char *line);
|
||||||
char *strip_line (char *line);
|
char *strip_line (char *line);
|
||||||
|
|
||||||
void enable_progress (int onoff);
|
void enable_progress (int onoff);
|
||||||
@@ -79,7 +66,7 @@ void stty (int fd, speed_t speed);
|
|||||||
|
|
||||||
void print_banner (const char *heading);
|
void print_banner (const char *heading);
|
||||||
void printv (const char *fmt, va_list ap);
|
void printv (const char *fmt, va_list ap);
|
||||||
void print (int action, const char *fmt, ...);
|
void print (int action, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
void print_desc (char *action, char *desc);
|
void print_desc (char *action, char *desc);
|
||||||
int print_result (int fail);
|
int print_result (int fail);
|
||||||
|
|
||||||
@@ -93,19 +80,62 @@ int mksubsys (const char *dir, mode_t mode, char *user, char *group);
|
|||||||
|
|
||||||
void set_hostname (char **hostname);
|
void set_hostname (char **hostname);
|
||||||
void networking (int updown);
|
void networking (int updown);
|
||||||
|
int in_container (void);
|
||||||
|
|
||||||
int complete (char *cmd, int pid);
|
int complete (char *cmd, int pid);
|
||||||
int run (char *cmd);
|
int run (char *cmd, char *log);
|
||||||
int run_interactive (char *cmd, char *fmt, ...);
|
int run_interactive (char *cmd, char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
int exec_runtask (char *cmd, char *args[]);
|
int exec_runtask (char *cmd, char *args[]);
|
||||||
pid_t run_getty (char *tty, char *cmd, char *args[], int noclear, int nowait, struct rlimit rlimit[]);
|
pid_t run_getty (char *tty, char *cmd, char *args[], int noclear, int nowait, struct rlimit rlimit[]);
|
||||||
pid_t run_sh (char *tty, int noclear, int nowait, struct rlimit rlimit[]);
|
pid_t run_sh (char *tty, int noclear, int nowait, struct rlimit rlimit[]);
|
||||||
int run_parts (char *dir, char *cmd);
|
pid_t run_bg (char *cmd, char *args[]);
|
||||||
|
int run_parts (char *dir, char *cmd, const char *env[], int progress, int sysv);
|
||||||
|
|
||||||
static inline int create(char *path, mode_t mode, uid_t uid, gid_t gid)
|
/*
|
||||||
|
* Defaults to user "root" and group "wheel" (root) if:
|
||||||
|
* 1) the user is missing
|
||||||
|
* 2) the group or the file /etc/group is missing
|
||||||
|
*/
|
||||||
|
static inline int create(char *path, mode_t mode, char *user, char *group)
|
||||||
{
|
{
|
||||||
if (touch(path) || chmod(path, mode) || chown(path, uid, gid)) {
|
int fd, uid, gid;
|
||||||
_w("Failed creating %s properly.", path);
|
|
||||||
|
if (!path) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uid = getuser(user, NULL);
|
||||||
|
if (uid < 0)
|
||||||
|
uid = 0;
|
||||||
|
gid = getgroup(group);
|
||||||
|
if (gid < 0)
|
||||||
|
gid = 0;
|
||||||
|
|
||||||
|
fd = creat(path, mode);
|
||||||
|
if (fd == -1) {
|
||||||
|
warn("Failed creating %s properly", path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
if (chown(path, uid, gid)) {
|
||||||
|
warn("Failed chowning %s properly", path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int ln(const char *target, const char *linkpath)
|
||||||
|
{
|
||||||
|
if (!target || !linkpath) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symlink(target, linkpath)) {
|
||||||
|
if (errno != EEXIST)
|
||||||
|
warn("Failed creating %s -> %s symlink", target, linkpath);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,6 +160,52 @@ static inline int dprint(int fd, const char *s, size_t len)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline char *fgetval(const char *line, const char *key, char *sep)
|
||||||
|
{
|
||||||
|
char *ptr, *str, *copy;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
str = copy = strdup(line);
|
||||||
|
if (!copy)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ptr = strsep(&str, sep);
|
||||||
|
if (ptr && strcmp(ptr, key)) {
|
||||||
|
fail:
|
||||||
|
free(copy);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if we should strip optional separator, e.g.,
|
||||||
|
* 'foo = bar' => '= bar' should be stripped to 'bar'
|
||||||
|
*/
|
||||||
|
while (str && strchr(sep, str[0])) {
|
||||||
|
ptr = strsep(&str, sep);
|
||||||
|
if (!ptr)
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
ptr = str;
|
||||||
|
|
||||||
|
if (*ptr == '"' || *ptr == '\'') {
|
||||||
|
char *end = &ptr[strlen(ptr) - 1];
|
||||||
|
char q = *ptr;
|
||||||
|
|
||||||
|
while (end > ptr && isspace(*end))
|
||||||
|
*end-- = 0;
|
||||||
|
|
||||||
|
if (*end == q) {
|
||||||
|
*end = 0;
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
len = strlen(ptr) + 1;
|
||||||
|
memmove(copy, ptr, len);
|
||||||
|
|
||||||
|
return realloc(copy, len);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* FINIT_HELPERS_H_ */
|
#endif /* FINIT_HELPERS_H_ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+665
-186
File diff suppressed because it is too large
Load Diff
+15
-2
@@ -1,6 +1,6 @@
|
|||||||
/* New client tool, replaces old /dev/initctl API and telinit tool
|
/* New client tool, replaces old /dev/initctl API and telinit tool
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2015-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* 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,17 +24,30 @@
|
|||||||
#ifndef FINIT_INITCTL_H_
|
#ifndef FINIT_INITCTL_H_
|
||||||
#define FINIT_INITCTL_H_
|
#define FINIT_INITCTL_H_
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
extern char *finit_conf;
|
||||||
|
extern char *finit_rcsd;
|
||||||
|
|
||||||
extern int icreate; /* initctl -c */
|
extern int icreate; /* initctl -c */
|
||||||
extern int iforce; /* initctl -f */
|
extern int iforce; /* initctl -f */
|
||||||
extern int ionce; /* initctl -1 */
|
extern int ionce; /* initctl -1 */
|
||||||
extern int heading; /* initctl -t */
|
extern int heading; /* initctl -t */
|
||||||
|
extern int json; /* initctl -j */
|
||||||
|
extern int noerr; /* initctl -n */
|
||||||
extern int verbose; /* initctl -v */
|
extern int verbose; /* initctl -v */
|
||||||
extern int plain; /* initctl -p */
|
extern int plain; /* initctl -p */
|
||||||
|
extern int quiet; /* initctl -q */
|
||||||
|
|
||||||
extern void print_header(const char *fmt, ...);
|
#define ERR(rc, fmt, args...) do { if (!quiet) err(rc, fmt, ##args); else exit(rc); } while (0)
|
||||||
|
#define ERRX(rc, fmt, args...) do { if (!quiet) errx(rc, fmt, ##args); else exit(rc); } while (0)
|
||||||
|
#define WARN(fmt, args...) do { if (!quiet) warn(fmt, ##args); } while (0)
|
||||||
|
#define WARNX(fmt, args...) do { if (!quiet) warnx(fmt, ##args); } while (0)
|
||||||
|
|
||||||
|
extern void print_header(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
||||||
|
|
||||||
#endif /* FINIT_INITCTL_H_ */
|
#endif /* FINIT_INITCTL_H_ */
|
||||||
|
|
||||||
|
|||||||
+38
-11
@@ -1,7 +1,7 @@
|
|||||||
/* inotify watcher for files or directories
|
/* inotify watcher for files or directories
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
|
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
|
||||||
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2016-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* 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,6 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "iwatch.h"
|
#include "iwatch.h"
|
||||||
@@ -39,6 +40,9 @@ static int initialized = 0;
|
|||||||
|
|
||||||
int iwatch_init(struct iwatch *iw)
|
int iwatch_init(struct iwatch *iw)
|
||||||
{
|
{
|
||||||
|
socklen_t len;
|
||||||
|
int sz;
|
||||||
|
|
||||||
if (!iw) {
|
if (!iw) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -48,9 +52,21 @@ int iwatch_init(struct iwatch *iw)
|
|||||||
|
|
||||||
iw->fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
iw->fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
||||||
if (iw->fd < 0) {
|
if (iw->fd < 0) {
|
||||||
_pe("Failed creating inotify descriptor");
|
warn("Failed creating inotify descriptor");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Double the size of the socket's receive buffer to address
|
||||||
|
* issues with lost events in some cases, e.g. bootstrap and
|
||||||
|
* reconf of systems with lots of services.
|
||||||
|
*/
|
||||||
|
len = sizeof(sz);
|
||||||
|
if (!getsockopt(iw->fd, SOL_SOCKET, SO_RCVBUF, &sz, &len)) {
|
||||||
|
if (setsockopt(iw->fd, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)))
|
||||||
|
warn("Failed increasing size of inotify socket");
|
||||||
|
}
|
||||||
|
|
||||||
initialized = 1;
|
initialized = 1;
|
||||||
|
|
||||||
return iw->fd;
|
return iw->fd;
|
||||||
@@ -71,7 +87,7 @@ void iwatch_exit(struct iwatch *iw)
|
|||||||
initialized = 0;
|
initialized = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int iwatch_add(struct iwatch *iw, char *file, uint32_t mask)
|
int iwatch_add1(struct iwatch *iw, char *file, uint32_t mask)
|
||||||
{
|
{
|
||||||
struct iwatch_path *iwp;
|
struct iwatch_path *iwp;
|
||||||
char *path;
|
char *path;
|
||||||
@@ -80,19 +96,25 @@ int iwatch_add(struct iwatch *iw, char *file, uint32_t mask)
|
|||||||
if (!initialized)
|
if (!initialized)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (!fexist(file)) {
|
iwp = iwatch_find_by_path(iw, file);
|
||||||
_d("skipping %s: no such file or directory", file);
|
if (iwp) {
|
||||||
|
dbg("skipping, %s already registered", file);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
_d("adding new watcher for path %s", file);
|
|
||||||
|
if (!fexist(file)) {
|
||||||
|
dbg("skipping %s: no such file or directory", file);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
dbg("adding new watcher for path %s", file);
|
||||||
|
|
||||||
path = strdup(file);
|
path = strdup(file);
|
||||||
if (!path) {
|
if (!path) {
|
||||||
_pe("Out of memory");
|
warn("Out of memory");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
wd = inotify_add_watch(iw->fd, path, IWATCH_MASK | mask);
|
wd = inotify_add_watch(iw->fd, path, mask);
|
||||||
if (wd < 0) {
|
if (wd < 0) {
|
||||||
switch (errno) {
|
switch (errno) {
|
||||||
case EEXIST:
|
case EEXIST:
|
||||||
@@ -108,7 +130,7 @@ int iwatch_add(struct iwatch *iw, char *file, uint32_t mask)
|
|||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_pe("Failed adding watcher for %s", path);
|
warn("Failed adding watcher for %s", path);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +140,7 @@ int iwatch_add(struct iwatch *iw, char *file, uint32_t mask)
|
|||||||
|
|
||||||
iwp = malloc(sizeof(struct iwatch_path));
|
iwp = malloc(sizeof(struct iwatch_path));
|
||||||
if (!iwp) {
|
if (!iwp) {
|
||||||
_pe("Failed allocating new `struct iwatch_path`");
|
warn("Failed allocating new `struct iwatch_path`");
|
||||||
inotify_rm_watch(iw->fd, wd);
|
inotify_rm_watch(iw->fd, wd);
|
||||||
free(path);
|
free(path);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -131,12 +153,17 @@ int iwatch_add(struct iwatch *iw, char *file, uint32_t mask)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int iwatch_add(struct iwatch *iw, char *file, uint32_t mask)
|
||||||
|
{
|
||||||
|
return iwatch_add1(iw, file, IWATCH_MASK | mask);
|
||||||
|
}
|
||||||
|
|
||||||
int iwatch_del(struct iwatch *iw, struct iwatch_path *iwp)
|
int iwatch_del(struct iwatch *iw, struct iwatch_path *iwp)
|
||||||
{
|
{
|
||||||
if (!initialized)
|
if (!initialized)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
_d("Removing watcher for removed path %s", iwp->path);
|
dbg("Removing watcher for removed path %s", iwp->path);
|
||||||
|
|
||||||
TAILQ_REMOVE(&iw->iwp_list, iwp, link);
|
TAILQ_REMOVE(&iw->iwp_list, iwp, link);
|
||||||
inotify_rm_watch(iw->fd, iwp->wd);
|
inotify_rm_watch(iw->fd, iwp->wd);
|
||||||
|
|||||||
+2
-1
@@ -1,7 +1,7 @@
|
|||||||
/* inotify watcher for files or directories
|
/* inotify watcher for files or directories
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
|
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
|
||||||
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2016-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -59,6 +59,7 @@ struct iwatch {
|
|||||||
int iwatch_init (struct iwatch *iw);
|
int iwatch_init (struct iwatch *iw);
|
||||||
void iwatch_exit (struct iwatch *iw);
|
void iwatch_exit (struct iwatch *iw);
|
||||||
|
|
||||||
|
int iwatch_add1 (struct iwatch *iw, char *file, uint32_t mask);
|
||||||
int iwatch_add (struct iwatch *iw, char *file, uint32_t mask);
|
int iwatch_add (struct iwatch *iw, char *file, uint32_t mask);
|
||||||
int iwatch_del (struct iwatch *iw, struct iwatch_path *iwp);
|
int iwatch_del (struct iwatch *iw, struct iwatch_path *iwp);
|
||||||
|
|
||||||
|
|||||||
+43
-7
@@ -1,6 +1,6 @@
|
|||||||
/* Listens to kernel events like AC power status and manages sys/ conditions
|
/* Listens to kernel events like AC power status and manages sys/ conditions
|
||||||
*
|
*
|
||||||
* Copyright (c) 2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2021-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* 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,6 +24,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
@@ -52,6 +53,10 @@
|
|||||||
static int num_ac_online;
|
static int num_ac_online;
|
||||||
static int num_ac;
|
static int num_ac;
|
||||||
|
|
||||||
|
static int running = 1;
|
||||||
|
static int level;
|
||||||
|
static int logon;
|
||||||
|
|
||||||
int debug; /* debug in other modules as well */
|
int debug; /* debug in other modules as well */
|
||||||
|
|
||||||
void logit(int prio, const char *fmt, ...)
|
void logit(int prio, const char *fmt, ...)
|
||||||
@@ -59,9 +64,9 @@ void logit(int prio, const char *fmt, ...)
|
|||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
if (!debug)
|
if (logon)
|
||||||
vsyslog(prio, fmt, ap);
|
vsyslog(prio, fmt, ap);
|
||||||
else {
|
else if (prio <= level) {
|
||||||
vfprintf(stderr, fmt, ap);
|
vfprintf(stderr, fmt, ap);
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
}
|
}
|
||||||
@@ -147,7 +152,7 @@ static void init(void)
|
|||||||
|
|
||||||
for (i = 0; i < (int)NELEMS(cond_dirs); i++) {
|
for (i = 0; i < (int)NELEMS(cond_dirs); i++) {
|
||||||
if (mkpath(cond_dirs[i], 0755) && errno != EEXIST) {
|
if (mkpath(cond_dirs[i], 0755) && errno != EEXIST) {
|
||||||
_pe("Failed creating %s condition directory, %s", COND_SYS,
|
warn("Failed creating %s condition directory, %s", COND_SYS,
|
||||||
cond_dirs[i]);
|
cond_dirs[i]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -179,6 +184,26 @@ static void init(void)
|
|||||||
sys_cond("pwr/ac", 1);
|
sys_cond("pwr/ac", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void set_logging(int prio)
|
||||||
|
{
|
||||||
|
setlogmask(LOG_UPTO(prio));
|
||||||
|
level = prio;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void toggle_debug(int signo)
|
||||||
|
{
|
||||||
|
(void)signo;
|
||||||
|
|
||||||
|
debug ^= 1;
|
||||||
|
set_logging(debug ? LOG_DEBUG : LOG_NOTICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void shut_down(int signo)
|
||||||
|
{
|
||||||
|
(void)signo;
|
||||||
|
running = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Started by Finit as soon as possible when base filesystem is up,
|
* Started by Finit as soon as possible when base filesystem is up,
|
||||||
* modules have been probed, or insmodded from /etc/finit.conf, so by
|
* modules have been probed, or insmodded from /etc/finit.conf, so by
|
||||||
@@ -198,10 +223,13 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!debug) {
|
if (!debug) {
|
||||||
openlog("keventd", LOG_CONS | LOG_PID, LOG_DAEMON);
|
openlog("keventd", LOG_PID, LOG_DAEMON);
|
||||||
setlogmask(LOG_UPTO(LOG_NOTICE));
|
set_logging(LOG_NOTICE);
|
||||||
|
logon = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signal(SIGUSR1, toggle_debug);
|
||||||
|
signal(SIGTERM, shut_down);
|
||||||
init();
|
init();
|
||||||
|
|
||||||
pfd.events = POLLIN;
|
pfd.events = POLLIN;
|
||||||
@@ -216,11 +244,18 @@ int main(int argc, char *argv[])
|
|||||||
panic("bind failed");
|
panic("bind failed");
|
||||||
|
|
||||||
logit(LOG_DEBUG, "Waiting for events ...");
|
logit(LOG_DEBUG, "Waiting for events ...");
|
||||||
while (-1 != poll(&pfd, 1, -1)) {
|
while (running) {
|
||||||
char *path = NULL;
|
char *path = NULL;
|
||||||
int ac = 0;
|
int ac = 0;
|
||||||
int i, len;
|
int i, len;
|
||||||
|
|
||||||
|
if (-1 == poll(&pfd, 1, -1)) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
len = recv(pfd.fd, buf, sizeof(buf), MSG_DONTWAIT);
|
len = recv(pfd.fd, buf, sizeof(buf), MSG_DONTWAIT);
|
||||||
if (len == -1) {
|
if (len == -1) {
|
||||||
switch (errno) {
|
switch (errno) {
|
||||||
@@ -235,6 +270,7 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf[len] = 0;
|
buf[len] = 0;
|
||||||
|
logit(LOG_DEBUG, "%s", buf);
|
||||||
|
|
||||||
/* skip libusb events, focus on kernel events/changes */
|
/* skip libusb events, focus on kernel events/changes */
|
||||||
if (strncmp(buf, "change@", 7))
|
if (strncmp(buf, "change@", 7))
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* Finit daemon log functions
|
/* Finit daemon log functions
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* 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,9 +21,11 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h" /* Generated by configure script */
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <time.h>
|
||||||
#ifdef _LIBITE_LITE
|
#ifdef _LIBITE_LITE
|
||||||
# include <libite/lite.h>
|
# include <libite/lite.h>
|
||||||
#else
|
#else
|
||||||
@@ -49,28 +51,32 @@ void log_init(void)
|
|||||||
/* If we enabled terse mode at boot, restore to previous setting at shutdown */
|
/* If we enabled terse mode at boot, restore to previous setting at shutdown */
|
||||||
void log_exit(void)
|
void log_exit(void)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* Unless in debug mode at shutdown, Reinitialize screen,
|
|
||||||
* terminal may have been resized at runtime
|
|
||||||
*/
|
|
||||||
if (!debug)
|
|
||||||
ttinit();
|
|
||||||
|
|
||||||
enable_progress(1);
|
enable_progress(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void log_open(void)
|
static int log_open(void)
|
||||||
{
|
{
|
||||||
int opts = LOG_PID;
|
int opts;
|
||||||
|
|
||||||
closelog();
|
if (up)
|
||||||
|
return 1;
|
||||||
|
if (access("/dev/log", W_OK))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
opts = LOG_CONS | LOG_PID;
|
||||||
if (debug)
|
if (debug)
|
||||||
opts |= LOG_PERROR; /* LOG_CONS | */
|
opts |= LOG_PERROR;
|
||||||
|
|
||||||
openlog("finit", opts, LOG_DAEMON);
|
openlog("finit", opts, LOG_DAEMON);
|
||||||
setlogmask(LOG_UPTO(loglevel));
|
setlogmask(LOG_UPTO(loglevel));
|
||||||
|
|
||||||
up = 1;
|
return up = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void log_close(void)
|
||||||
|
{
|
||||||
|
closelog();
|
||||||
|
up = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Toggle debug mode */
|
/* Toggle debug mode */
|
||||||
@@ -78,32 +84,40 @@ void log_debug(void)
|
|||||||
{
|
{
|
||||||
debug = !debug;
|
debug = !debug;
|
||||||
|
|
||||||
if (debug) {
|
log_close();
|
||||||
loglevel = LOG_DEBUG;
|
log_init();
|
||||||
} else {
|
|
||||||
loglevel = LOG_NOTICE;
|
|
||||||
ttinit();
|
|
||||||
}
|
|
||||||
log_open();
|
log_open();
|
||||||
|
|
||||||
logit(LOG_NOTICE, "Debug mode %s", debug ? "enabled" : "disabled");
|
logit(LOG_NOTICE, "Debug mode %s", debug ? "enabled" : "disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *l2s(int prio)
|
||||||
|
{
|
||||||
|
int level = prio & ~LOG_CONSOLE;
|
||||||
|
|
||||||
|
switch (level) {
|
||||||
|
case LOG_ERR: return "ERR";
|
||||||
|
case LOG_WARNING: return "WRN";
|
||||||
|
case LOG_NOTICE: return "NOT";
|
||||||
|
case LOG_INFO: return "NFO";
|
||||||
|
case LOG_DEBUG: return "DBG";
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return "UNK";
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Log to /dev/kmsg until syslogd has started, then openlog()
|
* Log to /dev/kmsg until syslogd has started, then openlog()
|
||||||
* and continue logging as a regular daemon.
|
* and continue logging as a regular daemon.
|
||||||
*/
|
*/
|
||||||
void logit(int prio, const char *fmt, ...)
|
void logit(int prio, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
|
|
||||||
if (up || fexist("/dev/log")) {
|
if (up || log_open()) {
|
||||||
if (!up)
|
|
||||||
log_open();
|
|
||||||
|
|
||||||
vsyslog(prio, fmt, ap);
|
vsyslog(prio, fmt, ap);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@@ -111,13 +125,21 @@ void logit(int prio, const char *fmt, ...)
|
|||||||
if (LOG_PRI(prio) > loglevel)
|
if (LOG_PRI(prio) > loglevel)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
fp = fopen("/dev/kmsg", "w");
|
if (in_container() || !(fp = fopen("/dev/kmsg", "w"))) {
|
||||||
if (!fp) {
|
static char buf[512];
|
||||||
vfprintf(stderr, fmt, ap);
|
time_t now;
|
||||||
|
size_t pos;
|
||||||
|
|
||||||
|
now = time(NULL);
|
||||||
|
pos = (int)strftime(buf, sizeof(buf), "%FT%T", localtime(&now));
|
||||||
|
pos += snprintf(&buf[pos], sizeof(buf) - pos, " [%s]: ", l2s(prio));
|
||||||
|
vsnprintf(&buf[pos], sizeof(buf) - pos, fmt, ap);
|
||||||
|
strlcat(buf, "\n", sizeof(buf));
|
||||||
|
fputs(buf, stderr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(fp, "<%d>finit[1]:", LOG_DAEMON | prio);
|
fprintf(fp, "<%d>finit[1]: ", LOG_DAEMON | prio);
|
||||||
vfprintf(fp, fmt, ap);
|
vfprintf(fp, fmt, ap);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
@@ -125,6 +147,7 @@ void logit(int prio, const char *fmt, ...)
|
|||||||
va_end(ap);
|
va_end(ap);
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
vfprintf(stderr, fmt, ap);
|
vfprintf(stderr, fmt, ap);
|
||||||
|
fputs("\n", stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* Finit daemon log functions
|
/* Finit daemon log functions
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -31,26 +31,56 @@
|
|||||||
#define LOG_CONSOLE (14<<3)
|
#define LOG_CONSOLE (14<<3)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef __FINIT__
|
||||||
|
#include <err.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
extern int debug;
|
||||||
|
|
||||||
|
static __attribute__ ((format (printf, 1, 2))) inline void dbg(char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
if (!debug)
|
||||||
|
return;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
fputs("\n", stderr);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
#define info(fmt, args...) warnx(fmt, ##args)
|
||||||
|
#define note(fmt, args...) warnx(fmt, ##args)
|
||||||
|
#else
|
||||||
/*
|
/*
|
||||||
* Developer error and debug messages, otherwise --> use logit() <--
|
* General log macros, similar to those used by initctl. Initially intended
|
||||||
* ~~~~~~~~~~~
|
* only for bridging client.c in Finit and initctl.
|
||||||
* All of these prepend the function, so only use for critical warnings
|
|
||||||
* errors and debug messages. For all other user messages, see logit()
|
|
||||||
*
|
|
||||||
* The default log level is LOG_NOTICE. To toggle LOG_DEBUG messages,
|
|
||||||
* use `initctl debug` or add `debug` to the kernel cmdline.
|
|
||||||
*/
|
*/
|
||||||
#define _d(fmt, args...) logit(LOG_DEBUG, "%s():" fmt "\n", __func__, ##args)
|
#define dbg(fmt, args...) logit(LOG_DEBUG, "%s():" fmt, __func__, ##args)
|
||||||
#define _w(fmt, args...) logit(LOG_WARNING, "%s():" fmt "\n", __func__, ##args)
|
#define info(fmt, args...) logit(LOG_INFO, "%s():" fmt, __func__, ##args)
|
||||||
#define _e(fmt, args...) logit(LOG_ERR, "%s():" fmt "\n", __func__, ##args)
|
#define note(fmt, args...) logit(LOG_NOTICE, "%s():" fmt, __func__, ##args)
|
||||||
#define _pe(fmt, args...) logit(LOG_ERR, "%s():" fmt ": %s\n", __func__, ##args, strerror(errno))
|
#define warnx(fmt, args...) logit(LOG_WARNING, "%s():" fmt, __func__, ##args)
|
||||||
|
#define warn(fmt, args...) logit(LOG_WARNING, "%s():" fmt ": %s", __func__, ##args, strerror(errno))
|
||||||
|
#define errx(rc, fmt, args...) logit(LOG_ERR, "%s():" fmt, __func__, ##args)
|
||||||
|
#define err(rc, fmt, args...) logit(LOG_ERR, "%s():" fmt ": %s", __func__, ##args, strerror(errno))
|
||||||
|
|
||||||
void log_init (void);
|
/*
|
||||||
void log_exit (void);
|
* DEPRECATED developer error and debug messages, please migrate to above!
|
||||||
|
* Will be removed without further warning in a future Finit release.
|
||||||
|
*/
|
||||||
|
#define _d(fmt, args...) logit(LOG_DEBUG, "%s():" fmt, __func__, ##args)
|
||||||
|
#define _w(fmt, args...) logit(LOG_WARNING, "%s():" fmt, __func__, ##args)
|
||||||
|
#define _e(fmt, args...) logit(LOG_ERR, "%s():" fmt, __func__, ##args)
|
||||||
|
#define _pe(fmt, args...) logit(LOG_ERR, "%s():" fmt ": %s", __func__, ##args, strerror(errno))
|
||||||
|
|
||||||
void log_debug (void);
|
void log_init (void);
|
||||||
|
void log_exit (void);
|
||||||
|
|
||||||
void logit (int prio, const char *fmt, ...);
|
void log_debug(void);
|
||||||
void flog (char *file, const char *fmt, ...);
|
|
||||||
|
void logit (int prio, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
|
void flog (char *file, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* FINIT_LOG_H_ */
|
#endif /* FINIT_LOG_H_ */
|
||||||
|
|||||||
+8
-3
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2018-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -208,8 +208,13 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ident)
|
if (!ident) {
|
||||||
ident = getenv("LOGNAME") ?: getenv("USER");
|
ident = getenv("LOGNAME");
|
||||||
|
if (!ident)
|
||||||
|
ident = getenv("USER");
|
||||||
|
if (!ident)
|
||||||
|
ident = PACKAGE_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
if (optind < argc) {
|
if (optind < argc) {
|
||||||
size_t pos = 0, len = sizeof(buf);
|
size_t pos = 0, len = sizeof(buf);
|
||||||
|
|||||||
+3
-4
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2018-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -49,7 +49,6 @@ static int recreate(char *path, mode_t mode, uid_t uid, gid_t gid)
|
|||||||
*/
|
*/
|
||||||
int logrotate(char *file, int num, off_t sz)
|
int logrotate(char *file, int num, off_t sz)
|
||||||
{
|
{
|
||||||
int cnt;
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if (stat(file, &st))
|
if (stat(file, &st))
|
||||||
@@ -60,6 +59,7 @@ int logrotate(char *file, int num, off_t sz)
|
|||||||
size_t len = strlen(file) + 10 + 1;
|
size_t len = strlen(file) + 10 + 1;
|
||||||
char ofile[len];
|
char ofile[len];
|
||||||
char nfile[len];
|
char nfile[len];
|
||||||
|
int cnt;
|
||||||
|
|
||||||
/* First age zipped log files */
|
/* First age zipped log files */
|
||||||
for (cnt = num; cnt > 2; cnt--) {
|
for (cnt = num; cnt > 2; cnt--) {
|
||||||
@@ -97,8 +97,7 @@ int logrotate(char *file, int num, off_t sz)
|
|||||||
} else {
|
} else {
|
||||||
fallback:
|
fallback:
|
||||||
if (truncate(file, 0))
|
if (truncate(file, 0))
|
||||||
syslog(LOG_ERR, "Failed truncating %s during logrotate: %s",
|
syslog(LOG_ERR, "Failed truncating %s: %s", file, strerror(errno));
|
||||||
file, strerror(errno));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
-6
@@ -1,6 +1,6 @@
|
|||||||
/* Handle MD arrays
|
/* Handle MD arrays
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2016-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* 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,11 +21,14 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h" /* Generated by configure script */
|
||||||
|
|
||||||
#include <glob.h>
|
#include <glob.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
|
||||||
static glob_t *get_arrays(void)
|
static glob_t *get_arrays(void)
|
||||||
@@ -46,17 +49,18 @@ static glob_t *get_arrays(void)
|
|||||||
*/
|
*/
|
||||||
void mdadm_wait(void)
|
void mdadm_wait(void)
|
||||||
{
|
{
|
||||||
size_t i;
|
|
||||||
glob_t *gl;
|
glob_t *gl;
|
||||||
char cmd[160];
|
|
||||||
|
|
||||||
/* Setup kernel specific settings, e.g. allow broadcast ping, etc. */
|
/* Setup kernel specific settings, e.g. allow broadcast ping, etc. */
|
||||||
gl = get_arrays();
|
gl = get_arrays();
|
||||||
if (gl) {
|
if (gl) {
|
||||||
for (i = 0; i < gl->gl_pathc; i++) {
|
size_t i;
|
||||||
char *array;
|
|
||||||
|
|
||||||
array = basename(gl->gl_pathv[i]);
|
for (i = 0; i < gl->gl_pathc; i++) {
|
||||||
|
const char *array;
|
||||||
|
char cmd[160];
|
||||||
|
|
||||||
|
array = basenm(gl->gl_pathv[i]);
|
||||||
snprintf(cmd, sizeof(cmd), "mdadm --wait-clean /dev/%s >/dev/null", array);
|
snprintf(cmd, sizeof(cmd), "mdadm --wait-clean /dev/%s >/dev/null", array);
|
||||||
run_interactive(cmd, "Marking MD array %s as clean", array);
|
run_interactive(cmd, "Marking MD array %s as clean", array);
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-6
@@ -1,6 +1,6 @@
|
|||||||
/* Mount and unmount helpers
|
/* Mount and unmount helpers
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2016-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* 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,10 +21,17 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h" /* Generated by configure script */
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#ifdef HAVE_MNTENT_H
|
||||||
#include <mntent.h>
|
#include <mntent.h>
|
||||||
|
#endif
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
|
|
||||||
|
#include "helpers.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SysV init on Debian/Ubuntu skips these protected mount points
|
* SysV init on Debian/Ubuntu skips these protected mount points
|
||||||
*
|
*
|
||||||
@@ -65,12 +72,12 @@ static void iterator_end(FILE **fp)
|
|||||||
*fp = NULL;
|
*fp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct mntent *iterator(char *fstab, FILE **fp)
|
static struct mntent *iterator(char *filename, FILE **fp)
|
||||||
{
|
{
|
||||||
static struct mntent *mnt;
|
static struct mntent *mnt;
|
||||||
|
|
||||||
if (!*fp && fstab) {
|
if (!*fp && filename) {
|
||||||
*fp = setmntent(fstab, "r");
|
*fp = setmntent(filename, "r");
|
||||||
if (!*fp)
|
if (!*fp)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -86,13 +93,29 @@ static struct mntent *iterator(char *fstab, FILE **fp)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int unmount(const char *target)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
dbg("Unmounting %s", target);
|
||||||
|
|
||||||
|
rc = umount(target);
|
||||||
|
if (rc) {
|
||||||
|
if (errno != EBUSY)
|
||||||
|
print(2, "Failed unmounting %s, error %d: %s", target, errno, strerror(errno));
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void unmount_tmpfs(void)
|
void unmount_tmpfs(void)
|
||||||
{
|
{
|
||||||
struct mntent *mnt;
|
struct mntent *mnt;
|
||||||
FILE *fp = NULL;
|
FILE *fp = NULL;
|
||||||
|
|
||||||
while ((mnt = iterator("/proc/mounts", &fp))) {
|
while ((mnt = iterator("/proc/mounts", &fp))) {
|
||||||
if (!strcmp("tmpfs", mnt->mnt_fsname) && !umount(mnt->mnt_dir))
|
if (!strcmp("tmpfs", mnt->mnt_fsname) && !unmount(mnt->mnt_dir))
|
||||||
iterator_end(&fp); /* Restart iteration */
|
iterator_end(&fp); /* Restart iteration */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,7 +126,7 @@ void unmount_regular(void)
|
|||||||
FILE *fp = NULL;
|
FILE *fp = NULL;
|
||||||
|
|
||||||
while ((mnt = iterator("/proc/mounts", &fp))) {
|
while ((mnt = iterator("/proc/mounts", &fp))) {
|
||||||
if (!umount(mnt->mnt_dir))
|
if (!unmount(mnt->mnt_dir))
|
||||||
iterator_end(&fp); /* Restart iteration */
|
iterator_end(&fp); /* Restart iteration */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* PID and PID file helpers
|
/* PID and PID file helpers
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||||
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* 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,6 +22,8 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h" /* Generated by configure script */
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -69,10 +71,11 @@ int pid_alive(pid_t pid)
|
|||||||
*/
|
*/
|
||||||
char *pid_get_name(pid_t pid, char *name, size_t len)
|
char *pid_get_name(pid_t pid, char *name, size_t len)
|
||||||
{
|
{
|
||||||
|
static char line[64];
|
||||||
|
char *pname = NULL;
|
||||||
|
char path[32];
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
char *pname, path[32];
|
|
||||||
static char line[64];
|
|
||||||
|
|
||||||
snprintf(path, sizeof(path), "/proc/%d/status", pid);
|
snprintf(path, sizeof(path), "/proc/%d/status", pid);
|
||||||
fp = fopen(path, "r");
|
fp = fopen(path, "r");
|
||||||
@@ -113,8 +116,8 @@ char *pid_file(svc_t *svc)
|
|||||||
pid_t pid_file_read(const char *fn)
|
pid_t pid_file_read(const char *fn)
|
||||||
{
|
{
|
||||||
pid_t pid = 0;
|
pid_t pid = 0;
|
||||||
FILE *fp;
|
|
||||||
char buf[42];
|
char buf[42];
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
fp = fopen(fn, "r");
|
fp = fopen(fn, "r");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
@@ -146,6 +149,8 @@ int pid_file_create(svc_t *svc)
|
|||||||
|
|
||||||
int pid_file_set(svc_t *svc, char *file, int not)
|
int pid_file_set(svc_t *svc, char *file, int not)
|
||||||
{
|
{
|
||||||
|
char buf[sizeof(svc->pidfile)];
|
||||||
|
|
||||||
if (!file) {
|
if (!file) {
|
||||||
file = pid_file(svc);
|
file = pid_file(svc);
|
||||||
if (!file)
|
if (!file)
|
||||||
@@ -157,7 +162,14 @@ int pid_file_set(svc_t *svc, char *file, int not)
|
|||||||
file++;
|
file++;
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_runpath(file, &svc->pidfile[not], sizeof(svc->pidfile) - not);
|
if (svc_is_forking(svc) && !not) {
|
||||||
|
logit(LOG_WARNING, "Service %s is forking, adjusting to pid:!%s", svc->name, file);
|
||||||
|
not = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
de_dotdot(file);
|
||||||
|
pid_runpath(file, buf, sizeof(buf));
|
||||||
|
strlcpy(&svc->pidfile[not], buf, sizeof(svc->pidfile) - not);
|
||||||
if (not)
|
if (not)
|
||||||
svc->pidfile[0] = '!';
|
svc->pidfile[0] = '!';
|
||||||
|
|
||||||
@@ -180,7 +192,7 @@ int pid_file_set(svc_t *svc, char *file, int not)
|
|||||||
* pid:foo.tla --> /run/foo.tla.pid
|
* pid:foo.tla --> /run/foo.tla.pid
|
||||||
* pid:/tmp/foo --> /tmp/foo.pid (Not handled by pidfile plugin!)
|
* pid:/tmp/foo --> /tmp/foo.pid (Not handled by pidfile plugin!)
|
||||||
*
|
*
|
||||||
* An exclamation mark, or logial NOT, in the first character position
|
* An exclamation mark, or logical NOT, in the first character position
|
||||||
* indicates that Finit should *not* manage the PID file, and that the
|
* indicates that Finit should *not* manage the PID file, and that the
|
||||||
* process uses a "non-standard" location. Eg. if service is 'bar'
|
* process uses a "non-standard" location. Eg. if service is 'bar'
|
||||||
* Finit would assume the PID file is /run/bar.pid and the below simply
|
* Finit would assume the PID file is /run/bar.pid and the below simply
|
||||||
@@ -199,8 +211,8 @@ int pid_file_parse(svc_t *svc, char *arg)
|
|||||||
|
|
||||||
/* 'pid:' implies argument following*/
|
/* 'pid:' implies argument following*/
|
||||||
if (!strncmp(arg, "pid:", 4)) {
|
if (!strncmp(arg, "pid:", 4)) {
|
||||||
int len, not = 0;
|
|
||||||
char path[MAX_ARG_LEN];
|
char path[MAX_ARG_LEN];
|
||||||
|
int len, not = 0;
|
||||||
|
|
||||||
arg += 4;
|
arg += 4;
|
||||||
if ((arg[0] == '!' && arg[1] == '/') || arg[0] == '/')
|
if ((arg[0] == '!' && arg[1] == '/') || arg[0] == '/')
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* PID and PID file helpers
|
/* PID and PID file helpers
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||||
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -51,6 +51,7 @@ static inline char *pid_runpath(const char *file, char *path, size_t len)
|
|||||||
{
|
{
|
||||||
static char *prefix = "/var/run";
|
static char *prefix = "/var/run";
|
||||||
static int unknown = 1;
|
static int unknown = 1;
|
||||||
|
char *ptr;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (unknown) {
|
if (unknown) {
|
||||||
@@ -59,14 +60,13 @@ static inline char *pid_runpath(const char *file, char *path, size_t len)
|
|||||||
unknown = 0;
|
unknown = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strncmp(file, "/var/run/", 9))
|
ptr = strstr(file, "/run/");
|
||||||
file += 9;
|
if (ptr)
|
||||||
else if (!strncmp(file, "/run/", 5))
|
file = ptr + 5;
|
||||||
file += 5;
|
|
||||||
|
|
||||||
rc = paste(path, len, prefix, file);
|
rc = paste(path, len, prefix, file);
|
||||||
if (rc < 0 || (size_t)rc >= len)
|
if (rc < 0 || (size_t)rc >= len)
|
||||||
_e("File path '%s' truncated, should end with '%s'", path, file);
|
err(1, "File path '%s' truncated, should end with '%s'", path, file);
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|||||||
+155
-33
@@ -1,6 +1,6 @@
|
|||||||
/* Plugin based services architecture for finit
|
/* Plugin based services architecture for finit
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2012-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* 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 <errno.h>
|
#include <errno.h>
|
||||||
#include <dlfcn.h> /* dlopen() et al */
|
#include <dlfcn.h> /* dlopen() et al */
|
||||||
#include <dirent.h> /* readdir() et al */
|
#include <dirent.h> /* readdir() et al */
|
||||||
@@ -34,13 +36,14 @@
|
|||||||
# include <lite/queue.h> /* BSD sys/queue.h API */
|
# include <lite/queue.h> /* BSD sys/queue.h API */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
#include "private.h"
|
#include "private.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
|
#include "sig.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
#define is_io_plugin(p) ((p)->io.cb && (p)->io.fd > 0)
|
#define is_io_plugin(p) ((p)->io.cb && (p)->io.fd > 0)
|
||||||
#define SEARCH_PLUGIN(str) \
|
#define SEARCH_PLUGIN(str) \
|
||||||
@@ -49,7 +52,8 @@
|
|||||||
return p; \
|
return p; \
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *plugpath = NULL; /* Set by first load. */
|
static int plugloaded = 0; /* Set while plugins are loaded */
|
||||||
|
static char *plugpath = NULL; /* Set by first load. */
|
||||||
static TAILQ_HEAD(plugin_head, plugin) plugins = TAILQ_HEAD_INITIALIZER(plugins);
|
static TAILQ_HEAD(plugin_head, plugin) plugins = TAILQ_HEAD_INITIALIZER(plugins);
|
||||||
|
|
||||||
#ifndef ENABLE_STATIC
|
#ifndef ENABLE_STATIC
|
||||||
@@ -74,27 +78,30 @@ static char *trim_ext(char *name)
|
|||||||
|
|
||||||
int plugin_register(plugin_t *plugin)
|
int plugin_register(plugin_t *plugin)
|
||||||
{
|
{
|
||||||
|
const char *nm;
|
||||||
|
|
||||||
if (!plugin) {
|
if (!plugin) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup default name if none is provided */
|
/* Setup default name if none is provided */
|
||||||
if (!plugin->name) {
|
nm = plugin->name;
|
||||||
|
if (!nm) {
|
||||||
#ifndef ENABLE_STATIC
|
#ifndef ENABLE_STATIC
|
||||||
Dl_info info;
|
Dl_info info;
|
||||||
|
|
||||||
if (dladdr(plugin, &info) && info.dli_fname)
|
if (dladdr(plugin, &info) && info.dli_fname)
|
||||||
plugin->name = basename(info.dli_fname);
|
nm = basenm(info.dli_fname);
|
||||||
#endif
|
#endif
|
||||||
if (!plugin->name)
|
if (!nm)
|
||||||
plugin->name = "unknown";
|
nm = "unknown";
|
||||||
}
|
}
|
||||||
plugin->name = trim_ext(strdup(plugin->name));
|
plugin->name = trim_ext(strdup(nm));
|
||||||
|
|
||||||
/* Already registered? */
|
/* Already registered? */
|
||||||
if (plugin_find(plugin->name)) {
|
if (plugin_find(plugin->name)) {
|
||||||
_d("... %s already loaded", plugin->name);
|
dbg("... %s already loaded", plugin->name);
|
||||||
free(plugin->name);
|
free(plugin->name);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -119,10 +126,10 @@ int plugin_unregister(plugin_t *plugin)
|
|||||||
#ifndef ENABLE_STATIC
|
#ifndef ENABLE_STATIC
|
||||||
TAILQ_REMOVE(&plugins, plugin, link);
|
TAILQ_REMOVE(&plugins, plugin, link);
|
||||||
|
|
||||||
_d("%s exiting ...", plugin->name);
|
dbg("%s exiting ...", plugin->name);
|
||||||
free(plugin->name);
|
free(plugin->name);
|
||||||
#else
|
#else
|
||||||
_d("Finit built statically, cannot unload %s ...", plugin->name);
|
dbg("Finit built statically, cannot unload %s ...", plugin->name);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -157,8 +164,8 @@ plugin_t *plugin_find(char *name)
|
|||||||
SEARCH_PLUGIN(name);
|
SEARCH_PLUGIN(name);
|
||||||
|
|
||||||
if (plugpath && name[0] != '/') {
|
if (plugpath && name[0] != '/') {
|
||||||
int noext;
|
|
||||||
char path[CMD_SIZE];
|
char path[CMD_SIZE];
|
||||||
|
int noext;
|
||||||
|
|
||||||
noext = strcmp(name + strlen(name) - 3, ".so");
|
noext = strcmp(name + strlen(name) - 3, ".so");
|
||||||
snprintf(path, sizeof(path), "%s%s%s%s", plugpath,
|
snprintf(path, sizeof(path), "%s%s%s%s", plugpath,
|
||||||
@@ -194,22 +201,73 @@ int plugin_exists(hook_point_t no)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(HAVE_HOOK_SCRIPTS_PLUGIN) && defined(PLUGIN_HOOK_SCRIPTS_PATH)
|
||||||
|
#define CHOOSE(x, y) y
|
||||||
|
static const char *hscript_paths[] = HOOK_TYPES;
|
||||||
|
#undef CHOOSE
|
||||||
|
|
||||||
|
void plugin_script_run(hook_point_t no)
|
||||||
|
{
|
||||||
|
const char *hook_name = hscript_paths[no];
|
||||||
|
const char *env[] = {
|
||||||
|
"FINIT_HOOK_NAME", hook_name,
|
||||||
|
"FINIT_SHUTDOWN", NULL,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
char path[CMD_SIZE] = "";
|
||||||
|
|
||||||
|
strlcat(path, PLUGIN_HOOK_SCRIPTS_PATH, sizeof(path));
|
||||||
|
strlcat(path, hook_name + 4, sizeof(path));
|
||||||
|
|
||||||
|
if (no >= HOOK_SHUTDOWN) {
|
||||||
|
switch (halt) {
|
||||||
|
case SHUT_OFF:
|
||||||
|
env[3] = "poweroff";
|
||||||
|
break;
|
||||||
|
case SHUT_HALT:
|
||||||
|
env[3] = "halt";
|
||||||
|
break;
|
||||||
|
case SHUT_REBOOT:
|
||||||
|
env[3] = "reboot";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
env[2] = NULL;
|
||||||
|
|
||||||
|
run_parts(path, NULL, env, 0, 0);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void plugin_script_run(hook_point_t no)
|
||||||
|
{
|
||||||
|
(void)no;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Some hooks are called with a fixed argument */
|
/* Some hooks are called with a fixed argument */
|
||||||
void plugin_run_hook(hook_point_t no, void *arg)
|
void plugin_run_hook(hook_point_t no, void *arg)
|
||||||
{
|
{
|
||||||
plugin_t *p, *tmp;
|
plugin_t *p, *tmp;
|
||||||
|
|
||||||
|
#ifdef HAVE_HOOK_SCRIPTS_PLUGIN
|
||||||
|
if (!cond_is_available() && !plugloaded) {
|
||||||
|
dbg("conditions not available, calling script based hooks only!");
|
||||||
|
plugin_script_run(no);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
PLUGIN_ITERATOR(p, tmp) {
|
PLUGIN_ITERATOR(p, tmp) {
|
||||||
if (p->hook[no].cb) {
|
if (p->hook[no].cb) {
|
||||||
_d("Calling %s hook n:o %d (arg: %p) ...", basename(p->name), no, arg ?: "NIL");
|
dbg("Calling %s hook n:o %d (arg: %p) ...", basenm(p->name), no, arg ?: "NIL");
|
||||||
p->hook[no].cb(arg ? arg : p->hook[no].arg);
|
p->hook[no].cb(arg ? arg : p->hook[no].arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Conditions are stored in /run, so don't try to signal
|
/*
|
||||||
|
* Conditions are stored in /run, so don't try to signal
|
||||||
* conditions for any hooks before filesystems have been
|
* conditions for any hooks before filesystems have been
|
||||||
* mounted. */
|
* mounted.
|
||||||
if (no >= HOOK_MOUNT_ERROR)
|
*/
|
||||||
|
if (cond_is_available() && no >= HOOK_BASEFS_UP && no <= HOOK_SHUTDOWN)
|
||||||
cond_set_oneshot(hook_cond[no]);
|
cond_set_oneshot(hook_cond[no]);
|
||||||
|
|
||||||
service_step_all(SVC_TYPE_RUNTASK);
|
service_step_all(SVC_TYPE_RUNTASK);
|
||||||
@@ -234,7 +292,7 @@ static void generic_io_cb(uev_t *w, void *arg, int events)
|
|||||||
/* Stop watcher, callback may close descriptor on us ... */
|
/* Stop watcher, callback may close descriptor on us ... */
|
||||||
uev_io_stop(w);
|
uev_io_stop(w);
|
||||||
|
|
||||||
_d("Calling I/O %s from runloop...", basename(p->name));
|
// dbg("Calling I/O %s from runloop...", basename(p->name));
|
||||||
p->io.cb(p->io.arg, w->fd, events);
|
p->io.cb(p->io.arg, w->fd, events);
|
||||||
|
|
||||||
/* Update fd, may be changed by plugin callback, e.g., if FIFO */
|
/* Update fd, may be changed by plugin callback, e.g., if FIFO */
|
||||||
@@ -247,9 +305,9 @@ int plugin_io_init(plugin_t *p)
|
|||||||
if (!is_io_plugin(p))
|
if (!is_io_plugin(p))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
_d("Initializing plugin %s for I/O", basename(p->name));
|
dbg("Initializing plugin %s for I/O", basenm(p->name));
|
||||||
if (uev_io_init(ctx, &p->watcher, generic_io_cb, p, p->io.fd, p->io.flags)) {
|
if (uev_io_init(ctx, &p->watcher, generic_io_cb, p, p->io.fd, p->io.flags)) {
|
||||||
_e("Failed setting up I/O plugin %s", basename(p->name));
|
warn("Failed setting up I/O plugin %s", basenm(p->name));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,8 +317,8 @@ int plugin_io_init(plugin_t *p)
|
|||||||
/* Setup any I/O callbacks for plugins that use them */
|
/* Setup any I/O callbacks for plugins that use them */
|
||||||
static int init_plugins(uev_ctx_t *ctx)
|
static int init_plugins(uev_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
int fail = 0;
|
|
||||||
plugin_t *p, *tmp;
|
plugin_t *p, *tmp;
|
||||||
|
int fail = 0;
|
||||||
|
|
||||||
PLUGIN_ITERATOR(p, tmp) {
|
PLUGIN_ITERATOR(p, tmp) {
|
||||||
if (plugin_io_init(p))
|
if (plugin_io_init(p))
|
||||||
@@ -301,16 +359,18 @@ static int load_one(char *path, char *name)
|
|||||||
noext = strcmp(name + strlen(name) - 3, ".so");
|
noext = strcmp(name + strlen(name) - 3, ".so");
|
||||||
snprintf(sofile, sizeof(sofile), "%s/%s%s", path, name, noext ? ".so" : "");
|
snprintf(sofile, sizeof(sofile), "%s/%s%s", path, name, noext ? ".so" : "");
|
||||||
|
|
||||||
_d("Loading plugin %s ...", basename(sofile));
|
dbg("Loading plugin %s ...", sofile);
|
||||||
handle = dlopen(sofile, RTLD_LAZY | RTLD_LOCAL);
|
handle = dlopen(sofile, RTLD_LAZY | RTLD_LOCAL);
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
_e("Failed loading plugin %s: %s", sofile, dlerror());
|
char *error = dlerror();
|
||||||
|
|
||||||
|
warn("Failed loading plugin %s: %s", sofile, error ? error : "unknown error");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
plugin = TAILQ_LAST(&plugins, plugin_head);
|
plugin = TAILQ_LAST(&plugins, plugin_head);
|
||||||
if (!plugin) {
|
if (!plugin) {
|
||||||
_e("Plugin %s failed to register, unloading from memory", sofile);
|
warn("Plugin %s failed to register, unloading from memory", sofile);
|
||||||
dlclose(handle);
|
dlclose(handle);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -337,9 +397,9 @@ static void check_plugin_depends(plugin_t *plugin)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < PLUGIN_DEP_MAX && plugin->depends[i]; i++) {
|
for (i = 0; i < PLUGIN_DEP_MAX && plugin->depends[i]; i++) {
|
||||||
// _d("Plugin %s depends on %s ...", plugin->name, plugin->depends[i]);
|
// dbg("Plugin %s depends on %s ...", plugin->name, plugin->depends[i]);
|
||||||
if (plugin_find(plugin->depends[i])) {
|
if (plugin_find(plugin->depends[i])) {
|
||||||
// _d("OK plugin %s was already loaded.", plugin->depends[i]);
|
// dbg("OK plugin %s was already loaded.", plugin->depends[i]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,13 +409,15 @@ static void check_plugin_depends(plugin_t *plugin)
|
|||||||
|
|
||||||
static int load_plugins(char *path)
|
static int load_plugins(char *path)
|
||||||
{
|
{
|
||||||
|
struct dirent *entry;
|
||||||
int fail = 0;
|
int fail = 0;
|
||||||
DIR *dp;
|
DIR *dp;
|
||||||
struct dirent *entry;
|
|
||||||
|
|
||||||
dp = opendir(path);
|
dp = opendir(path);
|
||||||
if (!dp) {
|
if (!dp) {
|
||||||
_e("Failed, cannot open plugin directory %s: %s", path, strerror(errno));
|
if (errno == ENOENT)
|
||||||
|
return 0;
|
||||||
|
warn("Failed, cannot open plugin directory %s: %s", path, strerror(errno));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
plugpath = path;
|
plugpath = path;
|
||||||
@@ -380,14 +442,70 @@ static int load_plugins(char *path)
|
|||||||
}
|
}
|
||||||
#endif /* ENABLE_STATIC */
|
#endif /* ENABLE_STATIC */
|
||||||
|
|
||||||
|
int plugin_list(char *buf, size_t len)
|
||||||
|
{
|
||||||
|
#ifndef ENABLE_STATIC
|
||||||
|
plugin_t *p, *tmp;
|
||||||
|
|
||||||
|
buf[0] = 0;
|
||||||
|
PLUGIN_ITERATOR(p, tmp) {
|
||||||
|
if (buf[0])
|
||||||
|
strlcat(buf, " ", len);
|
||||||
|
strlcat(buf, p->name, len);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
buf[0] = 0;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int plugin_deps(char *buf, size_t len)
|
||||||
|
{
|
||||||
|
#ifndef ENABLE_STATIC
|
||||||
|
plugin_t *p;
|
||||||
|
|
||||||
|
p = plugin_find(buf);
|
||||||
|
buf[0] = 0;
|
||||||
|
if (p) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < PLUGIN_DEP_MAX; i++) {
|
||||||
|
if (!p->depends[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (buf[0])
|
||||||
|
strlcat(buf, " ", len);
|
||||||
|
strlcat(buf, p->depends[i], len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
buf[0] = 0;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int plugin_init(uev_ctx_t *ctx)
|
int plugin_init(uev_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
int fail = 1;
|
load_plugins(PLUGIN_PATH);
|
||||||
|
|
||||||
if (!load_plugins(PLUGIN_PATH))
|
#ifdef EXTERNAL_PLUGIN_PATH
|
||||||
fail = init_plugins(ctx);
|
char *paths = strdup(EXTERNAL_PLUGIN_PATH);
|
||||||
|
char *path;
|
||||||
|
|
||||||
return fail;
|
if (paths) {
|
||||||
|
dbg("Loading external plugins from %s ...", paths);
|
||||||
|
path = strtok(paths, ":");
|
||||||
|
while (path) {
|
||||||
|
load_plugins(path);
|
||||||
|
path = strtok(NULL, ":");
|
||||||
|
}
|
||||||
|
free(paths);
|
||||||
|
}
|
||||||
|
|
||||||
|
plugloaded = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return init_plugins(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void plugin_exit(void)
|
void plugin_exit(void)
|
||||||
@@ -396,9 +514,13 @@ void plugin_exit(void)
|
|||||||
plugin_t *p, *tmp;
|
plugin_t *p, *tmp;
|
||||||
|
|
||||||
PLUGIN_ITERATOR(p, tmp) {
|
PLUGIN_ITERATOR(p, tmp) {
|
||||||
if (dlclose(p->handle))
|
if (dlclose(p->handle)) {
|
||||||
_e("Failed: unloading plugin %s: %s", p->name, dlerror());
|
char *error = dlerror();
|
||||||
|
warn("Failed unloading plugin %s: %s", p->name, error ? error : "unknown error");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
plugloaded = 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-1
@@ -1,6 +1,6 @@
|
|||||||
/* Plugin based services architecture for finit
|
/* Plugin based services architecture for finit
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2012-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -72,6 +72,7 @@
|
|||||||
CHOOSE(HOOK_MOUNT_ERROR, "hook/mount/error"), \
|
CHOOSE(HOOK_MOUNT_ERROR, "hook/mount/error"), \
|
||||||
CHOOSE(HOOK_MOUNT_POST, "hook/mount/post"), \
|
CHOOSE(HOOK_MOUNT_POST, "hook/mount/post"), \
|
||||||
CHOOSE(HOOK_BASEFS_UP, "hook/mount/all"), \
|
CHOOSE(HOOK_BASEFS_UP, "hook/mount/all"), \
|
||||||
|
CHOOSE(HOOK_SVC_PLUGIN, "hook/svc/plugin"), \
|
||||||
CHOOSE(HOOK_NETWORK_UP, "hook/net/up"), \
|
CHOOSE(HOOK_NETWORK_UP, "hook/net/up"), \
|
||||||
CHOOSE(HOOK_SVC_UP, "hook/svc/up"), \
|
CHOOSE(HOOK_SVC_UP, "hook/svc/up"), \
|
||||||
CHOOSE(HOOK_SYSTEM_UP, "hook/sys/up"), \
|
CHOOSE(HOOK_SYSTEM_UP, "hook/sys/up"), \
|
||||||
@@ -81,7 +82,10 @@
|
|||||||
CHOOSE(HOOK_RUNLEVEL_CHANGE, "nop"), \
|
CHOOSE(HOOK_RUNLEVEL_CHANGE, "nop"), \
|
||||||
\
|
\
|
||||||
/* Shutdown hooks, runlevel [06] */ \
|
/* Shutdown hooks, runlevel [06] */ \
|
||||||
|
CHOOSE(HOOK_NETWORK_DN, "hook/net/down"), \
|
||||||
CHOOSE(HOOK_SHUTDOWN, "hook/sys/shutdown"), \
|
CHOOSE(HOOK_SHUTDOWN, "hook/sys/shutdown"), \
|
||||||
|
CHOOSE(HOOK_SVC_DN, "hook/svc/down"), \
|
||||||
|
CHOOSE(HOOK_SYS_DN, "hook/sys/down"), \
|
||||||
CHOOSE(HOOK_MAX_NUM, "nop") \
|
CHOOSE(HOOK_MAX_NUM, "nop") \
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,6 +150,9 @@ typedef struct plugin {
|
|||||||
/* Public plugin API */
|
/* Public plugin API */
|
||||||
int plugin_io_init (plugin_t *plugin);
|
int plugin_io_init (plugin_t *plugin);
|
||||||
|
|
||||||
|
int plugin_list (char *buf, size_t len);
|
||||||
|
int plugin_deps (char *buf, size_t len);
|
||||||
|
|
||||||
int plugin_register (plugin_t *plugin);
|
int plugin_register (plugin_t *plugin);
|
||||||
int plugin_unregister (plugin_t *plugin);
|
int plugin_unregister (plugin_t *plugin);
|
||||||
|
|
||||||
|
|||||||
+25
-11
@@ -1,7 +1,7 @@
|
|||||||
/* Private header file for main finit daemon, not for plugins
|
/* Private header file for main finit daemon, not for plugins
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||||
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2008-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -29,20 +29,34 @@
|
|||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
|
||||||
#define SERVICE_INTERVAL_DEFAULT 300000 /* 5 mins */
|
#define SERVICE_INTERVAL_DEFAULT 300000 /* 5 mins */
|
||||||
extern int service_interval;
|
#define MATCH_CMD(l, c, x) \
|
||||||
|
(!strncasecmp(l, c, strlen(c)) && (x = (l) + strlen(c)))
|
||||||
|
|
||||||
int api_init (uev_ctx_t *ctx);
|
#define IS_RESERVED_RUNLEVEL(l) (l == 0 || l == 6 || l == INIT_LEVEL)
|
||||||
int api_exit (void);
|
|
||||||
|
|
||||||
void service_monitor (pid_t lost, int status);
|
extern char *finit_conf;
|
||||||
|
extern char *finit_rcsd;
|
||||||
|
extern svc_t *wdog;
|
||||||
|
extern int service_interval;
|
||||||
|
extern char *fsck_mode;
|
||||||
|
extern char *fsck_repair;
|
||||||
|
|
||||||
const char *plugin_hook_str(hook_point_t no);
|
int api_init (uev_ctx_t *ctx);
|
||||||
int plugin_exists (hook_point_t no);
|
int api_exit (void);
|
||||||
void plugin_run_hook (hook_point_t no, void *arg);
|
void conf_flush_events(void);
|
||||||
void plugin_run_hooks (hook_point_t no);
|
|
||||||
|
|
||||||
int plugin_init (uev_ctx_t *ctx);
|
void service_monitor (pid_t lost, int status);
|
||||||
void plugin_exit (void);
|
void service_notify_cb(uev_t *w, void *arg, int events);
|
||||||
|
|
||||||
|
const char *plugin_hook_str (hook_point_t no);
|
||||||
|
int plugin_exists (hook_point_t no);
|
||||||
|
|
||||||
|
void plugin_run_hook (hook_point_t no, void *arg);
|
||||||
|
void plugin_run_hooks (hook_point_t no);
|
||||||
|
void plugin_script_run(hook_point_t no);
|
||||||
|
|
||||||
|
int plugin_init (uev_ctx_t *ctx);
|
||||||
|
void plugin_exit (void);
|
||||||
|
|
||||||
#endif /* FINIT_PRIVATE_H_ */
|
#endif /* FINIT_PRIVATE_H_ */
|
||||||
|
|
||||||
|
|||||||
+30
-19
@@ -1,6 +1,6 @@
|
|||||||
/* reboot, halt, poweroff, shutdown, suspend for finit
|
/* reboot, halt, poweroff, shutdown, suspend for finit
|
||||||
*
|
*
|
||||||
* Copyright (c) 2009-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2009-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* 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
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@@ -42,6 +43,8 @@ static cmd_t cmd = CMD_UNKNOWN;
|
|||||||
static char *msg = NULL;
|
static char *msg = NULL;
|
||||||
|
|
||||||
/* initctl API */
|
/* initctl API */
|
||||||
|
extern int timeout;
|
||||||
|
|
||||||
extern int do_reboot (char *arg);
|
extern int do_reboot (char *arg);
|
||||||
extern int do_halt (char *arg);
|
extern int do_halt (char *arg);
|
||||||
extern int do_poweroff(char *arg);
|
extern int do_poweroff(char *arg);
|
||||||
@@ -98,21 +101,17 @@ static void do_kill(int signo, char *msg)
|
|||||||
do_sleep(5);
|
do_sleep(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sig(int signo)
|
|
||||||
{
|
|
||||||
(void)signo; /* NOP */
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usage(int rc)
|
static int usage(int rc)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Usage: %s [OPTIONS]\n\n"
|
fprintf(stderr, "Usage: %s [OPTIONS]\n\n"
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
" --help This help text\n"
|
" -?, --help This help text\n"
|
||||||
" -f, --force Force unsafe %s now, do not contact the init system.\n"
|
" -f, --force Force unsafe %s now, do not contact the init system.\n"
|
||||||
" --halt Halt system, regardless of how the command is called.\n"
|
" --halt Halt system, regardless of how the command is called.\n"
|
||||||
" -h Halt or power off after shutdown.\n"
|
" -h Halt or power off after shutdown.\n"
|
||||||
" -P, --poweroff Power-off system, regardless of how the command is called.\n"
|
" -P, --poweroff Power-off system, regardless of how the command is called.\n"
|
||||||
" -r, --reboot Reboot system, regardless of how the command is called.\n"
|
" -r, --reboot Reboot system, regardless of how the command is called.\n"
|
||||||
|
" -t, --timeout=SEC Force reboot/shutdown after a given timeout\n"
|
||||||
"\n", prognm, msg);
|
"\n", prognm, msg);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
@@ -120,20 +119,22 @@ static int usage(int rc)
|
|||||||
|
|
||||||
int reboot_main(int argc, char *argv[])
|
int reboot_main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int c, force = 0;
|
|
||||||
struct option long_options[] = {
|
struct option long_options[] = {
|
||||||
{"help", 0, NULL, 'h'},
|
{"help", 0, NULL, '?'},
|
||||||
{"force", 0, NULL, 'f'},
|
{"force", 0, NULL, 'f'},
|
||||||
{"halt", 0, NULL, 'H'},
|
{"halt", 0, NULL, 'H'},
|
||||||
{"poweroff", 0, NULL, 'p'},
|
{"poweroff", 0, NULL, 'p'},
|
||||||
{"reboot", 0, NULL, 'r'},
|
{"reboot", 0, NULL, 'r'},
|
||||||
|
{"timeout", 1, NULL, 't'},
|
||||||
{NULL, 0, NULL, 0}
|
{NULL, 0, NULL, 0}
|
||||||
};
|
};
|
||||||
|
int c, force = 0;
|
||||||
|
int tmp;
|
||||||
|
|
||||||
/* Initial command taken from program name */
|
/* Initial command taken from program name */
|
||||||
transform(prognm);
|
transform(prognm);
|
||||||
|
|
||||||
while ((c = getopt_long(argc, argv, "h?fHPpr", long_options, NULL)) != EOF) {
|
while ((c = getopt_long(argc, argv, "h?fHPprt:", long_options, NULL)) != EOF) {
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case '?':
|
case '?':
|
||||||
return usage(0);
|
return usage(0);
|
||||||
@@ -156,6 +157,13 @@ int reboot_main(int argc, char *argv[])
|
|||||||
cmd = CMD_REBOOT;
|
cmd = CMD_REBOOT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 't':
|
||||||
|
tmp = atoi(optarg);
|
||||||
|
if (tmp < 1)
|
||||||
|
errx(1, "Invalid forced timeout value.");
|
||||||
|
timeout = tmp;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return usage(1);
|
return usage(1);
|
||||||
}
|
}
|
||||||
@@ -164,10 +172,13 @@ int reboot_main(int argc, char *argv[])
|
|||||||
/* Check for any overrides */
|
/* Check for any overrides */
|
||||||
transform(NULL);
|
transform(NULL);
|
||||||
|
|
||||||
/* Catch and ignore SIGTERM on halt/poweroff */
|
/* Check if we're in sulogin shell */
|
||||||
signal(SIGTERM, sig);
|
if (getenv("SULOGIN"))
|
||||||
|
force = 1;
|
||||||
|
|
||||||
if (force) {
|
if (force) {
|
||||||
|
sync();
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case CMD_REBOOT:
|
case CMD_REBOOT:
|
||||||
c = reboot(RB_AUTOBOOT);
|
c = reboot(RB_AUTOBOOT);
|
||||||
@@ -182,9 +193,9 @@ int reboot_main(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CMD_SUSPEND:
|
case CMD_SUSPEND:
|
||||||
c = reboot(RB_SW_SUSPEND);
|
c = suspend();
|
||||||
if (c && errno == EINVAL)
|
if (c && errno == EINVAL)
|
||||||
errx(1, "Kernel does not support suspend.");
|
errx(1, "Kernel does not support suspend to RAM.");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMD_UNKNOWN:
|
case CMD_UNKNOWN:
|
||||||
|
|||||||
+242
@@ -0,0 +1,242 @@
|
|||||||
|
#include <ctype.h> /* isdigit() */
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <paths.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/conio.h>
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/conio.h>
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "sig.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#ifdef __FINIT__
|
||||||
|
#include "helpers.h"
|
||||||
|
#else
|
||||||
|
#include <sys/prctl.h>
|
||||||
|
|
||||||
|
const char *active_msg = NULL;
|
||||||
|
int interactive = 1;
|
||||||
|
int debug;
|
||||||
|
|
||||||
|
static void print_desc(const char *prefix, const char *msg)
|
||||||
|
{
|
||||||
|
if (interactive)
|
||||||
|
fprintf(stderr, "\e[1m[\e[0m\e[1;33m ⋯ \e[0m\e[1m]\e[0m %s %s", prefix, msg);
|
||||||
|
else
|
||||||
|
fprintf(stderr, "%s %s ...\n", prefix, msg);
|
||||||
|
active_msg = msg;
|
||||||
|
}
|
||||||
|
static void print_result(int rc)
|
||||||
|
{
|
||||||
|
if (interactive) {
|
||||||
|
if (rc)
|
||||||
|
fputs("\r\e[1m[\e[0m\e[1;31mFAIL\e[0m\e[1m]\e[0m\n", stderr);
|
||||||
|
else
|
||||||
|
fputs("\r\e[1m[\e[0m\e[1;32m OK \e[0m\e[1m]\e[0m\n", stderr);
|
||||||
|
} else
|
||||||
|
fprintf(stderr, "[%s] %s\n", rc ? "FAIL" : " OK ", active_msg ?: "");
|
||||||
|
}
|
||||||
|
|
||||||
|
void sig_unblock(void)
|
||||||
|
{
|
||||||
|
struct sigaction sa;
|
||||||
|
sigset_t nmask;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
sigemptyset(&nmask);
|
||||||
|
sigaddset(&nmask, SIGHUP);
|
||||||
|
sigaddset(&nmask, SIGCHLD);
|
||||||
|
sigaddset(&nmask, SIGINT);
|
||||||
|
sigaddset(&nmask, SIGPWR);
|
||||||
|
sigaddset(&nmask, SIGSTOP);
|
||||||
|
sigaddset(&nmask, SIGTSTP);
|
||||||
|
sigaddset(&nmask, SIGCONT);
|
||||||
|
sigaddset(&nmask, SIGTERM);
|
||||||
|
sigaddset(&nmask, SIGUSR1);
|
||||||
|
sigaddset(&nmask, SIGUSR2);
|
||||||
|
sigprocmask(SIG_UNBLOCK, &nmask, NULL);
|
||||||
|
|
||||||
|
/* Reset signal handlers that were set by the parent process */
|
||||||
|
for (i = 1; i < NSIG; i++)
|
||||||
|
DFLSIG(sa, i, 0);
|
||||||
|
}
|
||||||
|
#endif /* __FINIT__ */
|
||||||
|
|
||||||
|
static void run_env(const char *env[])
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
if (!env)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (env[i]) {
|
||||||
|
size_t j = i + 1;
|
||||||
|
|
||||||
|
if (!env[j])
|
||||||
|
break;
|
||||||
|
|
||||||
|
setenv(env[i], env[j], 1);
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int run_parts(char *dir, char *cmd, const char *env[], int progress, int sysv)
|
||||||
|
{
|
||||||
|
size_t cmdlen = cmd ? strlen(cmd) : strlen("start");
|
||||||
|
struct dirent **d;
|
||||||
|
int i, num;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
num = scandir(dir, &d, NULL, alphasort);
|
||||||
|
if (num < 0) {
|
||||||
|
dbg("No files found in %s, skipping ...", dir);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
char path[strlen(dir) + strlen(d[i]->d_name) + 3 + cmdlen];
|
||||||
|
const char *name = d[i]->d_name;
|
||||||
|
char *argv[4] = {
|
||||||
|
"sh",
|
||||||
|
"-c",
|
||||||
|
path,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
struct stat st;
|
||||||
|
int result = 0;
|
||||||
|
pid_t pid = 0;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
/* skip backup files */
|
||||||
|
if (name[strlen(name) - 1] == '~')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* cannot rely on d_type, not supported on all filesystems */
|
||||||
|
paste(path, sizeof(path), dir, name);
|
||||||
|
if (stat(path, &st)) {
|
||||||
|
warn("failed stat(%s)", path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* skip non-executable files and directories */
|
||||||
|
if (!S_ISEXEC(st.st_mode) || S_ISDIR(st.st_mode)) {
|
||||||
|
dbg("skipping %s not an executable or is a directory", path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sysv && name[0] != 'S' && name[0] != 'K') {
|
||||||
|
dbg("S-only flag set, skipping non-SysV script: %s", name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the callee didn't supply a run_parts() argument */
|
||||||
|
if (!cmd) {
|
||||||
|
/* Check if S<NUM>service or K<NUM>service notation is used */
|
||||||
|
if (name[0] == 'S' && isdigit(name[1]))
|
||||||
|
strlcat(path, " start", sizeof(path));
|
||||||
|
else if (name[0] == 'K' && isdigit(name[1]))
|
||||||
|
strlcat(path, " stop", sizeof(path));
|
||||||
|
} else {
|
||||||
|
strlcat(path, " ", sizeof(path));
|
||||||
|
strlcat(path, cmd, sizeof(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (progress)
|
||||||
|
print_desc("Calling", path);
|
||||||
|
|
||||||
|
pid = fork();
|
||||||
|
if (!pid) {
|
||||||
|
sig_unblock();
|
||||||
|
run_env(env);
|
||||||
|
|
||||||
|
_exit(execvp(_PATH_BSHELL, argv));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (waitpid(pid, &status, 0) == -1) {
|
||||||
|
warnx("failed starting %s, error %d: %s", path, errno, strerror(errno));
|
||||||
|
result = 1;
|
||||||
|
} else {
|
||||||
|
if (WIFEXITED(status)) {
|
||||||
|
result = WEXITSTATUS(status);
|
||||||
|
dbg("%s exited with status %d", path, result);
|
||||||
|
} else if (WIFSIGNALED(status)) {
|
||||||
|
warnx("%s terminated by signal %d", path, WTERMSIG(status));
|
||||||
|
result = 1;
|
||||||
|
} else
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (progress)
|
||||||
|
print_result(result);
|
||||||
|
rc += result;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (num--)
|
||||||
|
free(d[num]);
|
||||||
|
free(d);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef __FINIT__
|
||||||
|
static int usage(int rc)
|
||||||
|
{
|
||||||
|
warnx("usage: runparts [-dhps?] DIRECTORY");
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int rc, c, progress = 0, sysv = 0;
|
||||||
|
char *dir;
|
||||||
|
|
||||||
|
while ((c = getopt(argc, argv, "bdh?ps")) != EOF) {
|
||||||
|
switch(c) {
|
||||||
|
case 'b': /* batch mode */
|
||||||
|
interactive = 0;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
debug = 1;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
case '?':
|
||||||
|
return usage(0);
|
||||||
|
case 'p':
|
||||||
|
progress = 1;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
sysv = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return usage(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optind >= argc)
|
||||||
|
return usage(1);
|
||||||
|
|
||||||
|
dir = argv[optind];
|
||||||
|
if (!fisdir(dir))
|
||||||
|
return usage(1);
|
||||||
|
|
||||||
|
prctl(PR_SET_CHILD_SUBREAPER, 1);
|
||||||
|
|
||||||
|
rc = run_parts(dir, NULL, NULL, progress, sysv);
|
||||||
|
if (rc == -1)
|
||||||
|
err(1, "failed run-parts %s", dir);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
#endif /* __FINIT__ */
|
||||||
+3
-1
@@ -1,6 +1,6 @@
|
|||||||
/* Work queue helper functions
|
/* Work queue helper functions
|
||||||
*
|
*
|
||||||
* Copyright (c) 2018-2021 Joachim Wiberg <troglobit@gmail.com>
|
* Copyright (c) 2018-2024 Joachim Wiberg <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* 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,6 +23,7 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
|
#include "log.h"
|
||||||
#include "schedule.h"
|
#include "schedule.h"
|
||||||
|
|
||||||
#define SC_INIT 0x494E4954 /* "INIT", see ascii(7) */
|
#define SC_INIT 0x494E4954 /* "INIT", see ascii(7) */
|
||||||
@@ -35,6 +36,7 @@ static void cb(uev_t *w, void *arg, int events)
|
|||||||
struct wq *work = (struct wq *)arg;
|
struct wq *work = (struct wq *)arg;
|
||||||
|
|
||||||
if (UEV_ERROR == events) {
|
if (UEV_ERROR == events) {
|
||||||
|
dbg("%s(): spurious problem with schedule work timer, restarting.", __func__);
|
||||||
uev_timer_start(w);
|
uev_timer_start(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user