mirror of
https://github.com/troglobit/finit.git
synced 2026-10-12 10:12:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83915b42f3 | ||
|
|
babcd117b1 | ||
|
|
892ac2edb2 | ||
|
|
5b12d17b56 | ||
|
|
1b6930126e | ||
|
|
8def97a465 | ||
|
|
7bbc0847b1 | ||
|
|
88dc3f0061 | ||
|
|
02e69932ae | ||
|
|
662dfbe777 | ||
|
|
c249cbdbe1 | ||
|
|
a47171891f | ||
|
|
1dc67acd40 | ||
|
|
146685c2c2 | ||
|
|
3cc2df20f9 | ||
|
|
4f3d246100 | ||
|
|
11bfec1a23 | ||
|
|
f24a03a32c | ||
|
|
829ff0b9f7 | ||
|
|
b9ae4d04ef | ||
|
|
47060c9738 | ||
|
|
846692ca03 | ||
|
|
985d53bec4 | ||
|
|
8548e67dcd | ||
|
|
1c60e949e7 | ||
|
|
86f02e8553 | ||
|
|
2c7332583c | ||
|
|
a96b74ea5e | ||
|
|
5a1b13ff41 | ||
|
|
4a71f19c40 | ||
|
|
5c672885f1 | ||
|
|
e38eb7cbd5 | ||
|
|
ba9ae0337d | ||
|
|
b674aad802 | ||
|
|
88f9458c6e | ||
|
|
6cb3d86cd1 | ||
|
|
5cde809909 | ||
|
|
1b6931eaea | ||
|
|
c3b7530b98 | ||
|
|
0f61b0792b | ||
|
|
bab13c9cef | ||
|
|
9c9fe51eee | ||
|
|
4f8211f6a1 | ||
|
|
5fc3a0a3b9 | ||
|
|
67c55145b9 | ||
|
|
fc2489d9e1 | ||
|
|
a384a95529 | ||
|
|
a013e48ab5 | ||
|
|
24a0ddfc59 | ||
|
|
3da4c2abe9 | ||
|
|
2950820d34 | ||
|
|
75b1ac8199 | ||
|
|
8f05b36551 | ||
|
|
0f840e6576 | ||
|
|
451f63ebe0 | ||
|
|
2dc9daf118 | ||
|
|
3c67a10347 | ||
|
|
6885a9f868 | ||
|
|
38142baa93 | ||
|
|
34bdbdb3b1 | ||
|
|
83af7e8e9d | ||
|
|
4eb5f8a0dc | ||
|
|
e03b358ff0 | ||
|
|
d2846b805a | ||
|
|
07d767e1af | ||
|
|
d423e6b774 | ||
|
|
bb89bdd8a9 | ||
|
|
5cc98f6e53 | ||
|
|
a6300f6ac6 | ||
|
|
aeabb4d2ea | ||
|
|
dcbb429863 | ||
|
|
077d52d209 | ||
|
|
44f5de188d | ||
|
|
191e5440b2 | ||
|
|
a2b0d00058 | ||
|
|
e8fa827026 | ||
|
|
89105090ed | ||
|
|
6ce218612b | ||
|
|
dd87c81adc | ||
|
|
37f3478873 | ||
|
|
a64259362e | ||
|
|
3554138118 | ||
|
|
f7d6d269c7 | ||
|
|
2c1e9877f9 | ||
|
|
a94c97221e | ||
|
|
f9732a6fb9 | ||
|
|
581fc956be | ||
|
|
ee901b018c | ||
|
|
d373ebfdd7 | ||
|
|
698b87dd35 | ||
|
|
dd566acfd2 | ||
|
|
5c56f5c5a7 | ||
|
|
7ab963a576 | ||
|
|
73d462c847 | ||
|
|
56e94a4e4a | ||
|
|
51830e0f5b | ||
|
|
85115eca62 | ||
|
|
659ff9962e | ||
|
|
9436c8b73c | ||
|
|
5a3397419f | ||
|
|
10b72f1d7f | ||
|
|
6b237b7b00 | ||
|
|
b4f385d2e0 | ||
|
|
4b4572de4d | ||
|
|
19b81cf434 | ||
|
|
3023433def | ||
|
|
49968c188b | ||
|
|
2499405b27 | ||
|
|
9fc1f50678 | ||
|
|
b1d709ba22 | ||
|
|
5ddc35d387 | ||
|
|
50632f941b | ||
|
|
7b215e4fd4 | ||
|
|
bb7208c591 | ||
|
|
bb0505f57c | ||
|
|
4aa569de44 | ||
|
|
512a07a25c | ||
|
|
8cfd11c909 | ||
|
|
c3adf3bf51 | ||
|
|
3ca28e765d | ||
|
|
79207dcb22 | ||
|
|
47f3e2ca04 | ||
|
|
2e7bee9f84 | ||
|
|
2681e4c01a | ||
|
|
56a3f6882b | ||
|
|
88d8ab67c9 | ||
|
|
74eb2bf4d2 | ||
|
|
b3fb9ab3ed | ||
|
|
308ae609c4 | ||
|
|
e3783e8bac | ||
|
|
002b24fbc2 | ||
|
|
3f71ed352d | ||
|
|
f7305c36b8 | ||
|
|
8bcecd474b | ||
|
|
a9a7b08021 | ||
|
|
62cb683af0 | ||
|
|
65e44dc88f | ||
|
|
54467d4467 | ||
|
|
cfa258e7f2 | ||
|
|
574760df13 | ||
|
|
c2ec25efd3 | ||
|
|
d670e7d3e8 | ||
|
|
77561b6071 | ||
|
|
cec1c64755 | ||
|
|
5bab329178 | ||
|
|
b6bf8bf518 | ||
|
|
0a21ff5236 | ||
|
|
3853061f09 | ||
|
|
078982d3ec | ||
|
|
f4327910d9 | ||
|
|
b1fb536468 | ||
|
|
95cb94cf49 | ||
|
|
e1c0e7fe58 | ||
|
|
9783e120af | ||
|
|
3ad149fb28 | ||
|
|
e6430aabc2 | ||
|
|
2743a49d91 | ||
|
|
6f99c1db05 | ||
|
|
0eafe8bcd9 | ||
|
|
b01fae03ec | ||
|
|
dbbe6b31b8 | ||
|
|
2718c709aa | ||
|
|
8c54fde36c | ||
|
|
0d1bc167ff | ||
|
|
f8def336d4 | ||
|
|
addc21bdf6 | ||
|
|
27899feea0 | ||
|
|
a016359891 | ||
|
|
7cdd42195b | ||
|
|
07f06c8b95 | ||
|
|
2067fd597f | ||
|
|
f0318b0df0 | ||
|
|
508c7b225a | ||
|
|
8a79b05a97 | ||
|
|
7b07d5559c | ||
|
|
23cdd6e438 | ||
|
|
576cb1075c | ||
|
|
fc74fb110d | ||
|
|
baa914e995 | ||
|
|
6490735ee9 | ||
|
|
13159ea99a | ||
|
|
b9fa0f85a2 | ||
|
|
dbbe3cecb3 | ||
|
|
1a8f1d9604 | ||
|
|
d76ecad517 | ||
|
|
f81750e0b1 | ||
|
|
7fc7faf59a | ||
|
|
c38b452ac4 | ||
|
|
7eac88b639 | ||
|
|
f374f443f4 | ||
|
|
d2a5e65862 | ||
|
|
501deae4ed | ||
|
|
2c29893558 | ||
|
|
a1a7f69349 | ||
|
|
8d9fbea551 | ||
|
|
1d89e1a706 | ||
|
|
596b7cc413 | ||
|
|
fbed5cd8cb | ||
|
|
0cb1ce2483 | ||
|
|
e23b62ffb7 | ||
|
|
94d41e38f8 | ||
|
|
42800a1cc8 | ||
|
|
4cf60b7491 | ||
|
|
72a9832662 | ||
|
|
eeb59eb22b | ||
|
|
0df0f019e3 | ||
|
|
bc7f6f1bc1 | ||
|
|
73b807a007 | ||
|
|
62113a0057 | ||
|
|
968f1bf991 | ||
|
|
57514130fc | ||
|
|
0710fdd2a3 | ||
|
|
08e46782e5 | ||
|
|
b96d8d3055 | ||
|
|
4ede2a93b2 | ||
|
|
dd2eb9ce04 | ||
|
|
d15633781b | ||
|
|
789354ab40 | ||
|
|
8002704a5f | ||
|
|
82853bf0ea | ||
|
|
bfe9e011bd | ||
|
|
9416e14074 | ||
|
|
46a58f058a | ||
|
|
72a484b639 | ||
|
|
82e483d6c7 | ||
|
|
dafa50ee42 | ||
|
|
2187e05e06 | ||
|
|
a4fd058607 | ||
|
|
c49eb5e10d | ||
|
|
01d1dabaae | ||
|
|
a3b0022d66 | ||
|
|
e4d882e99e | ||
|
|
5ef426d424 | ||
|
|
5ee1b7c322 | ||
|
|
0d665f3773 | ||
|
|
38619966ee | ||
|
|
6380f17d1f | ||
|
|
42181a3031 | ||
|
|
77b32ebff0 | ||
|
|
97de3ad0bb | ||
|
|
44f8a2666f | ||
|
|
4cf5b055cf | ||
|
|
744bb9dd14 | ||
|
|
1edfecdaab | ||
|
|
bc84d66018 | ||
|
|
2216923343 | ||
|
|
ac834cfa1c | ||
|
|
f191266a33 | ||
|
|
796275af62 | ||
|
|
a7e52914d2 | ||
|
|
fcfbd57ca8 | ||
|
|
5b81d14e51 | ||
|
|
329af172de | ||
|
|
33ce1592c1 | ||
|
|
7a954e3743 | ||
|
|
48c2937f4f | ||
|
|
24961eb3ba | ||
|
|
aced97c2e6 | ||
|
|
a67350ebf6 | ||
|
|
c47a0cd812 | ||
|
|
67c0d43912 | ||
|
|
7b00969f6c | ||
|
|
875080d1e1 | ||
|
|
1121965167 | ||
|
|
45bdadebb6 | ||
|
|
7dfdc2395b | ||
|
|
5723b2e75b | ||
|
|
d4fdf50636 | ||
|
|
4f7366640b | ||
|
|
90497af7bb | ||
|
|
cd0983a7f6 | ||
|
|
c7573fedad | ||
|
|
2b74fb0e93 | ||
|
|
eb57457522 | ||
|
|
f0cda83d24 | ||
|
|
fbacae7071 | ||
|
|
48e2cbd183 | ||
|
|
8f9ea0ae57 | ||
|
|
1c0776b818 | ||
|
|
6ff9cb2ff3 | ||
|
|
fbef03a4c6 | ||
|
|
66f22a0a5f | ||
|
|
171ae7dc85 | ||
|
|
ebfa8f061c | ||
|
|
2baa4f8ea9 | ||
|
|
38203ab9e8 | ||
|
|
88a4ebf9e7 | ||
|
|
51f61939da | ||
|
|
7262a25c85 | ||
|
|
8b9309ee41 | ||
|
|
affc6a97b9 | ||
|
|
ec041b3c02 | ||
|
|
267eeb9692 | ||
|
|
58e00fe52e | ||
|
|
a40301ef86 | ||
|
|
3a86db7d9f | ||
|
|
927956bf78 | ||
|
|
05938a88ce | ||
|
|
4a8a92af2e | ||
|
|
79b95daf3a | ||
|
|
ea21bfc4c9 | ||
|
|
e9da876a10 | ||
|
|
ef7f0b100b | ||
|
|
33ccff7733 | ||
|
|
00e5a8f5d9 | ||
|
|
f74a73be20 | ||
|
|
34d8848b5c | ||
|
|
662f364d09 | ||
|
|
e53acd1cdd | ||
|
|
d96d1a3023 | ||
|
|
f249210c04 | ||
|
|
969ecffc05 | ||
|
|
cc15d3f77b | ||
|
|
ad2bafbfe8 | ||
|
|
c5fad8e659 | ||
|
|
c1f725340d | ||
|
|
29315090f9 | ||
|
|
60df2043ac | ||
|
|
d48da81026 | ||
|
|
5b86c76694 | ||
|
|
364f3bbafb | ||
|
|
9a539c636a | ||
|
|
ca830b9a09 | ||
|
|
f2b0951d78 | ||
|
|
6d84fd010e | ||
|
|
110ee220e7 | ||
|
|
f29dff691f | ||
|
|
a1e6febc4f | ||
|
|
df1fbbc996 | ||
|
|
448a9e1198 | ||
|
|
80624d3ff8 | ||
|
|
4b0f78c1b5 | ||
|
|
5ea3cc0090 | ||
|
|
7f5f8ba09d | ||
|
|
efd265c9c8 | ||
|
|
7e91cb4afc | ||
|
|
9a03adce5a | ||
|
|
06d1e90bac | ||
|
|
439d9df122 | ||
|
|
f44ac5a023 | ||
|
|
84c75c4416 | ||
|
|
ee8a69f5ed | ||
|
|
acf6cb6900 | ||
|
|
f51183d5f2 | ||
|
|
ff5814e4d4 | ||
|
|
831d0c5520 | ||
|
|
d9cc21b3c8 | ||
|
|
096a3eff51 | ||
|
|
889bce1768 | ||
|
|
0ba8df5c2d | ||
|
|
ec2505191b | ||
|
|
3de9e4e5db | ||
|
|
1177c734ce | ||
|
|
f7f222c924 | ||
|
|
dd8715f3dc | ||
|
|
3e93ed2ead | ||
|
|
e50e12417e | ||
|
|
9e70a12273 | ||
|
|
b313e623df | ||
|
|
376d7a0fbb | ||
|
|
1398536194 | ||
|
|
95135ca0a7 | ||
|
|
ec31930638 | ||
|
|
ed8b21db36 | ||
|
|
b1cd3a2332 | ||
|
|
5675d068f8 | ||
|
|
4baf2611f6 | ||
|
|
13d4821abe | ||
|
|
1f1c2e0466 | ||
|
|
c4af8b7cbd | ||
|
|
426d915c08 | ||
|
|
86be6812b9 | ||
|
|
4efdc4fe19 | ||
|
|
da76cf4f75 | ||
|
|
a2177a8063 | ||
|
|
cfa155deae | ||
|
|
e7832e2ca7 | ||
|
|
d7d45b65d0 | ||
|
|
4ae5c54f45 | ||
|
|
7b8944730d | ||
|
|
87ca6574b8 | ||
|
|
35844f2d1d | ||
|
|
2e2d87ee78 | ||
|
|
ba11d218bc | ||
|
|
707c42db63 | ||
|
|
4cfe4781a3 | ||
|
|
8f415aeaf6 | ||
|
|
3f3220e806 | ||
|
|
e54c7eef65 | ||
|
|
05cc6bf5d2 | ||
|
|
4fecb8621d | ||
|
|
6a49f7ed8c | ||
|
|
8bcc34ce91 | ||
|
|
8da1505454 | ||
|
|
34e4d31219 | ||
|
|
6489dcc967 | ||
|
|
2d6769005a | ||
|
|
98cd6dffb1 | ||
|
|
eb86a76a0d | ||
|
|
4423a2b16e | ||
|
|
0467c571df | ||
|
|
cef4b5761a | ||
|
|
806d05622a | ||
|
|
57fb4738f1 | ||
|
|
0bbc69200b | ||
|
|
726f0d428d | ||
|
|
0704947c33 | ||
|
|
2555fe8e96 | ||
|
|
c41016ef32 | ||
|
|
5d86137142 | ||
|
|
bd58345b8c | ||
|
|
994b589377 | ||
|
|
caff08f58d | ||
|
|
d58c58d972 | ||
|
|
a97499999e | ||
|
|
9c7046a25d | ||
|
|
cd5d55ef51 | ||
|
|
5eb172ed46 | ||
|
|
3d99940252 | ||
|
|
fce420121c | ||
|
|
6c91c4ec12 | ||
|
|
2cb5997abe | ||
|
|
5afb47bc9b | ||
|
|
d6d92f1df7 | ||
|
|
4899bba06b | ||
|
|
97a160dd1d | ||
|
|
901bdc68ba | ||
|
|
c6055031b8 | ||
|
|
e8d699c194 | ||
|
|
80273555c5 | ||
|
|
6ece4b8fa3 | ||
|
|
0beb566e45 | ||
|
|
c641a1374e | ||
|
|
171d611b14 | ||
|
|
02eb68f46c | ||
|
|
7fe4c3355f | ||
|
|
5b28fed321 | ||
|
|
aa1da0e9f2 | ||
|
|
2232aea0f7 | ||
|
|
7a3408c173 | ||
|
|
af7b6c17cb | ||
|
|
a822a7657c | ||
|
|
e46271c1a9 | ||
|
|
1028725079 | ||
|
|
ed5ee667ae | ||
|
|
4c3e053041 | ||
|
|
a5c5a5c644 | ||
|
|
fa3a97366c | ||
|
|
5b3e3da7ff | ||
|
|
59d96f264d | ||
|
|
7027cbc439 | ||
|
|
8218fff7e5 | ||
|
|
263e23a0df | ||
|
|
1f88e1ff8a | ||
|
|
b4ccc8b008 | ||
|
|
8df2b7b6e9 | ||
|
|
8073f7cf27 | ||
|
|
e303e1f833 | ||
|
|
3ea4be9343 | ||
|
|
d8188428ed | ||
|
|
d9f1882204 | ||
|
|
4d899851cc | ||
|
|
ad8feca3e7 | ||
|
|
7569c479b8 | ||
|
|
e7db6c6ac6 | ||
|
|
f12535dc19 | ||
|
|
b19ea16e9d | ||
|
|
eb59155dad | ||
|
|
f38dfaf2dc | ||
|
|
4ada42f380 | ||
|
|
924bf041bc | ||
|
|
b1d57d6828 | ||
|
|
87f9b94b42 | ||
|
|
c8f0b97d0f | ||
|
|
f902505b5d | ||
|
|
a6b78d57c0 | ||
|
|
a33478d563 | ||
|
|
369fcf2100 | ||
|
|
b2c5e97417 | ||
|
|
8725200260 | ||
|
|
58980c72fa | ||
|
|
bcc70ec774 | ||
|
|
44579cc089 | ||
|
|
da361f460d | ||
|
|
bc2cb21005 | ||
|
|
e1169628ce | ||
|
|
48b420b757 | ||
|
|
9796809907 | ||
|
|
a3193b34a6 | ||
|
|
c0af01db6d | ||
|
|
3c1c7df420 | ||
|
|
258efd4101 | ||
|
|
5e33647f80 | ||
|
|
d2f23e281f | ||
|
|
b5e3e69553 | ||
|
|
8d85e59214 | ||
|
|
a1c8ada320 | ||
|
|
ae15988eb8 | ||
|
|
9491f18972 | ||
|
|
545f3105e2 | ||
|
|
eec166a9eb | ||
|
|
125fc661a3 | ||
|
|
6531b2f20a | ||
|
|
1f84edfb8c | ||
|
|
c354d0e7e6 | ||
|
|
98eb7cfea1 | ||
|
|
ec80ce1c9b | ||
|
|
ef05983dc8 | ||
|
|
1c04097dca | ||
|
|
36aba8952f | ||
|
|
6e07dd8dec | ||
|
|
ffa32c6674 | ||
|
|
c30039facf | ||
|
|
b13c6421b3 | ||
|
|
fcaf5d7b76 | ||
|
|
f9ddb1bdfc | ||
|
|
5701a00558 | ||
|
|
9a81bbccbb | ||
|
|
2fcd0fd899 | ||
|
|
5126017c7e | ||
|
|
d2ed03e74c | ||
|
|
525aef10dd | ||
|
|
57031071fb | ||
|
|
0bd57a7826 | ||
|
|
814ffd9259 | ||
|
|
f94db7bceb | ||
|
|
98ba5955c8 | ||
|
|
52c51f16ed | ||
|
|
3b1e652d40 | ||
|
|
d6490df9a3 | ||
|
|
0fd9aa6497 | ||
|
|
b30678bbe9 | ||
|
|
1db144c677 | ||
|
|
8b8ddc43b5 | ||
|
|
838ec0423d | ||
|
|
05a8ace030 | ||
|
|
a05f920292 | ||
|
|
d8b331d737 | ||
|
|
381a32bf8a | ||
|
|
ee9e49f412 | ||
|
|
ff2df8ce5c | ||
|
|
e595e9da5f | ||
|
|
f1807a32ca | ||
|
|
9a6ab331a6 | ||
|
|
70af5d7f8d | ||
|
|
36c59e77b4 | ||
|
|
57b167f9aa | ||
|
|
155ae15390 | ||
|
|
06a1a3c839 | ||
|
|
42f3d4dc79 | ||
|
|
8e12dba8d9 | ||
|
|
589a7ea8a5 | ||
|
|
e5732f24d3 | ||
|
|
3d0e58ebcd | ||
|
|
162b394726 | ||
|
|
c6a9fa3b98 | ||
|
|
e04c73bab8 | ||
|
|
ac0edc9b37 | ||
|
|
59731988fd | ||
|
|
d0da3b8b98 | ||
|
|
be074abce8 | ||
|
|
577622c945 | ||
|
|
5d2172eac8 | ||
|
|
276cda9a4d | ||
|
|
bafdf0007f | ||
|
|
064e94e030 | ||
|
|
c00ac21fe2 | ||
|
|
164fe12685 | ||
|
|
e7dad9a770 | ||
|
|
02e5c868ba | ||
|
|
66f472bb05 | ||
|
|
7b894fcf52 | ||
|
|
0de4fb0cbf | ||
|
|
231539cd7d | ||
|
|
195f17ae08 | ||
|
|
54ace1a6cf | ||
|
|
1f19b50846 | ||
|
|
6c58a7d774 | ||
|
|
dbcece81ea | ||
|
|
70f4d99922 | ||
|
|
ee6d524bc8 | ||
|
|
d9055c3965 | ||
|
|
03573b41ca | ||
|
|
b0c759e518 | ||
|
|
1a1f24721f | ||
|
|
66edb42e06 | ||
|
|
4e904142cb | ||
|
|
7b5d56df98 | ||
|
|
1d58f4abbe | ||
|
|
24e1d284ad | ||
|
|
720324b256 | ||
|
|
534979e6c7 | ||
|
|
6a27ad8997 | ||
|
|
6d3972cca8 | ||
|
|
f8d608107c | ||
|
|
0dd97de046 | ||
|
|
2026486fda | ||
|
|
811bd75eab | ||
|
|
97a48ec5fb | ||
|
|
8e9a5ee678 | ||
|
|
7236e8c6a3 | ||
|
|
2c1f3b1f7a | ||
|
|
f5584ecc3c | ||
|
|
e83f4ab4bf | ||
|
|
fa89370517 | ||
|
|
2cba0c73be | ||
|
|
cb075560ed | ||
|
|
687f52b0b5 | ||
|
|
24051ab2fb | ||
|
|
9139afd318 | ||
|
|
71ecead5b7 | ||
|
|
56292f27c2 | ||
|
|
14c2f612cf | ||
|
|
e9506aec1c | ||
|
|
d2eb46c173 | ||
|
|
0d733ad234 | ||
|
|
4955e05882 | ||
|
|
c3fcfe7e4e | ||
|
|
32587d341c | ||
|
|
a74b640507 | ||
|
|
52664791f5 | ||
|
|
cf651df744 | ||
|
|
807df44769 | ||
|
|
f97bc83ac1 | ||
|
|
daa299721d | ||
|
|
ec90e3dac3 | ||
|
|
5ddd5c15a5 | ||
|
|
957586db09 | ||
|
|
e0c8a7df66 | ||
|
|
c769fbda0f | ||
|
|
1f860164f4 | ||
|
|
e29c5c069b | ||
|
|
872d0d24e7 | ||
|
|
b644f6f635 | ||
|
|
510d15195c | ||
|
|
7ad4bce487 | ||
|
|
703b7537cf | ||
|
|
9cb6c88f34 | ||
|
|
97068223ff | ||
|
|
1de5777f7e | ||
|
|
aff11d83d8 | ||
|
|
335f09726f | ||
|
|
12c470667f | ||
|
|
71ac8bb802 | ||
|
|
fc9758da8e | ||
|
|
216701ce3c | ||
|
|
5d5075954e | ||
|
|
ded4b3926e | ||
|
|
365932510f | ||
|
|
888128e56b | ||
|
|
2adec264af | ||
|
|
ccdab464c3 | ||
|
|
a7353678a3 | ||
|
|
ad8ae4af91 | ||
|
|
dd7f0ce090 | ||
|
|
8c955836dd | ||
|
|
183022ebe4 | ||
|
|
33be077f92 | ||
|
|
6a137fa73c | ||
|
|
25c85dfc88 | ||
|
|
58cc96115c | ||
|
|
b4b63d3722 | ||
|
|
d6efe85a57 | ||
|
|
51b27e8372 | ||
|
|
cac612c485 | ||
|
|
a5b9f566b3 | ||
|
|
0d098616e8 | ||
|
|
63722a20ac | ||
|
|
6f6ab6bc33 | ||
|
|
7f0a85c106 | ||
|
|
46ddf4bcc6 | ||
|
|
f5ab075f9d | ||
|
|
9b361864fa | ||
|
|
41b0dc41a6 | ||
|
|
cab339c857 | ||
|
|
dcb42602c9 | ||
|
|
9e446557b4 | ||
|
|
a3d76c58a4 | ||
|
|
e0e0581d10 | ||
|
|
ef75d5ec31 | ||
|
|
dfeabd8bae | ||
|
|
7aa687bad9 | ||
|
|
c2ea2c1193 | ||
|
|
291b22e987 | ||
|
|
a091b69dd6 | ||
|
|
887c84a0d1 | ||
|
|
5009d54ab8 | ||
|
|
840ade6da7 | ||
|
|
030aa70842 | ||
|
|
dea3ae857b | ||
|
|
9f5172b0d1 | ||
|
|
e0529a5597 | ||
|
|
425cd17e57 | ||
|
|
0669a9cb81 | ||
|
|
5e040449c4 | ||
|
|
074686b520 | ||
|
|
d40f52357e | ||
|
|
076f77a31b | ||
|
|
8f1c16a8a5 | ||
|
|
b149dbc73e | ||
|
|
aa8d6a7294 | ||
|
|
a94dde403f | ||
|
|
9bb7e7b014 | ||
|
|
02a97e8d7d | ||
|
|
def759fe41 | ||
|
|
939cfc2476 | ||
|
|
7f2c73468f | ||
|
|
81a368f710 | ||
|
|
4e975e4974 | ||
|
|
a296c2dd00 | ||
|
|
5ff7994852 | ||
|
|
1bdcef9a2c | ||
|
|
f621117eb9 | ||
|
|
83cec7129a | ||
|
|
06b33c58fd | ||
|
|
8ce39f592c | ||
|
|
d37c451e81 | ||
|
|
a7ff1a61d5 | ||
|
|
8349909f60 | ||
|
|
3a2cf30f47 | ||
|
|
9a3cab3645 | ||
|
|
7dbc02f879 | ||
|
|
a39f75744c | ||
|
|
5742c6591a | ||
|
|
588901ee4c | ||
|
|
e30d2aae19 | ||
|
|
463e4f12f8 | ||
|
|
01c2817005 | ||
|
|
1a16aab970 | ||
|
|
8247344f0d | ||
|
|
2fdd64a2d8 | ||
|
|
22ed4e7f73 | ||
|
|
327ac9f931 | ||
|
|
5ad0c38fe8 | ||
|
|
757911f149 | ||
|
|
35b771fb42 | ||
|
|
720f1b0e5b | ||
|
|
292a3be515 | ||
|
|
5ed407e493 | ||
|
|
40988b901c | ||
|
|
26d49b2027 | ||
|
|
10386ee4de | ||
|
|
773d2e65d6 | ||
|
|
3e29d883fa | ||
|
|
f6f2895524 | ||
|
|
62287f8fcc | ||
|
|
be3257f805 | ||
|
|
1bf3aa528a | ||
|
|
056236c9f8 | ||
|
|
71fff76111 | ||
|
|
1095724e5c | ||
|
|
e81c2f2f90 | ||
|
|
9f91b4c050 | ||
|
|
7ada824e3e | ||
|
|
7cf7591f0a | ||
|
|
143a257c25 | ||
|
|
1d98647c54 | ||
|
|
7cd52b36a1 | ||
|
|
b033052647 | ||
|
|
4fcf2533a6 | ||
|
|
a8a103a521 | ||
|
|
12b09bb80b | ||
|
|
49aaffcf9a | ||
|
|
afbe628f17 | ||
|
|
1d6cbe31fe | ||
|
|
cb874d7a94 | ||
|
|
d7598ca672 | ||
|
|
ff8e494abd | ||
|
|
dfaa6dd3f8 | ||
|
|
849f3fbb28 | ||
|
|
329acf24bb | ||
|
|
bf40278131 | ||
|
|
4f2cf52eff | ||
|
|
f96fb855ce | ||
|
|
65f0be8a55 | ||
|
|
bcfcafdb7c | ||
|
|
c57bd066d1 | ||
|
|
4171fbdfd3 | ||
|
|
0f60aa2289 | ||
|
|
f97aab4699 | ||
|
|
740d447442 | ||
|
|
6448d6ccfa | ||
|
|
25cc9f3b9b | ||
|
|
e776838de9 | ||
|
|
bf0cfe0693 | ||
|
|
f690767507 | ||
|
|
4d57b14b5b | ||
|
|
263036045a | ||
|
|
56ef3f75d3 | ||
|
|
d0c902ab78 | ||
|
|
5ba7bc1fdf | ||
|
|
7e9ac7ba67 | ||
|
|
e2eaee9620 | ||
|
|
b23ce7ab8e | ||
|
|
53127a7ce6 | ||
|
|
011b73ba39 | ||
|
|
5d04a72a61 | ||
|
|
c3b76fdccf | ||
|
|
ec95243dad | ||
|
|
ae5d4a0bb2 | ||
|
|
0231f858e9 | ||
|
|
5d6db9f76f | ||
|
|
3bcefd2160 | ||
|
|
89675403d8 | ||
|
|
f277166354 | ||
|
|
b212babc87 | ||
|
|
6518c2d246 | ||
|
|
c551228079 | ||
|
|
c1198087af | ||
|
|
990ccc6d8b | ||
|
|
56a16066b7 | ||
|
|
407a47dd12 | ||
|
|
73b43b4f2b | ||
|
|
5961748b2a | ||
|
|
a18c5f3441 | ||
|
|
03c47a4020 | ||
|
|
77b0df3d07 | ||
|
|
7e3465a022 | ||
|
|
04fd3f7a1b | ||
|
|
685618691d | ||
|
|
f29d2733c7 | ||
|
|
af59174e49 | ||
|
|
785c21d27b | ||
|
|
40c7a44d4f | ||
|
|
cbb50937cd | ||
|
|
83a4bf7947 | ||
|
|
0d7d5a9820 | ||
|
|
65c9e7ebc6 | ||
|
|
c002b5301f | ||
|
|
3f1c2f6211 | ||
|
|
5116cd66ef | ||
|
|
f55f68d032 | ||
|
|
5e99b5e735 | ||
|
|
d26852e07a | ||
|
|
a90a7c04e4 | ||
|
|
14a1fb9cde | ||
|
|
b373e199a8 | ||
|
|
149ed0e81c | ||
|
|
e32ca1fc83 | ||
|
|
9aa90763b0 | ||
|
|
06759d3544 | ||
|
|
ff73dab447 | ||
|
|
0d70fa4cf0 | ||
|
|
103bf33b3c | ||
|
|
2b2fcb740c | ||
|
|
7542f4e199 | ||
|
|
1fece1f9b5 | ||
|
|
814ff1f77e | ||
|
|
fbfffbc9a4 | ||
|
|
e496913f5c | ||
|
|
5bc9ff0e20 | ||
|
|
dd0220fd2c | ||
|
|
bb0a378f1c | ||
|
|
2a025356d4 | ||
|
|
c49d89dfe0 | ||
|
|
75eb5cc043 | ||
|
|
dfa0fe6428 | ||
|
|
0e02429e75 | ||
|
|
5dda9051ac | ||
|
|
239772d667 | ||
|
|
a0fa877520 | ||
|
|
23ef745985 | ||
|
|
077a7e82e0 | ||
|
|
d21dc2b477 | ||
|
|
c0356b5c7a | ||
|
|
855c7d8251 | ||
|
|
2f527215d0 | ||
|
|
5da4f4cfc3 | ||
|
|
b0aec188bc | ||
|
|
4657d9713a | ||
|
|
a654d99b92 | ||
|
|
e2c4a6ceaf | ||
|
|
5816c9cab9 | ||
|
|
f92438d42a | ||
|
|
6afbcbdd6e | ||
|
|
b9583fb354 | ||
|
|
37af9970d4 | ||
|
|
3a7f7cd61a | ||
|
|
b11d6c6d4e | ||
|
|
88ffb9351d | ||
|
|
c70872f19e | ||
|
|
9e0b22ddb6 | ||
|
|
321264f0dc | ||
|
|
65c971925c | ||
|
|
a2de2c1591 | ||
|
|
85fedac866 | ||
|
|
29ab953a87 | ||
|
|
1843a0e66f | ||
|
|
6a8a3fd4ab | ||
|
|
d096efe643 | ||
|
|
e33d385f0c | ||
|
|
7ebc19782f | ||
|
|
4af58f8bb0 | ||
|
|
ed4abc952a | ||
|
|
52feb6f51c | ||
|
|
c7c388e567 | ||
|
|
95a70ed2af | ||
|
|
4554377e4d | ||
|
|
3811275df5 | ||
|
|
7360ef1f08 | ||
|
|
529224153f | ||
|
|
0f8393ef0e | ||
|
|
a1d7e48225 | ||
|
|
938773765c | ||
|
|
367049a11c | ||
|
|
efcdc141c8 | ||
|
|
dfed328d47 | ||
|
|
804aa3c747 | ||
|
|
3ce7638dab | ||
|
|
b0746f5220 | ||
|
|
c324eff01a | ||
|
|
a6f534621c | ||
|
|
b0e3dbc47f | ||
|
|
220b2c9ae3 | ||
|
|
173853ca17 | ||
|
|
9f83bbe788 | ||
|
|
a187b88dd9 | ||
|
|
134d9f3463 | ||
|
|
25e9d84673 | ||
|
|
765bef0991 | ||
|
|
7d10388158 | ||
|
|
a0382dfab8 | ||
|
|
ead2eb7076 | ||
|
|
0f2a14bf4f | ||
|
|
4e8be438e9 | ||
|
|
2f3404165f | ||
|
|
ca9ee99f59 | ||
|
|
0ab62c8871 | ||
|
|
efdac3fc2d | ||
|
|
c127735e2d | ||
|
|
d621b0ba15 | ||
|
|
33469873a5 | ||
|
|
36043c04f9 | ||
|
|
ec10fecd8d | ||
|
|
0fc7654a83 | ||
|
|
ba9c897e83 | ||
|
|
4948844f82 | ||
|
|
9f99f38561 | ||
|
|
f516108ca6 | ||
|
|
04b91da9f9 | ||
|
|
f94504ad96 | ||
|
|
698c5a1852 | ||
|
|
d5037d1352 | ||
|
|
57ad91136b | ||
|
|
9488e65998 | ||
|
|
19540d148e | ||
|
|
df14fd5255 |
+35
@@ -0,0 +1,35 @@
|
||||
*~
|
||||
*.o
|
||||
*.so
|
||||
*.gz
|
||||
*.map
|
||||
configure
|
||||
Makefile
|
||||
Makefile.in
|
||||
/.deps/*
|
||||
/.libs/*
|
||||
/finit
|
||||
/initctl
|
||||
/reboot
|
||||
/config.h
|
||||
/config.mk
|
||||
/GPATH
|
||||
/GRTAGS
|
||||
/GSYMS
|
||||
/GTAGS
|
||||
/autom4te.cache/*
|
||||
/aclocal.m4
|
||||
/ar-lib
|
||||
/compile
|
||||
/config.guess
|
||||
/config.h.in
|
||||
/config.log
|
||||
/config.status
|
||||
/config.sub
|
||||
/depcomp
|
||||
/install-sh
|
||||
/libtool
|
||||
/ltmain.sh
|
||||
|
||||
/missing
|
||||
/stamp-h1
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
# Travis CI integration -- https://travis-ci.org/troglobit/finit
|
||||
# Defaults to GNU GCC and autotools: ./configure && make && make test
|
||||
language: c
|
||||
|
||||
# Use docker for quicker builds, it now allows https://docs.travis-ci.com/user/apt/
|
||||
sudo: false
|
||||
|
||||
# Use non-docker builds atm. to install libuEv and libite from source
|
||||
#sudo: true
|
||||
|
||||
# Test build with both GCC and Clang (LLVM)
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
|
||||
env:
|
||||
global:
|
||||
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||
# via the "travis encrypt" command using the project repo's public key
|
||||
- secure: "eOiuHs02lG2Uv146K9dMqucGTWUJFEhpz1oAtwe+kPrRXsXWc20hYMO+DSpMgD05vSvNeQA6p7h7LdRFQ+/g/Obj27TsOE+RKkUvRAtdwzxnKVyii9C/nmML8cFw7rIA0VS8O9mAkVYeyDxNDupBp3e9DPCibhKPvqCvioTnyy4="
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- tree
|
||||
coverity_scan:
|
||||
project:
|
||||
name: "troglobit/finit"
|
||||
description: "finit | Fast & Extensible init for Linux"
|
||||
notification_email: troglobit@gmail.com
|
||||
build_command_prepend: "./autogen.sh && PKG_CONFIG_PATH=/tmp/lib/pkgconfig ./configure --prefix=/tmp"
|
||||
build_command: "make"
|
||||
branch_pattern: dev
|
||||
|
||||
install:
|
||||
- wget https://github.com/troglobit/libuev/releases/download/v1.5.2/libuev-1.5.2.tar.xz
|
||||
- wget https://github.com/troglobit/libite/releases/download/v1.8.2/libite-1.8.2.tar.xz
|
||||
- tar xf libuev-1.5.2.tar.xz
|
||||
- tar xf libite-1.8.2.tar.xz
|
||||
- (cd libuev-1.5.2 && ./configure --prefix=/tmp && make && make install-strip)
|
||||
- (cd libite-1.8.2 && ./configure --prefix=/tmp && make && make install-strip)
|
||||
|
||||
# Custom build script for the time being, no "make test" yet
|
||||
script:
|
||||
- ./autogen.sh
|
||||
- PKG_CONFIG_PATH=/tmp/lib/pkgconfig ./configure --prefix=/tmp
|
||||
- cat config.log
|
||||
- make clean
|
||||
- make -j5 V=1
|
||||
- make install-strip
|
||||
- tree /tmp
|
||||
- ldd /tmp/sbin/finit
|
||||
- size /tmp/sbin/finit
|
||||
- size /tmp/sbin/initctl
|
||||
- size /tmp/sbin/reboot
|
||||
- LD_LIBRARY_PATH=/tmp/lib /tmp/sbin/initctl -h
|
||||
@@ -0,0 +1,6 @@
|
||||
Current Maintainer(s):
|
||||
* Joachim Nilsson <troglobit@gmail.com>
|
||||
|
||||
Original Author(s):
|
||||
* Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
|
||||
+551
@@ -0,0 +1,551 @@
|
||||
Change Log
|
||||
==========
|
||||
|
||||
All relevant changes are documented in this file.
|
||||
|
||||
[3.0][UNRELEASED] - 2016-XX-YY
|
||||
------------------------------
|
||||
|
||||
### Changes
|
||||
|
||||
* Manage service states based on user defined conditions
|
||||
* Manage dependencies between services, w/ conditions (pidfile plugin)
|
||||
* Manage service dependenceis on network events (netlink plugin)
|
||||
* Support for dynamically reloading Finit configuration at runtime
|
||||
* Refactor to use GNU configure and build system
|
||||
* New hooks for for detecting lost and started services (lost plugin)
|
||||
* External libraries, libuEv and libite, now build requirements
|
||||
* Early logging support to `/dev/kmsg` instead of console
|
||||
* Support for redirecting stdout/stderr of services to syslog
|
||||
* Support for managing resource limits for Finit and its processes
|
||||
* Add optional built-in inetd services: echo server, chargen, etc.
|
||||
* Add simple built-in getty
|
||||
* Greatly improved accounting support, both UTMP and WTMP fixes+features
|
||||
* Improved udev support, on non-embedded systems
|
||||
* Improvide shutdown and file-system unmount support (Debian)
|
||||
* Added `--enable-emergency-shell` (configure) fallback debug mode
|
||||
* Support SysV init `/etc/rc.local`
|
||||
* Inetd protection against UDP looping attacks
|
||||
* Support systems with `/run` instead of `/var/run` (bootmisc plugin)
|
||||
* Adopted BusyBox init signals for halt/reboot/poweroff
|
||||
* SysV init compat support for reboot (setenv)
|
||||
* Compat support for musl libc
|
||||
* Add OpenRC-like support for sysctl.d/*.conf
|
||||
* Add support for Debian/BusyBox `/etc/network/interfaces`
|
||||
* Add support for running fsck on file systems in `/etc/fstab`
|
||||
* Added example configs + HowTos for Debian (Jessie) and Alpine Linux
|
||||
|
||||
|
||||
[2.4][] - 2015-12-04
|
||||
--------------------
|
||||
|
||||
Bug fix release.
|
||||
|
||||
### Changes
|
||||
|
||||
* Add support for status/show service by `name:id`
|
||||
* Enforce terse mode after boot, if verbose mode is disabled
|
||||
* Reenable verbose mode at reboot, if disabled at boot
|
||||
* Update section mentioning BusyBox getty
|
||||
* Update debugging documentation
|
||||
* Allow debug to override terse mode
|
||||
* Revert confusing change in service state introduced in [v2.3][2.3].
|
||||
As of [v2.4][2.4] services are listed as "halted" and "stopped", when
|
||||
they have been halted due to a runlevel changed or stopped by the
|
||||
user, respectively.
|
||||
|
||||
### Fixes
|
||||
|
||||
* Fix system freeze at reconfiguration. Changed services that
|
||||
all support `SIGHUP` caused a freeze due to Finit waiting for
|
||||
them to stop.
|
||||
* Make sure to start and/or `SIGHUP` services after reconfiguration
|
||||
when there was no services to stop.
|
||||
|
||||
|
||||
[2.3][] - 2015-11-28
|
||||
--------------------
|
||||
|
||||
Bug fix release.
|
||||
|
||||
### Changes
|
||||
|
||||
* Add support for stop/start/restart/reload service by `name:id`
|
||||
* Refactor service status listed in `initctl show`, show actual status
|
||||
|
||||
### Fixes
|
||||
|
||||
* Remove bootstrap-only tasks/services when leaving runlevel 'S'
|
||||
* Fix reference counting issue with already stopped and removed services
|
||||
when the user performs `initctl reload` to change system configuration
|
||||
* Revert semantic change in behavior of `initctl restart`: users expect
|
||||
service to be stopped/started, not reloaded with `SIGHUP` even if the
|
||||
service supports it
|
||||
* Fix `NULL` pointer dereference causing kernel panic when user calls
|
||||
`initctl reload` after change of system configuration
|
||||
* Fix column alignment in output of `initctl show` for services not in
|
||||
current runlevel
|
||||
|
||||
|
||||
[2.2][] - 2015-11-23
|
||||
--------------------
|
||||
|
||||
Lots of fixes to handle static builds, but also fixes for dynamic event
|
||||
handling and reconfiguration at runtime.
|
||||
|
||||
### Changes
|
||||
|
||||
* Upgrade to libuEv v1.2.4, to handle static builds
|
||||
* Upgrade to libite (LITE) v1.2.0, to handle static builds
|
||||
* Clarify how to select different plugins with the configure script
|
||||
* Improve urandom plugin for embedded systems w/o random seed
|
||||
* Add `--debug` flag to `initctl`
|
||||
* The runlevels listed for services in `initctl show` now hightlight the
|
||||
active runlevel.
|
||||
* Clarify in the README and in `initctl help` that the GW event to
|
||||
listen for in service declarations is `GW:UP`
|
||||
|
||||
### Fixes
|
||||
|
||||
* Build fixes for `configure --disable-inetd`
|
||||
* Fixed issue #14: Improved support for static Finit builds
|
||||
* Misc. fixes to silence warnings when building a static Finit
|
||||
* Default to register services as `SIGHUP`'able, regression in v2.0
|
||||
* Call `HOOK_SVC_RECONF` only when all processes have been stopped
|
||||
* On reload/reconf we must wait for all services to stop first
|
||||
* Only trigger on events that matches the service's specification,
|
||||
fix by Tobias Waldekranz
|
||||
|
||||
|
||||
[2.1][] - 2015-10-16
|
||||
--------------------
|
||||
|
||||
### Changes
|
||||
|
||||
* Add hook point for fstab mount failure
|
||||
* Set hostname on dynamic reload
|
||||
* Upgrade to libite v1.1.1
|
||||
|
||||
### Fixes
|
||||
|
||||
* Fix service callback coredump checks and simplify callback exit
|
||||
* Do not use `-Os` use `-O2` as default optimization level. Many cross
|
||||
compiler toolchains are known to have problems with `-Os`
|
||||
* Do not allow build VERSION to be overloaded by an environment variable
|
||||
* Fix too small MAX arguments and too few argments in `svc_t` for
|
||||
reading currently running services with `initctl show`
|
||||
* Unblock blocked signals after forking off a child
|
||||
|
||||
|
||||
[2.0][] - 2015-09-20
|
||||
--------------------
|
||||
|
||||
Support for multiple instances and event based services, as well as the
|
||||
introduction of an `initctl` tool.
|
||||
|
||||
**Note:** Incompatible change to syntax for custom `inetd` services,
|
||||
c.f. Finit v[1.12][].
|
||||
|
||||
### Changes
|
||||
* The most notable change is the support for multiple instances. A must
|
||||
have when running multiple DHCP clients, OpenVPN tunnels, or anything
|
||||
that means using the same command only with different arguments. Now
|
||||
simply add a `:ID` after the `service` keyword, where `ID` is a unique
|
||||
instance number for that service.
|
||||
|
||||
service :1 [2345] /sbin/httpd -f -h /http -p 80 -- Web server
|
||||
service :2 [2345] /sbin/httpd -f -h /http -p 8080 -- Old web server
|
||||
|
||||
* Another noteworthy new feature is support for starting/stopping
|
||||
services on Netlink events:
|
||||
|
||||
service :1 [2345] <!IFUP:eth0,GW> /sbin/dropbear -R -F -p 22 -- SSH daemon
|
||||
|
||||
Here the first instance `:1` of the SSH daemon is declared to run in
|
||||
runlevels 2-5, but only if eth0 `IFUP:eth0` is up and a gateway `GW`
|
||||
is set. When the configuration changes, a new gateway is set, or if
|
||||
somehow a new `IFUP` event for eth0 is received, then dropbear is not
|
||||
SIGHUP'ed, but instead stop-started `<!>`. The latter trick applies
|
||||
to all services, even those that do not define any events.
|
||||
* Support for reloading `*.conf` files in `/etc/finit.d/` on SIGHUP.
|
||||
All `task`, `service` and `run` statements can be used in these .conf
|
||||
files. Use the `telinit q` command, `initctl reload` or simply send
|
||||
`SIGHUP` to PID 1 to reload them. Finit automatically does reload of
|
||||
these `*.conf` files when changing runlevel.
|
||||
* Support for a modern `initctl` tool which can stop/start/reload and
|
||||
list status of all system services. Also, the old client tool used
|
||||
to change runlevel is now also available as a symlink: `telinit`.
|
||||
|
||||
initctl [-v] <status|stop|start|reload|restart> [JOB]
|
||||
|
||||
* Add concept of "jobs". This is a unique identifier, composed of a
|
||||
service and instance number, `SVC:ID`
|
||||
|
||||
initctl <stop|start|reload|restart> JOB
|
||||
|
||||
* Support for *deny filters* in `inetd` services.
|
||||
|
||||
inetd service/proto[@iface,!iface,...] </path/to/cmd | internal[.service]>
|
||||
|
||||
Internal services on a custom port must use the `internal.service`
|
||||
syntax so Finit can properly bind the inetd service to the correct
|
||||
plugin. Here follows a few examples:
|
||||
|
||||
inetd time/udp wait [2345] internal -- UNIX rdate service
|
||||
inetd time/tcp nowait [2345] internal -- UNIX rdate service
|
||||
inetd 3737/tcp nowait [2345] internal.time -- UNIX rdate service
|
||||
inetd telnet/tcp@*,!eth1,!eth0, nowait [2345] /sbin/telnetd -i -F -- Telnet service
|
||||
inetd 2323/tcp@eth1,eth2,eth0 nowait [2345] /sbin/telnetd -i -F -- Telnet service
|
||||
inetd 222/tcp@eth0 nowait [2345] /sbin/dropbear -i -R -F -- SSH service
|
||||
inetd ssh/tcp@*,!eth0 nowait [2345] /sbin/dropbear -i -R -F -- SSH service
|
||||
|
||||
Access to telnet on port `2323` is only possible from interfaces
|
||||
`eth0`, `eth1` and `eth2`. The standard telnet port (`23`) is
|
||||
available from all other interfaces, but also `eth2`. The `*`
|
||||
notation used in the ssh stanza means *any* interface, however, here
|
||||
`eth0` is not allowed.
|
||||
|
||||
**NOTE:** This change breaks syntax compatibility with Finit v[1.12].
|
||||
* Support for a more user-friendly configure script rather than editing
|
||||
the top Makefile, or setting environment variables at build time.
|
||||
* Support for building Finit statically, no external libraries. This
|
||||
unfortunately means that some plugins cannot be built, at all.
|
||||
Big thanks goes to James Mills for all help testing this out!
|
||||
* Support for disabling the built-in inetd server with `configure`.
|
||||
* Support for two new hook points: `HOOK_SVC_RECONF` and
|
||||
`HOOK_RUNLEVEL_CHANGE`. See the source for the exact location.
|
||||
* The `include <FILE>` option now needs an absolute path to `FILE`.
|
||||
|
||||
### Fixes
|
||||
* Rename `patches/` to `contrib/` to simplify integration in 3rd party
|
||||
build systems.
|
||||
* Fix for unwanted zombies ... when receiving SIGCHLD we must reap *all*
|
||||
children. We only receive one signal, but multiple processes may have
|
||||
exited and need to be collected.
|
||||
|
||||
|
||||
[1.12][] - 2015-03-04
|
||||
---------------------
|
||||
|
||||
The inetd release.
|
||||
|
||||
### Changes
|
||||
* Add support for built-in inetd super server -- launch services on
|
||||
demand. Supports filtering per interface and custom Inet ports.
|
||||
* Upgrade to [libuEv] v1.1.0 to better handle error conditions.
|
||||
* Allow mixed case config directives in `finit.conf`
|
||||
* Add support for RFC 868 (rdate) time plugin, start as inetd service.
|
||||
* Load plugins before parsing `finit.conf`, this makes it possible to
|
||||
extend finit even with configuration commands. E.g., the `time.so`
|
||||
plugin must be loaded for the `inetd time/tcp internal` service to be
|
||||
accepted when parsing `finit.conf`.
|
||||
* Slight change in TTY fallback behavior, if no TTY is listed in the
|
||||
system `finit.conf` first inspect the `console` setting and only if
|
||||
that too is unset fall back to `/bin/sh`
|
||||
* When falling back to the `console` TTY or `/bin/sh`, finit now marks
|
||||
this fallback as console. Should improve usability in some use cases.
|
||||
|
||||
### Fixes
|
||||
* Revert "Use vfork() instead of fork() before exec()" from v1.11. It
|
||||
turned out to not work so well after all. For instance, launching
|
||||
TTYs in a background process completely blocked inetd services from
|
||||
even starting up listening sockets ... proper fork seems to work fine
|
||||
though. This is the casue for *yanking* the [1.11] release, below.
|
||||
* Trap segfaults caused by external plugins/callbacks in a sub-process.
|
||||
This prevents a single programming mistake in by a 3rd party developer
|
||||
from taking down the entire system.
|
||||
* Fix Coverity CID 56281: dlopen() resource leak by storing the pointer.
|
||||
For the time being we do not support unloading plugins.
|
||||
* Set hostname early, so bootstrap processes like syslog can use it.
|
||||
* Only restart *lost daemons* when recovering from a SIGSTOP/norespawn.
|
||||
|
||||
|
||||
[1.11][] - 2015-01-24 [YANKED]
|
||||
------------------------------
|
||||
|
||||
The [libuEv] release.
|
||||
|
||||
**Note:** This release has been *yanked* from distribution due to a
|
||||
regression in launching background processes and TTY's. Fixed in
|
||||
Finit v[1.12].
|
||||
|
||||
### Changes
|
||||
* Now using the asynchronous libuEv library for handling all events:
|
||||
signals, timers and listening to sockets or file descriptors.
|
||||
* Rename NEWS.md --> CHANGELOG.md, with symlinks for `make install`
|
||||
* Attempt to align with http://keepachangelog.com/ for this file.
|
||||
* Travis CI now only invokes Coverity Scan from the 'dev' branch. This
|
||||
means that all development, except documentation updates, must go into
|
||||
that branch.
|
||||
|
||||
### Fixes
|
||||
* Fix bug with finit dying when no `tty` is defined in `finit.conf`, now
|
||||
even the fallback shell has control over its TTY, see fix in GIT
|
||||
commit [dea3ae8] for this.
|
||||
|
||||
|
||||
[1.10][] - 2014-11-27
|
||||
---------------------
|
||||
|
||||
Major bug fix release.
|
||||
|
||||
### Changes
|
||||
* Project now relies on static code analysis from Coverity, so this
|
||||
release contains many serious bug fixes.
|
||||
* Convert to use Markdown for README, NEWS and TODO.
|
||||
* Serious update to README and slight pruning of finished TODO items.
|
||||
|
||||
### Fixes
|
||||
* Fix serious file descriptor and memory leaks in the following
|
||||
functions. In particular the leaks in `run_interactive()` are very
|
||||
serious since that function is called every time a service is started
|
||||
and/or restarted! For details, see the GIT log:
|
||||
* `helpers.c:run()`
|
||||
* `helpers.c:run_interactive()`
|
||||
* `helpers.c:set_hostname()`
|
||||
* `helpers.c:procname_kill()`
|
||||
* `svc.c:svc_start()`: Fix swapped arguments to dup2() and add close(fd)
|
||||
to prevent descriptor leak.
|
||||
* `svc.c:svc_start()`: Fix out of bounds write to local stack variable,
|
||||
wrote off-by-one outside array.
|
||||
* Several added checks for return values to `mknod()`, `mkdir()`,
|
||||
`remove()`, etc.
|
||||
|
||||
|
||||
[1.9][] - 2014-04-21
|
||||
--------------------
|
||||
|
||||
### Changes
|
||||
* Add support for an include directive to `.conf` files
|
||||
* Fallback to `/bin/sh` if user forgets tty setting
|
||||
* Initial support for restarting lost services during `norespwan`
|
||||
|
||||
### Fixes
|
||||
* Bug fixes, code cleanup
|
||||
* Handle `SIGHUP` from service callback properly when switching runlevel
|
||||
* Misc. major (memleak) and minor fixes and additions to `libite/lite.h`
|
||||
|
||||
|
||||
[1.8][] - 2013-06-07
|
||||
--------------------
|
||||
|
||||
### Changes
|
||||
* Support for runlevels, with a bootstrap runlevel 'S'
|
||||
* Support for saving previous and current runlevel to UTMP
|
||||
* Support for new `finit.conf` commands: run, task, and runlevel
|
||||
* Support for tty and console commands in `finit.conf`, like services
|
||||
but for launching multiple getty logins
|
||||
* New tty plugin to monitor TTYs coming and going, like USB TTYs
|
||||
|
||||
### Fixes
|
||||
* Bugfixes to libite
|
||||
|
||||
|
||||
[1.7][] - 2012-10-08
|
||||
--------------------
|
||||
|
||||
### Changes
|
||||
* Show `__FILE__` in `_d()` debug messages, useful for plugins with
|
||||
similarily named callbacks. Also, only in debug mode anyway
|
||||
* Make sure to cleanup recorded PID when a service is lost. Required by
|
||||
service plugins for their callbacks to work.
|
||||
* Only clear screen when in verbose mode. Maybe this should be removed
|
||||
altogether?
|
||||
|
||||
### Fixes
|
||||
* Bugfix: Do not `free()` static string in `finit.conf` parser
|
||||
|
||||
|
||||
[1.6][] - 2012-10-06
|
||||
--------------------
|
||||
|
||||
### Changes
|
||||
* Skip `.` and `..` in plugin loader and display error when failing to
|
||||
load plugins
|
||||
* Support for overriding `/etc/finit.d` with `runparts DIR` in
|
||||
`finit.conf`
|
||||
* Revoke support for starting services not starting with a slash.
|
||||
* Prevent endless restart of non-existing services in `finit.conf`
|
||||
* Support for sysvinit style startstop scripts in `/etc/finit.d`
|
||||
|
||||
### Fixes
|
||||
* Minor fix to alsa-utils plugin to silence on non-existing cards
|
||||
|
||||
|
||||
[1.5][] - 2012-10-03
|
||||
--------------------
|
||||
|
||||
### Changes
|
||||
* Use bootmisc plugin to setup standard FHS 2.3 structure in `/var`
|
||||
* Added `FLOG_WARN()` syslog macro, for plugins
|
||||
* Add plugin dependency resolver. Checks `plugin_t` for `.depends`
|
||||
|
||||
|
||||
[1.4][] - 2012-10-02
|
||||
--------------------
|
||||
|
||||
### Changes
|
||||
* Start refactoring helpers.c into a libite.so (-lite). This means
|
||||
other user space applications/daemons can make use of the neat toolbox
|
||||
available in finit
|
||||
* Use short-form -s/-w -u to work with BusyBox hwclock as well
|
||||
* Use RTLD_GLOBAL flag to tell dynamic loader to load dependent .so
|
||||
files as well. Lets other plugins use global symbols.
|
||||
* Greatly simplify svc hook for external plugins and cleanup plugin API.
|
||||
* And more ... see the GIT log for more details.
|
||||
|
||||
### Fixes
|
||||
* Fix I/O plugin watcher and load plugins earlier for a new hook
|
||||
|
||||
|
||||
[1.3][] - 2012-09-28
|
||||
--------------------
|
||||
|
||||
### Changes
|
||||
* Cleanup public plugin API a bit and add new pid/pidfile funcs
|
||||
* Add plugin hook to end of service startup
|
||||
* Remove finit.h from svc.h, plugins should not need this.
|
||||
* Move utility macros etc. to helpers.h
|
||||
* Make `finit.h` daemon internal, only
|
||||
* Move defines of FIFO, conf and rcS.d to Makefile => correct paths
|
||||
* Add support for installing required headers in system include dir
|
||||
* Better support for distributions and packagers with install-exec,
|
||||
install-data, and install-dev targets in Makefile. Useful if you want
|
||||
to call targets with different `$DESTDIR`!
|
||||
* Makefile fixes for installation, paths encoded wrong
|
||||
* Strip binaries + .so files, support for `$(CROSS)` toolchain strip
|
||||
* Default install is now to `/sbin/finit` and `/usr/`
|
||||
* Note change in `$PLUGIN_DIR` environemnt variable to `$plugindir`
|
||||
|
||||
|
||||
[1.2][] - 2012-09-27
|
||||
--------------------
|
||||
|
||||
### Changes
|
||||
* Update README with section on building and enviroment variables
|
||||
|
||||
### Fixes
|
||||
* Fix installation paths encoded in finit binary
|
||||
|
||||
|
||||
[1.1][] - 2012-09-27
|
||||
--------------------
|
||||
|
||||
### Changes
|
||||
* Rename signal.[ch]-->sig.[ch] to avoid name clash w/ system headers
|
||||
|
||||
### Fixes
|
||||
* Build fixes for ARM eabi/uClibc
|
||||
|
||||
|
||||
[1.0][] - 2012-09-26
|
||||
--------------------
|
||||
|
||||
### Changes
|
||||
* New plugin based system for all odd extensions
|
||||
* New service monitor that restarts services if they die
|
||||
* New maintainer at GitHub http://github.com/troglobit/finit
|
||||
* Add standard LICENSE and AUTHORS files
|
||||
* New focus: embedded systems and small headless servers
|
||||
|
||||
|
||||
[0.6][] - 2010-06-14
|
||||
--------------------
|
||||
|
||||
* Don't start consolekit manually, dbus starts it (rtp)
|
||||
* Unmount all filesystems before rebooting
|
||||
* Disable `USE_VAR_RUN_RESOLVCONF` for Mandriva
|
||||
* Unset terminal type in Mandriva before running X
|
||||
* Remove extra sleep in finit-alt before calling services.sh (caio)
|
||||
|
||||
|
||||
[0.5][] - 2008-08-21
|
||||
--------------------
|
||||
|
||||
* Add option to start dbus and consolekit before the X server
|
||||
* finit-alt listens to `/dev/initctl` to work with `reboot(8)` (smurfy)
|
||||
* Write runlevel to utmp, needed by Printerdrake (Pascal Terjan)
|
||||
* Fix ownership of `/var/run/utmp` (reported by Pascal Terjan)
|
||||
* Remove obsolete code to load AGP drivers
|
||||
* Conditional build of `/etc/resolveconf/run` support
|
||||
* Add support to `/var/run/resolvconf` in Mandriva (blino)
|
||||
|
||||
|
||||
[0.4][] - 2008-05-16
|
||||
--------------------
|
||||
|
||||
* Default username for finit-alt configurable in Makefile
|
||||
* Create loopback device node in finit-alt (for squashfs)
|
||||
* Add option to use built-in run-parts instead of `/bin/run-parts`
|
||||
* Ignore signal instead of setting to an empty handler (Metalshark)
|
||||
* Handle pam_console permissions in finit-alt for Mandriva
|
||||
* Add services.sh example and nash-hotplug patch for Mandriva
|
||||
* Mount `/proc/bus/usb` in Mandriva
|
||||
* Add runtime debug to finit-alt if finit_debug parameter is specified
|
||||
* Read configuration from `/etc/finit.conf`
|
||||
* Run getty with openvt on the virtual terminal
|
||||
|
||||
|
||||
[0.3][] - 2008-02-23
|
||||
--------------------
|
||||
|
||||
* Change poweroff method to `reboot(RB_POWER_OFF)` (Metalshark)
|
||||
* Remove duplicate `unionctl()` reimplementation error
|
||||
* Fix string termination in path creation
|
||||
* Mount `/var/lock` and `/var/run` as tmpfs
|
||||
|
||||
|
||||
[0.2][] - 2008-02-19
|
||||
--------------------
|
||||
|
||||
* Replace `system("touch")` with `touch()` in finit-mod (Metalshark)
|
||||
* Disable `NO_HCTOSYS` by default to match stock Eeepc kernel
|
||||
* Drop `system("rm -f")` to clean `/tmp`, its a fresh mounted tmpfs
|
||||
* Write ACPI sleep state to `/sys/power/state` instead of
|
||||
`/proc/acpi/sleep` (Metalshark)
|
||||
* Use direct calls to set loopback instead of `system("ifconfig")`
|
||||
* Replace `system("cat")` and `system("dd")` with C implementation
|
||||
* Moved finit-mod and finit-alt helpers to `helpers.c`
|
||||
* Replace `system("echo;cat")` to draw shutdown splash with C calls
|
||||
|
||||
|
||||
0.1 - 2008-02-14
|
||||
----------------
|
||||
|
||||
* Initial release
|
||||
|
||||
[UNRELEASED]: https://github.com/troglobit/finit/compare/2.4...HEAD
|
||||
[2.4]: https://github.com/troglobit/finit/compare/2.3...2.4
|
||||
[2.3]: https://github.com/troglobit/finit/compare/2.2...2.3
|
||||
[2.2]: https://github.com/troglobit/finit/compare/2.1...2.2
|
||||
[2.1]: https://github.com/troglobit/finit/compare/2.0...2.1
|
||||
[2.0]: https://github.com/troglobit/finit/compare/1.12...2.0
|
||||
[1.12]: https://github.com/troglobit/finit/compare/1.11...1.12
|
||||
[1.11]: https://github.com/troglobit/finit/compare/1.10...1.11
|
||||
[1.10]: https://github.com/troglobit/finit/compare/1.9...1.10
|
||||
[1.9]: https://github.com/troglobit/finit/compare/1.8...1.9
|
||||
[1.8]: https://github.com/troglobit/finit/compare/1.7...1.8
|
||||
[1.7]: https://github.com/troglobit/finit/compare/1.6...1.7
|
||||
[1.6]: https://github.com/troglobit/finit/compare/1.5...1.6
|
||||
[1.5]: https://github.com/troglobit/finit/compare/1.4...1.5
|
||||
[1.4]: https://github.com/troglobit/finit/compare/1.3...1.4
|
||||
[1.3]: https://github.com/troglobit/finit/compare/1.2...1.3
|
||||
[1.2]: https://github.com/troglobit/finit/compare/1.1...1.2
|
||||
[1.1]: https://github.com/troglobit/finit/compare/1.0...1.1
|
||||
[1.0]: https://github.com/troglobit/finit/compare/0.9...1.0
|
||||
[0.9]: https://github.com/troglobit/finit/compare/0.8...0.9
|
||||
[0.8]: https://github.com/troglobit/finit/compare/0.7...0.8
|
||||
[0.7]: https://github.com/troglobit/finit/compare/0.6...0.7
|
||||
[0.6]: https://github.com/troglobit/finit/compare/0.5...0.6
|
||||
[0.5]: https://github.com/troglobit/finit/compare/0.4...0.5
|
||||
[0.4]: https://github.com/troglobit/finit/compare/0.3...0.4
|
||||
[0.3]: https://github.com/troglobit/finit/compare/0.2...0.3
|
||||
[0.2]: https://github.com/troglobit/finit/compare/0.1...0.2
|
||||
[libuEv]: https://github.com/troglobit/libuev
|
||||
[dea3ae8]: https://github.com/troglobit/finit/commit/dea3ae8
|
||||
|
||||
<!--
|
||||
-- Local Variables:
|
||||
-- mode: markdown
|
||||
-- End:
|
||||
-->
|
||||
@@ -1,31 +0,0 @@
|
||||
O.4 (20080516)
|
||||
- default username for finit-alt configurable in Makefile
|
||||
- create loopback device node in finit-alt (for squashfs)
|
||||
- add option to use built-in run-parts instead of /bin/run-parts
|
||||
- ignore signal instead of setting to an empty handler (Metalshark)
|
||||
- handle pam_console permissions in finit-alt for Mandriva
|
||||
- add services.sh example and nash-hotplug patch for Mandriva
|
||||
- mount /proc/bus/usb in Mandriva
|
||||
- add runtime debug to finit-alt if finit_debug parameter is specified
|
||||
- read configuration from /etc/finit.conf
|
||||
- run getty with openvt on the virtual terminal
|
||||
|
||||
0.3 (20080223)
|
||||
- Change poweroff method to reboot(RB_POWER_OFF) (Metalshark)
|
||||
- Remove duplicate unionctl() reimplementation error
|
||||
- Fix string termination in path creation
|
||||
- Mount /var/lock and /var/run as tmpfs
|
||||
|
||||
0.2 (20080219)
|
||||
- replace system("touch") with touch() in finit-mod (Metalshark)
|
||||
- disable NO_HCTOSYS by default to match stock Eeepc kernel
|
||||
- drop system("rm -f") to clean /tmp, its a fresh mounted tmpfs
|
||||
- write ACPI sleep state to /sys/power/state instead of
|
||||
/proc/acpi/sleep (Metalshark)
|
||||
- use direct calls to set loopback instead of system("ifconfig")
|
||||
- replace system("cat") and system("dd") with C implementation
|
||||
- moved finit-mod and finit-alt helpers to helpers.c
|
||||
- replace system("echo;cat") to draw shutdown splash with C calls
|
||||
|
||||
0.1 (20081214)
|
||||
- initial release
|
||||
@@ -0,0 +1,20 @@
|
||||
Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -1,77 +0,0 @@
|
||||
CC = gcc
|
||||
CFLAGS = -Os -Wall -DVERSION=\"$(VERSION)\" -DWHOAMI=\"`whoami`@`hostname`\"
|
||||
LD = gcc
|
||||
LDFLAGS =
|
||||
LIBS =
|
||||
VERSION = 0.4
|
||||
PKG = finit-$(VERSION)
|
||||
DFILES = Makefile README finit.c finit-mod.c finit-alt.c helpers.c helpers.h \
|
||||
patches/*patch contrib/services.sh*
|
||||
BINS = finit finit-mod finit-mdv
|
||||
|
||||
|
||||
|
||||
#### Configurable parameters
|
||||
|
||||
# Default user for finit-alt if not "user"
|
||||
#DEFUSER = fred
|
||||
|
||||
# Use -march=pentium-m to build for Eeepc
|
||||
CFLAGS += -march=pentium-m
|
||||
|
||||
# Omit the first /sbin/hwclock if CONFIG_RTC_HCTOSYS is enabled in the kernel
|
||||
#CFLAGS += -DNO_HCTOSYS
|
||||
|
||||
# Append -directisa to /sbin/hwclock lines if the user has disabled
|
||||
# CONFIG_GENRTC and enabled CONFIG_RTC but not enabled CONFIG_HPET_TIMER
|
||||
# and CONFIG_HPET_RTC_IRQ.
|
||||
#CFLAGS += -DDIRECTISA
|
||||
|
||||
# Use built-in run-parts instead of /bin/run-parts
|
||||
CFLAGS += -DBUILTIN_RUNPARTS
|
||||
|
||||
#### End of configurable parameters
|
||||
|
||||
|
||||
|
||||
ifneq ($(DEFUSER),)
|
||||
CFLAGS += -DDEFUSER=\"$(DEFUSER)\"
|
||||
endif
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(CFLAGS) -o $*.o $<
|
||||
|
||||
all: $(BINS)
|
||||
|
||||
finit: finit.o
|
||||
$(LD) $(LDFLAGS) -o $@ $+ $(LIBS)
|
||||
strip $@
|
||||
|
||||
finit-mod: finit-mod.o helpers.o
|
||||
$(LD) $(LDFLAGS) -o $@ $+ $(LIBS)
|
||||
strip $@
|
||||
|
||||
finit-mdv: finit-mdv.o helpers.o
|
||||
$(LD) $(LDFLAGS) -o $@ $+ $(LIBS)
|
||||
strip $@
|
||||
|
||||
finit-mdv.o: finit-alt.c Makefile
|
||||
$(CC) -c $(CFLAGS) -DDIST_MDV -o $@ finit-alt.c
|
||||
|
||||
clean:
|
||||
rm -f *.o core *~ $(BINS)
|
||||
|
||||
finit.o: finit.c Makefile
|
||||
|
||||
finit-mod.o: finit-mod.c Makefile
|
||||
|
||||
helpers.o: helpers.c Makefile
|
||||
|
||||
dist:
|
||||
rm -Rf $(PKG)
|
||||
mkdir -p $(PKG)/contrib $(PKG)/patches
|
||||
for i in $(DFILES); do cp $$i $(PKG)/`dirname $$i`; done
|
||||
tar cf - $(PKG) | gzip -c > $(PKG).tar.gz
|
||||
rm -Rf $(PKG)
|
||||
ls -l $(PKG).tar.gz
|
||||
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
sbin_PROGRAMS = finit initctl reboot
|
||||
finit_SOURCES = api.c \
|
||||
cond.c cond-w.c cond.h \
|
||||
client.c \
|
||||
conf.c conf.h \
|
||||
exec.c finit.c finit.h \
|
||||
getty.c \
|
||||
helpers.c helpers.h \
|
||||
mdadm.c mount.c pid.c \
|
||||
plugin.c plugin.h private.h \
|
||||
service.c service.h \
|
||||
sig.c sig.h \
|
||||
sm.c sm.h \
|
||||
svc.c svc.h \
|
||||
tty.c tty.h \
|
||||
util.c util.h \
|
||||
utmp-api.c utmp-api.h
|
||||
pkginclude_HEADERS = cond.h finit.h helpers.h inetd.h plugin.h svc.h
|
||||
if INETD
|
||||
finit_SOURCES += inetd.c inetd.h
|
||||
endif
|
||||
if WATCHDOGD
|
||||
finit_SOURCES += watchdog.c watchdog.h
|
||||
endif
|
||||
|
||||
finit_CFLAGS = -W -Wall -Wextra -std=gnu99 $(lite_CFLAGS) $(uev_CFLAGS)
|
||||
finit_LDADD = $(lite_LIBS) $(uev_LIBS)
|
||||
if STATIC
|
||||
finit_LDADD += plugins/libplug.la
|
||||
else
|
||||
finit_LDADD += -ldl
|
||||
endif
|
||||
|
||||
initctl_SOURCES = initctl.c svc.c svc.h helpers.c helpers.h cond.c cond.h \
|
||||
util.c util.h utmp-api.c utmp-api.h
|
||||
initctl_CFLAGS = $(lite_CFLAGS)
|
||||
initctl_LDADD = $(lite_LIBS)
|
||||
|
||||
reboot_SOURCES = reboot.c util.c util.h
|
||||
|
||||
INIT_LNKS = telinit init
|
||||
REBOOT_LNKS = shutdown halt poweroff suspend
|
||||
SUBDIRS = plugins
|
||||
doc_DATA = README.md LICENSE finit.conf
|
||||
EXTRA_DIST = README.md LICENSE ChangeLog.md finit.conf
|
||||
AM_CPPFLAGS = -U_FORTIFY_SOURCE
|
||||
AM_CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
|
||||
|
||||
if STATIC
|
||||
AM_CPPFLAGS += -DENABLE_STATIC
|
||||
AM_LDFLAGS = -static-libtool-libs
|
||||
else
|
||||
AM_CPPFLAGS += -DPLUGIN_PATH=\"$(pkglibdir)\"
|
||||
AM_LDFLAGS = -export-dynamic
|
||||
endif
|
||||
|
||||
# Compat hook
|
||||
install-dev: install-pkgincludeHEADERS
|
||||
|
||||
# Hook in install to add finit and reboot symlink(s)
|
||||
install-exec-hook:
|
||||
@for file in $(INIT_LNKS); do \
|
||||
lnk=$(DESTDIR)$(sbindir)/$$file; \
|
||||
if [ -e $$lnk ]; then \
|
||||
echo "Skipping $$lnk exists already."; \
|
||||
else \
|
||||
$(LN_S) finit $$lnk; \
|
||||
fi; \
|
||||
done
|
||||
@if [ -L $(DESTDIR)$(sbindir)/reboot ]; then \
|
||||
echo "Non-finit reboot, skipping install."; \
|
||||
else \
|
||||
for file in $(REBOOT_LNKS); do \
|
||||
link=$(DESTDIR)$(sbindir)/$$file; \
|
||||
if [ -e $$link ]; then \
|
||||
echo "$$link exists, skipping.";\
|
||||
else \
|
||||
$(LN_S) reboot $$link; \
|
||||
fi; \
|
||||
done; \
|
||||
fi
|
||||
|
||||
uninstall-hook:
|
||||
@for file in $(INIT_LNKS); do \
|
||||
lnk=`readlink $(DESTDIR)$(sbindir)/$$file`; \
|
||||
if [ "$$lnk" != "finit" ]; then \
|
||||
echo "Skipping non-finit $$file."; \
|
||||
continue; \
|
||||
fi; \
|
||||
$(RM) $(DESTDIR)$(sbindir)/$$file; \
|
||||
done
|
||||
@if [ -L $(DESTDIR)$(sbindir)/reboot ]; then \
|
||||
echo "Non-finit reboot, skipping uninstall."; \
|
||||
else \
|
||||
for file in $(REBOOT_LNKS); do \
|
||||
if [ "`readlink $$file`" != "reboot" ]; \
|
||||
then continue; \
|
||||
fi; \
|
||||
$(RM) $(DESTDIR)$(sbindir)/$$file; \
|
||||
done; \
|
||||
fi
|
||||
|
||||
# Target to run when building a release
|
||||
release: dist
|
||||
@for file in $(DIST_ARCHIVES); do \
|
||||
md5sum $$file > ../$$file.md5; \
|
||||
done
|
||||
@mv $(DIST_ARCHIVES) ../
|
||||
@echo
|
||||
@echo "Resulting release files:"
|
||||
@echo "================================================================="
|
||||
@for file in $(DIST_ARCHIVES); do \
|
||||
printf "$$file \tDistribution tarball\n"; \
|
||||
printf "$$file.md5\t"; cat ../$$file.md5 | cut -f1 -d' '; \
|
||||
done
|
||||
@@ -1,68 +0,0 @@
|
||||
|
||||
Eeepc "fastinit" reimplementations
|
||||
----------------------------------
|
||||
|
||||
finit.c is a reimplementation of the Asus Eeepc fastinit program based
|
||||
on its library calls. It tries to be an accurate re-creation and keeps
|
||||
the original bugs and unoptimized calls.
|
||||
|
||||
finit-mod.c is a fixed/improved version of finit.c intended to be a drop-in
|
||||
replacement for the original Eeepc OS.
|
||||
|
||||
finit-alt.c is a fixed/improved version of finit.c for alternative Linux
|
||||
distributions running on the Eeepc (previously ffinit.c). It's currently
|
||||
able to boot Mandriva Linux 2008.0/2008.1.
|
||||
|
||||
See Makefile for configurable parameters to better suit your system.
|
||||
|
||||
|
||||
* Eeepc boot process
|
||||
|
||||
The essential steps in the boot process carried out in initramfs are:
|
||||
|
||||
ROOT=`sed 's!.*root=\([^ ]*\).*!\1!' < /proc/cmdline`
|
||||
mount -t proc proc /proc
|
||||
mount -t ext2 -o ro $ROOT /mnt-system
|
||||
mount -t ext3 -o rw /dev/sda2 /mnt-user
|
||||
mount -t unionfs -o dirs=/mnt-user=rw:/mnt-system=ro unionfs /mnt
|
||||
mount --move /mnt-system /mnt/mnt
|
||||
umount -l /mnt-user
|
||||
umount /proc
|
||||
exec switch_root /mnt /sbin/fastinit "$@" </mnt/dev/console >/mnt/dev/console
|
||||
|
||||
If mounting the root filesystem fails, execute a maintenance shell. If
|
||||
mounting the user filesystem fails, fsck and reboot.
|
||||
|
||||
|
||||
* Utilities available in the Eeepc initramfs busybox:
|
||||
|
||||
[ cat cp cut dd
|
||||
dmesg echo env expr false
|
||||
grep insmod ln losetup ls
|
||||
mdev mkdir mknod mount mv
|
||||
pivot_root realpath rm rmmod sed
|
||||
sh sleep switch_root test true
|
||||
umount vi
|
||||
|
||||
|
||||
* Devices in the Eeepc initramfs /dev:
|
||||
|
||||
console fb null ram0 sda1 sda2 sda3 sr0 tty0
|
||||
|
||||
|
||||
Reboot and poweroff
|
||||
-------------------
|
||||
|
||||
Stock reboot and poweroff utilities of a modern Linux distribution may not
|
||||
work correctly with finit. You can replace them with simple scripts that
|
||||
send SIGUSR1 to finit for reboot, SIGUSR2 for poweroff.
|
||||
|
||||
|
||||
Using finit with KDE
|
||||
--------------------
|
||||
|
||||
If you use finit to start KDE with auto-login enabled, hal-based device
|
||||
automounting may not work correctly. That happens because the session
|
||||
is started before the system message bus, so add a "dcop kded mediamanager
|
||||
reloadBackends" call in the user AutoStart to restart the client.
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
|
||||
Mandriva 2008
|
||||
-------------
|
||||
|
||||
1 - Add init=/sbin/finit-mdv to the kernel boot line
|
||||
|
||||
2 - Provide a suitable /usr/sbin/services.sh, this is the one I use in my
|
||||
test system running e17:
|
||||
|
||||
mkdir /var/lock/subsys
|
||||
chmod 1777 /var/lock/subsys
|
||||
/etc/init.d/network start
|
||||
dhclient eth0
|
||||
/sbin/start_udev&
|
||||
/etc/init.d/portmap start
|
||||
/etc/init.d/nfs-common start
|
||||
|
||||
If you use KDE or need more services, see examples in contrib/
|
||||
|
||||
3 - Create /etc/finit.conf with user, module, filesystems to check and
|
||||
hostname parameters. See the included finit.conf for more information.
|
||||
If no user is specified, user "user" will be used as default.
|
||||
|
||||
4 - Set the pointer device in the X server configuration to /dev/input/mice
|
||||
|
||||
|
||||
|
||||
Mandriva 2008.1
|
||||
---------------
|
||||
|
||||
If you have a stuck nash-hotplug consuming 100% of CPU after the boot, you
|
||||
may want to patch mkinitrd using patches/mkinitrd-6.0.34-nash-hotplug.patch
|
||||
|
||||
@@ -0,0 +1,427 @@
|
||||
<p align="center"><img src="images/finit3.png" alt="Finit: Fast Init" /></p>
|
||||
|
||||
Table of Contents
|
||||
-----------------
|
||||
[![Travis Status]][Travis] [![Coverity Status]][Coverity Scan]
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [Features](#features)
|
||||
* [/etc/finit.conf](doc/config.md#etcfinitconf)
|
||||
* [/etc/finit.d](doc/config.md#etcfinitd)
|
||||
* [Runparts & /etc/rc.local](#runparts--etcrclocal)
|
||||
* [Bootstrap](doc/bootstrap.md#bootstrap)
|
||||
* [Runlevels](#runlevels)
|
||||
* [Inetd](doc/inetd.md#inetd)
|
||||
* [Hooks, Callbacks & Plugins](doc/plugins.md#hooks-callbacks--plugins)
|
||||
* [Rebooting & Halting](#rebooting--halting)
|
||||
* [Commands & Status](#commands--status)
|
||||
* [Building](doc/build.md#building)
|
||||
* [Requirements](#requirements)
|
||||
* [Running](#running)
|
||||
* [Debugging](#debugging)
|
||||
* [Origin & References](#origin--references)
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Finit is an EeePC Fastinit inspired clone with [process supervision][1]
|
||||
similar to that of D.J. Bernstein's [daemontools][2] and Gerrit Pape's
|
||||
[runit][3]. It also supports free-form conditions based on events, e.g.
|
||||
triggering on PID file creation, Netlink events like a default route or
|
||||
interfaces coming up, or even custom events. Similar to [systemd][6].
|
||||
|
||||
Finit focuses on small and embedded Linux systems, although fully usable
|
||||
on servers and desktops as well. See the [contrib section](contrib/)
|
||||
for Debian and Alpine Linux examples.
|
||||
|
||||
Traditional [SysV init][4] style systems are scripted. For low-resource
|
||||
embedded systems this is quite resource intensive and often leads to
|
||||
long boot times. Finit reduces context switches and forking of shell
|
||||
scripts to provide a swift [system bootstrap](doc/bootstrap.md) written
|
||||
entirely in C.
|
||||
|
||||
Configuration is read from [/etc/finit.conf](doc/config.md#etcfinitconf)
|
||||
which details kernel modules to load, services and TTYs to start. When
|
||||
initial [bootstrap](doc/bootstrap.md) is done, including setting up
|
||||
networking, [/etc/finit.d/](doc/config.md#etcfinitd) and the familiar
|
||||
[/etc/rc.local](#runparts--etcrclocal) are run.
|
||||
|
||||
**Example /etc/finit.conf:**
|
||||
|
||||
```
|
||||
# Fallback if /etc/hostname is missing
|
||||
host wopr
|
||||
|
||||
# Runlevel to start after bootstrap, runlevel 'S'
|
||||
runlevel 2
|
||||
|
||||
# Services to be monitored and respawned as needed
|
||||
service [S12345] /sbin/watchdogd -L -f -- System watchdog daemon
|
||||
service [S12345] /sbin/syslogd -n -b 3 -D -- System log daemon
|
||||
service [S12345] /sbin/klogd -n -- Kernel log daemon
|
||||
service [2345] /sbin/lldpd -d -c -M1 -H0 -i -- LLDP daemon (IEEE 802.1ab)
|
||||
|
||||
# For multiple instances of the same service, add :ID somewhere between
|
||||
# the service/run/task keyword and the command.
|
||||
service :1 [2345] /sbin/merecat -n -p 80 /var/www -- Web server
|
||||
service :2 [2345] /sbin/merecat -n -p 8080 /var/www -- Old web server
|
||||
|
||||
# Alternative method instead of below runparts, can also use /etc/rc.local
|
||||
#task [S] /etc/init.d/keyboard-setup start -- Setting up preliminary keymap
|
||||
#task [S] /etc/init.d/acpid start -- Starting ACPI Daemon
|
||||
#task [S] /etc/init.d/kbd start -- Preparing console
|
||||
|
||||
# Inetd services to start on demand, with alternate ports and filtering
|
||||
inetd ftp/tcp nowait [2345] /sbin/uftpd -i -f -- FTP daemon
|
||||
inetd tftp/udp wait [2345] /sbin/uftpd -i -y -- TFTP daemon
|
||||
inetd time/udp wait [2345] internal -- UNIX rdate service
|
||||
inetd time/tcp nowait [2345] internal -- UNIX rdate service
|
||||
inetd 3737/tcp nowait [2345] internal.time -- UNIX rdate service
|
||||
inetd telnet/tcp nowait [2345] /sbin/telnetd -i -F -- Telnet daemon
|
||||
inetd 2323/tcp nowait [2345] /sbin/telnetd -i -F -- Telnet daemon
|
||||
inetd 222/tcp@eth0 nowait [2345] /sbin/dropbear -i -R -F -- SSH service
|
||||
inetd ssh/tcp@*,!eth0 nowait [2345] /sbin/dropbear -i -R -F -- SSH service
|
||||
|
||||
# Run start scripts from this directory
|
||||
# runparts /etc/start.d
|
||||
|
||||
# Virtual consoles to start built-in getty on
|
||||
tty [12345] /dev/tty1 115200 linux
|
||||
tty [12345] /dev/ttyAMA0 115200 vt100
|
||||
```
|
||||
|
||||
For an example of a full blown embedded Linux, see [TroglOS][9], or take
|
||||
a look at the `contrib/` section with [Alpine Linux](contrib/alpine/),
|
||||
[Debian](contrib/debian/), support and more.
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
**Process Supervision**
|
||||
|
||||
Start, monitor and restart services should they fail.
|
||||
|
||||
**Inetd**
|
||||
|
||||
Finit comes with a built-in [inetd server](doc/inetd.md). No need to
|
||||
maintain a separate config file for services that you want to start on
|
||||
demand.
|
||||
|
||||
All inetd services started can be filtered per port and inbound
|
||||
interface, reducing the need for a full blown firewall.
|
||||
|
||||
Built-in optional inetd services:
|
||||
|
||||
- echo RFC862
|
||||
- chargen RFC864
|
||||
- daytime RFC867
|
||||
- discard RFC863
|
||||
- time (rdate) RFC868
|
||||
|
||||
For more information, see [doc/inetd.md](doc/inetd.md).
|
||||
|
||||
**Getty**
|
||||
|
||||
Finit also comes with a built-in Getty for Linux console TTYs. It can
|
||||
parse `/etc/inittab` and set the speed. Then `/bin/login` handles all
|
||||
nasty bits with PAM etc.
|
||||
|
||||
# /etc/finit.conf
|
||||
tty [12345] /dev/tty1 38400 linux
|
||||
tty [12345] /dev/ttyAMA0 115200 vt100
|
||||
|
||||
**Runlevels**
|
||||
|
||||
Support for SysV init-style [runlevels][5] is available, in the same
|
||||
minimal style as everything else in Finit. The `[2345]` syntax can be
|
||||
applied to service, task, run, inetd, and TTY stanzas.
|
||||
|
||||
All services in runlevel S(1) are started first, followed by the desired
|
||||
run-time runlevel. Runlevel S can be started in sequence by using `run
|
||||
[S] cmd`. Changing runlevels at runtime is done like any other init,
|
||||
e.g. <kbd>init 4</kbd>, but also using the more advanced `intictl` tool.
|
||||
|
||||
|
||||
**Plugins**
|
||||
|
||||
Plugins can *extend* the functionality of Finit and *hook into* the
|
||||
different stages of the boot process and at runtime. Plugins are
|
||||
written in C and compiled into a dynamic library loaded automatically by
|
||||
finit at boot. A basic set of plugins are bundled in the `plugins/`
|
||||
directory.
|
||||
|
||||
Capabilities:
|
||||
|
||||
- **Hooks**
|
||||
Hook into the boot at predefined points to extend Finit
|
||||
- **I/O**
|
||||
Listen to external events and control Finit behavior/services
|
||||
- **Inetd**
|
||||
Extend Finit with internal inetd services, for an example, see
|
||||
`plugins/time.c`
|
||||
|
||||
Extensions and functionality not purely related to what an `/sbin/init`
|
||||
needs to start a system are available as a set of plugins that either
|
||||
hook into the boot process or respond to various I/O.
|
||||
|
||||
For more information, see [doc/plugins.md](doc/plugins.md).
|
||||
|
||||
|
||||
Runparts & /etc/rc.local
|
||||
------------------------
|
||||
|
||||
At the end of the boot, when networking and all services are up, Finit
|
||||
calls its built-in [run-parts(8)][] on the `runparts <DIR>` directory,
|
||||
and `/etc/rc.local`, in that order if they exist.
|
||||
|
||||
```shell
|
||||
runparts /etc/rc.d/
|
||||
```
|
||||
|
||||
No configuration stanza in `/etc/finit.conf` is required for `rc.local`.
|
||||
If it exists and is an executable shell script, finit calls it at the
|
||||
very end of the boot, before calling the `HOOK_SYSTEM_UP`. See more on
|
||||
hooks in [doc/plugins.md](doc/plugins.md#hooks), and about the system
|
||||
bootstrap in [doc/bootstrap.md](doc/bootstrap.md).
|
||||
|
||||
|
||||
Runlevels
|
||||
---------
|
||||
|
||||
Basic support for [runlevels][5] is included in Finit from v1.8. By
|
||||
default all services, tasks, run commands and TTYs listed without a set
|
||||
of runlevels get a default set `[234]` assigned. The default runlevel
|
||||
after boot is 2.
|
||||
|
||||
Finit supports runlevels 0-9, and S, with 0 reserved for halt, 6 reboot
|
||||
and S for services to only run at bootstrap. Runlevel 1 is the single
|
||||
user level, where usually no networking is enabled. In Finit this is
|
||||
more of a policy for the user to define. Normally only runlevels 1-6
|
||||
are used, and even more commonly, only the default runlevel is used.
|
||||
|
||||
To specify an allowed set of runlevels for a `service`, `run` command,
|
||||
`task`, or `tty`, add `[NNN]` to your `/etc/finit.conf`, like this:
|
||||
|
||||
```
|
||||
service [S12345] /sbin/syslogd -n -x -- System log daemon
|
||||
run [S] /etc/init.d/acpid start -- Starting ACPI Daemon
|
||||
task [S] /etc/init.d/kbd start -- Preparing console
|
||||
service [S12345] /sbin/klogd -n -x -- Kernel log daemon
|
||||
tty [12345] /dev/tty1
|
||||
tty [2] /dev/tty2
|
||||
tty [2] /dev/tty3
|
||||
tty [2] /dev/tty4
|
||||
tty [2] /dev/tty5
|
||||
tty [2] /dev/tty6
|
||||
```
|
||||
|
||||
In this example syslogd is first started, in parallel, and then acpid is
|
||||
called using a conventional SysV init script. It is called with the run
|
||||
command, meaning the following task command to start the kbd script is
|
||||
not called until the acpid init script has fully completed. Then the
|
||||
keyboard setup script is called in parallel with klogd as a monitored
|
||||
service.
|
||||
|
||||
Again, tasks and services are started in parallel, while run commands
|
||||
are called in the order listed and subsequent commands are not started
|
||||
until a run command has completed.
|
||||
|
||||
Switching between runlevels can be done by calling init with a single
|
||||
argument, e.g. <kbd>init 5</kbd> switches to runlevel 5. When changing
|
||||
runlevels Finit also automatically reloads all `.conf` files in the
|
||||
`/etc/finit.d/` directory. So if you want to set a new system config,
|
||||
switch to runlevel 1, change all config files in the system, and touch
|
||||
all `.conf` files in `/etc/finit.d` before switching back to the
|
||||
previous runlevel again — that way Finit can both stop old services and
|
||||
start any new ones for you, without rebooting the system.
|
||||
|
||||
|
||||
Rebooting & Halting
|
||||
-------------------
|
||||
|
||||
Traditionally, rebooting and halting a UNIX system is done by changing
|
||||
its runlevel. Finit comes with its own tooling providing: `shutdown`,
|
||||
`reboot`, `poweroff`, and `suspend`, but also the traditional `init` and
|
||||
`telinit`, as well as a more modern `initctl` tool, detailed in the next
|
||||
section.
|
||||
|
||||
For compatibility reasons Finit listens to the same set of signals as
|
||||
BusyBox init. This is not 100% compatible with SysV init, but clearly
|
||||
the more common combination for Finit. For more details, see
|
||||
[doc/signals.md](doc/signals.md).
|
||||
|
||||
Finit also listens to the classic SysV init FIFO, used by `telinit`.
|
||||
Support for this is implemented by the `initctl.so` plugin. Hence,
|
||||
`telinit q` will work as the UNIX beards intended.
|
||||
|
||||
~ # telinit -h
|
||||
Usage: telinit [OPTIONS] [q | Q | 0-9]
|
||||
|
||||
Options:
|
||||
-h, --help This help text
|
||||
-V, --version Show Finit version
|
||||
|
||||
Commands:
|
||||
0 Power-off the system, same as initctl poweroff
|
||||
6 Reboot the system, same as initctl reboot
|
||||
2, 3, 4, 5 Change runlevel. Starts services in new runlevel, stops any
|
||||
services in prev. runlevel that are not allowed in new.
|
||||
q, Q Reload *.conf in /etc/finit.d/, same as initctl reload or
|
||||
sending SIGHUP to PID 1
|
||||
1, s, S Enter system rescue mode, runlevel 1
|
||||
|
||||
|
||||
Commands & Status
|
||||
-----------------
|
||||
|
||||
Finit also implements a more modern API to query status, and start/stop
|
||||
services, called `initctl`. Unlike `telinit` the `initctl` tool does
|
||||
not return until the given command has fully completed.
|
||||
|
||||
~ $ initctl -h
|
||||
Usage: initctl [OPTIONS] <COMMAND>
|
||||
|
||||
Options:
|
||||
-d, --debug Debug initctl (client)
|
||||
-v, --verbose Verbose output
|
||||
-h, --help This help text
|
||||
|
||||
Commands:
|
||||
debug Toggle Finit (daemon) debug
|
||||
help This help text
|
||||
reload Reload *.conf in /etc/finit.d/ and activate changes
|
||||
runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot
|
||||
status | show Show status of services
|
||||
cond set <COND> Set (assert) condition => +COND
|
||||
cond clear <COND> Clear (deassert) condition => -COND
|
||||
cond flux <COND> Emulate flux condition => ~COND
|
||||
cond show Show condition status
|
||||
start <JOB|NAME>[:ID] Start service by job# or name, with optional ID
|
||||
stop <JOB|NAME>[:ID] Stop/Pause a running service by job# or name
|
||||
restart <JOB|NAME>[:ID] Restart (stop/start) service by job# or name
|
||||
reload <JOB|NAME>[:ID] Reload (SIGHUP) service by job# or name
|
||||
version Show Finit version
|
||||
|
||||
For services *not* supporting `SIGHUP` the `<!>` notation in the .conf
|
||||
file must be used to tell Finit to stop and start it on `reload` and
|
||||
`runlevel` changes. If `<>` holds more [conditions](doc/conditions.md),
|
||||
these will also affect how a service is maintained.
|
||||
|
||||
**Note:** even though it is possible to start services not belonging in
|
||||
the 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.
|
||||
|
||||
~ $ initctl status -v
|
||||
1 running 476 [S12345] /sbin/watchdog -T 16 -t 2 -F /dev/watchdog
|
||||
2 running 477 [S12345] /sbin/syslogd -n -b 3 -D
|
||||
3 running 478 [S12345] /sbin/klogd -n
|
||||
4:1 inetd 0 [2345] internal time allow *:37
|
||||
4:2 inetd 0 [2345] internal time allow *:37
|
||||
4:3 inetd 0 [2345] internal 3737 allow *:3737
|
||||
5:1 inetd 0 [2345] /sbin/telnetd allow *:23 deny eth0,eth1
|
||||
5:2 inetd 0 [2345] /sbin/telnetd allow eth0:2323,eth2:2323,eth1:2323
|
||||
6:1 inetd 0 [345] /sbin/dropbear allow eth0:222
|
||||
6:2 inetd 0 [345] /sbin/dropbear allow *:22 deny eth0
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
Finit is capable of running on both desktop/server systems with udev and
|
||||
embedded systems that usually come with BusyBox mdev. Finit probes for
|
||||
them at runtime and expects `/dev/` to be writable, usually `devtmpfs`.
|
||||
It is also possible to run on a statically set up `/dev` if needed. It
|
||||
is however not a good idea to have both udev and mdev installed at the
|
||||
same time, this will lead to unpredictable results.
|
||||
|
||||
At boot Finit calls either `mdev` or `udevd` to populate `/dev`, this is
|
||||
done slightly differently and on systems with udev you might want to add
|
||||
the following one-shot task early in your `/etc/finit.conf`:
|
||||
|
||||
run [S] /sbin/udevadm settle --timeout=120 -- Waiting for udev
|
||||
|
||||
Finit has a built-in Getty for TTYs, but requires a working `/bin/login`
|
||||
or `/bin/sh`, if no TTYs are configured in `/etc/finit.conf`.
|
||||
|
||||
For a fully operational system `/var`, `/run` and `/tmp` must be set up
|
||||
properly in `/etc/fstab` -- which is iterated over at boot.
|
||||
|
||||
The built-in Inetd requires `/etc/services` and `/etc/protocols` to work
|
||||
with port names rather than numbers.
|
||||
|
||||
|
||||
Running
|
||||
-------
|
||||
|
||||
Having successfully [built Finit](doc/build.md) it may now be time to
|
||||
take it for a test drive. The `make install` attempts to set up finit
|
||||
as the system system init, `/sbin/init`, but this is usually a symlink
|
||||
pointing to the current init.
|
||||
|
||||
So either change the symlink, or change your boot loader (GRUB, LOADLIN,
|
||||
LILO, U-Boot/Barebox or RedBoot) configuration to append the following
|
||||
to the kernel command line:
|
||||
|
||||
```shell
|
||||
append="init=/sbin/finit"
|
||||
```
|
||||
|
||||
Remember to also set up an initial `/etc/finit.conf` before rebooting!
|
||||
|
||||

|
||||
|
||||
|
||||
Debugging
|
||||
---------
|
||||
|
||||
Add `finit_debug`, or `--debug`, to the kernel command line to enable
|
||||
debug messages.
|
||||
|
||||
```shell
|
||||
append="init=/sbin/finit --debug"
|
||||
```
|
||||
|
||||
To debug startup issues, in particular issues with getty/login, try
|
||||
`configure --enable-fallback-shell`. When no TTYs are detected, and
|
||||
Finit is configured with this option, Finit will try to start a bare
|
||||
`/bin/sh` on the boot console.
|
||||
|
||||
|
||||
Origin & References
|
||||
-------------------
|
||||
|
||||
This project is based on the [original finit][] by [Claudio Matsuoka][]
|
||||
which was reverse engineered from syscalls of the [EeePC fastinit][] —
|
||||
"gaps filled with frog DNA …"
|
||||
|
||||
Finit is developed and maintained by [Joachim Nilsson][] at [GitHub][].
|
||||
Please file bug reports, clone it, or send pull requests for bug fixes
|
||||
and proposed extensions.
|
||||
|
||||
|
||||
[1]: https://en.wikipedia.org/wiki/Process_supervision
|
||||
[2]: http://cr.yp.to/daemontools.html
|
||||
[3]: http://smarden.org/runit/
|
||||
[4]: http://en.wikipedia.org/wiki/Init
|
||||
[5]: http://en.wikipedia.org/wiki/Runlevel
|
||||
[6]: https://www.freedesktop.org/wiki/Software/systemd/
|
||||
[9]: https://github.com/troglobit/troglos
|
||||
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
||||
[original finit]: http://helllabs.org/finit/
|
||||
[EeePC fastinit]: http://wiki.eeeuser.com/boot_process:the_boot_process
|
||||
[Claudio Matsuoka]: https://github.com/cmatsuoka
|
||||
[Joachim Nilsson]: http://troglobit.com
|
||||
[GitHub]: https://github.com/troglobit/finit
|
||||
[Travis]: https://travis-ci.org/troglobit/finit
|
||||
[Travis Status]: https://travis-ci.org/troglobit/finit.png?branch=master
|
||||
[Coverity Scan]: https://scan.coverity.com/projects/3545
|
||||
[Coverity Status]: https://scan.coverity.com/projects/3545/badge.svg
|
||||
|
||||
<!--
|
||||
-- Local Variables:
|
||||
-- mode: markdown
|
||||
-- End:
|
||||
-->
|
||||
@@ -0,0 +1,115 @@
|
||||
Goals of Finit
|
||||
==============
|
||||
|
||||
The intent of finit is to monitor not just processes, but to supervise
|
||||
an entire system and the behavior of certain processes that declare
|
||||
themselves to be finit compliant. Similar to launchd, the goal of
|
||||
finit is to be a replacement for:
|
||||
|
||||
* init
|
||||
* inetd
|
||||
* crond
|
||||
* watchdogd
|
||||
|
||||
A small and simple replacement, primarily for embedded systems, with a
|
||||
very low dependency on external packages.
|
||||
|
||||
|
||||
General
|
||||
-------
|
||||
|
||||
* Add halt/poweroff/shutdown symlinks to finit and convert reboot, but
|
||||
only install symlinks if these tools don't already exist.
|
||||
* Add support for timed shutdown in Finit, including cancelled shutdown.
|
||||
* SysV init and systemd use SIGUSR1 to restart their FIFO/D-Bus. Add
|
||||
API restart to SIGHUP callback for the same functionality in Finit.
|
||||
* Add `finit.conf` support for UPS notification (SIGPWR) to start a task
|
||||
using, e.g. <sys/power/{ok,fail,low}> conditions. More info in sig.c
|
||||
* Add `finit.conf` support for ctrl-alt-delete (SIGINT) and kbrequest,
|
||||
i.e. KeyboardSignal, (SIGWINCH) behavior. Using conditions to a task,
|
||||
e.g, <sys/key/ctrlaltdel> and <sys/key/signal> like SIGPWR handling.
|
||||
* Add `IFF_RUNNING` support to netlink plugin along `IFF_IUP`
|
||||
* Allow process callbacks to be scripts.
|
||||
* Add support for a pipe/popen where we can listen for `STOP`, `START`
|
||||
and `RELOAD` on `STDOUT` from a script ... call it for example
|
||||
`.monitor=` in `svc_t` ... the script named as the basename of the
|
||||
service it monitors + `.sh`.
|
||||
* Implement `initctl stop|start|restart|reload|status <SVC>` and
|
||||
`service <SVC> stop|start|restart|reload|status` on top
|
||||
* Add support for JSON output, or similar, from `initctl show`, e.g.
|
||||
`initctl show --json`
|
||||
* Improve output of `initctl show SVC`, list service uptime, last
|
||||
ten relevant logs, etc. Similar to `systemctl show SVC`
|
||||
* Add PRE and POST hooks for when switching between runlevels
|
||||
|
||||
|
||||
Init
|
||||
----
|
||||
|
||||
Finit in itself is not SysV Init compatible, it doesn't use `/etc/rc.d`
|
||||
and `/etc/inet.d` scripts to boot the system. However, a plausible way
|
||||
to achieve compatibility would be to add a plugin to finit which reads
|
||||
`/etc/inittab` to be able to start standard Linux systems.
|
||||
|
||||
|
||||
Inetd
|
||||
-----
|
||||
|
||||
* Add support for throttling connections.
|
||||
* Optimize interface filtering by using socket filter. The functions
|
||||
`inet_*_peek()` and `inetd_is_allowed()` used for interace filtering
|
||||
should be possible to rewrite as socket filters.
|
||||
* Optimize HTTP/HTTPS inetd connections by adding basic support for the
|
||||
`inetd` variant `redir http/tcp@eth0 nowait [2345] 127.0.0.1:8080`,
|
||||
which would reduce the overhead of spawn the web server on each HTTP
|
||||
connection, yet still provide a means of filtering access per iface.
|
||||
|
||||
|
||||
Crond
|
||||
-----
|
||||
|
||||
Requirements are quite rudimentary, basic cron functionality, mainly
|
||||
system-level timed periodic tasks:
|
||||
|
||||
* Periodically run a task, in a matching runlevel
|
||||
* Optionally run as non-root (`crontab -e` as operator)
|
||||
|
||||
Proposed syntax:
|
||||
|
||||
# Crontab
|
||||
cron @YY-mm-ddTHH:MM [LVLS] /path/to/cmd [ARGS] -- Optional descr
|
||||
|
||||
# One-shot 'at' command
|
||||
at @YY-mm-ddTHH:MM [LVLS] /path/to/cmd [ARGS] -- Optional descr
|
||||
|
||||
Notice the ISO date in notation. The runlevels is extra filtering
|
||||
sugar. E.g., if cron service is only allowed in runlevels two or three
|
||||
it will not start if system currently is in runlevel four.
|
||||
|
||||
To run a command as another user the `.conf` file must have a that
|
||||
owner. E.g., `/etc/finit.d/extra.conf` may be owned by operator and
|
||||
only hold `cron ...` lines.
|
||||
|
||||
What would be extremely useful is if `initctl`, or a homegrown `at`,
|
||||
could support the basic functionality of the `at` command directly from
|
||||
the shell -- that way setting up one-time jobs would not entail
|
||||
re-reading `/etc/finit.conf`
|
||||
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
* Write man pages for finit and `finit.conf`, steal from the excellent
|
||||
`pimd` man pages ...
|
||||
* Add simple, *very* simple, `finit-simple.conf` example. To illustrate
|
||||
how close Finit3 still is to the original easy-to-use Finit0 :)
|
||||
|
||||
|
||||
[libwdt]: http://www.wehavemorefun.de/fritzbox/Libwdt.so
|
||||
[Fritz!Box source dump]: ftp://ftp.avm.de/fritz.box/fritzbox.fon_wlan_7170/x_misc/opensrc/
|
||||
|
||||
<!--
|
||||
-- Local Variables:
|
||||
-- mode: markdown
|
||||
-- End:
|
||||
-->
|
||||
@@ -0,0 +1,402 @@
|
||||
/* External client API, using UNIX domain socket.
|
||||
*
|
||||
* Copyright (c) 2015 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <lite/lite.h>
|
||||
#include <uev/uev.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "finit.h"
|
||||
#include "cond.h"
|
||||
#include "conf.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
#include "sig.h"
|
||||
#include "service.h"
|
||||
|
||||
uev_t api_watcher;
|
||||
|
||||
/* Allowed characters in job/id/name */
|
||||
static int isallowed(int ch)
|
||||
{
|
||||
return isprint(ch);
|
||||
}
|
||||
|
||||
/* Sanitize user input, make sure to NUL terminate. */
|
||||
static char *sanitize(char *arg, size_t len)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
while (isallowed(arg[i]) && i < len)
|
||||
i++;
|
||||
|
||||
if (i + 1 < len) {
|
||||
arg[i + 1] = 0;
|
||||
return arg;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int call(int (*action)(svc_t *), char *buf, size_t len)
|
||||
{
|
||||
int result = 0;
|
||||
char *input, *token, *pos;
|
||||
|
||||
input = sanitize(buf, len);
|
||||
if (!input)
|
||||
return -1;
|
||||
|
||||
token = strtok_r(input, " ", &pos);
|
||||
while (token) {
|
||||
svc_t *svc;
|
||||
char *ptr = strchr(token, ':');
|
||||
|
||||
if (isdigit(token[0])) {
|
||||
int job = atonum(token);
|
||||
|
||||
if (!ptr) {
|
||||
svc = svc_job_iterator(1, job);
|
||||
while (svc) {
|
||||
result += action(svc);
|
||||
svc = svc_job_iterator(0, job);
|
||||
}
|
||||
} else {
|
||||
*ptr++ = 0;
|
||||
job = atonum(token);
|
||||
result += action(svc_find_by_jobid(job, atonum(ptr)));
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!ptr) {
|
||||
svc = svc_named_iterator(1, token);
|
||||
while (svc) {
|
||||
result += action(svc);
|
||||
svc = svc_named_iterator(0, token);
|
||||
}
|
||||
} else {
|
||||
*ptr++ = 0;
|
||||
result += action(svc_find_by_nameid(token, atonum(ptr)));
|
||||
}
|
||||
}
|
||||
|
||||
token = strtok_r(NULL, " ", &pos);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int service_block(svc_t *svc)
|
||||
{
|
||||
svc_block(svc);
|
||||
service_step(svc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int service_unblock(svc_t *svc)
|
||||
{
|
||||
svc_unblock(svc);
|
||||
service_step(svc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int service_restart(svc_t *svc)
|
||||
{
|
||||
svc_mark_dirty(svc);
|
||||
service_step(svc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_start (char *buf, size_t len) { return call(service_unblock, buf, len); }
|
||||
static int do_pause (char *buf, size_t len) { return call(service_block, buf, len); }
|
||||
static int do_restart(char *buf, size_t len) { return call(service_restart, buf, len); }
|
||||
|
||||
#ifndef INETD_DISABLED
|
||||
static int do_query_inetd(char *buf, size_t len)
|
||||
{
|
||||
int id = 1;
|
||||
char *ptr, *input = sanitize(buf, len);
|
||||
svc_t *svc;
|
||||
|
||||
if (!input)
|
||||
return -1;
|
||||
|
||||
ptr = strchr(input, ':');
|
||||
if (ptr) {
|
||||
*ptr++ = 0;
|
||||
id = atonum(ptr);
|
||||
}
|
||||
|
||||
svc = svc_find_by_jobid(atonum(input), id);
|
||||
if (!svc || !svc_is_inetd(svc)) {
|
||||
_e("Cannot %s svc %s ...", !svc ? "find" : "query, not an inetd", input);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return inetd_filter_str(&svc->inetd, buf, len);
|
||||
}
|
||||
#endif /* !INETD_DISABLED */
|
||||
|
||||
typedef struct {
|
||||
char *event;
|
||||
void (*cb)(void);
|
||||
} ev_t;
|
||||
|
||||
ev_t ev_list[] = {
|
||||
{ "RELOAD", service_reload_dynamic },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static int do_handle_event(char *event)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; ev_list[i].event; i++) {
|
||||
ev_t *e = &ev_list[i];
|
||||
size_t len = MAX(strlen(e->event), strlen(event));
|
||||
|
||||
if (!strncasecmp(e->event, event, len)) {
|
||||
e->cb();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (event[0] == '-')
|
||||
cond_clear(&event[1]);
|
||||
else if (event[0] == '+')
|
||||
cond_set(&event[1]);
|
||||
else
|
||||
cond_set(event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_handle_emit(char *buf, size_t len)
|
||||
{
|
||||
int result = 0;
|
||||
char *input, *event, *pos;
|
||||
|
||||
input = sanitize(buf, len);
|
||||
if (!input)
|
||||
return -1;
|
||||
|
||||
event = strtok_r(input, " ", &pos);
|
||||
while (event) {
|
||||
result += do_handle_event(event);
|
||||
event = strtok_r(NULL, " ", &pos);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* In contrast to the SysV compat handling in plugins/initctl.c, when
|
||||
* `initctl runlevel 0` is issued we default to POWERDOWN the system
|
||||
* instead of just halting.
|
||||
*/
|
||||
static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
|
||||
{
|
||||
int sd, lvl;
|
||||
struct init_request rq;
|
||||
|
||||
sd = accept(w->fd, NULL, NULL);
|
||||
if (sd < 0) {
|
||||
_pe("Failed serving API request");
|
||||
return;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
int result = 0;
|
||||
ssize_t len;
|
||||
|
||||
len = read(sd, &rq, sizeof(rq));
|
||||
if (len <= 0) {
|
||||
if (-1 == len) {
|
||||
if (EINTR == errno)
|
||||
continue;
|
||||
|
||||
if (EAGAIN == errno)
|
||||
break;
|
||||
|
||||
_e("Failed reading initctl request, error %d: %s", errno, strerror(errno));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (rq.magic != INIT_MAGIC || len != sizeof(rq)) {
|
||||
_e("Invalid initctl request");
|
||||
break;
|
||||
}
|
||||
|
||||
switch (rq.cmd) {
|
||||
case INIT_CMD_RUNLVL:
|
||||
switch (rq.runlevel) {
|
||||
case 's':
|
||||
case 'S':
|
||||
rq.runlevel = '1'; /* Single user mode */
|
||||
/* Fall through to regular processing */
|
||||
|
||||
case '0'...'9':
|
||||
_d("Setting new runlevel %c", rq.runlevel);
|
||||
lvl = rq.runlevel - '0';
|
||||
if (lvl == 0)
|
||||
halt = SHUT_OFF;
|
||||
if (lvl == 6)
|
||||
halt = SHUT_REBOOT;
|
||||
service_runlevel(lvl);
|
||||
break;
|
||||
|
||||
default:
|
||||
_d("Unsupported runlevel: %d", rq.runlevel);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case INIT_CMD_DEBUG:
|
||||
debug = !debug;
|
||||
if (debug)
|
||||
silent = 0;
|
||||
else
|
||||
silent = quiet ? 1 : SILENT_MODE;
|
||||
break;
|
||||
|
||||
case INIT_CMD_RELOAD: /* 'init q' and 'initctl reload' */
|
||||
service_reload_dynamic();
|
||||
break;
|
||||
|
||||
case INIT_CMD_START_SVC:
|
||||
result = do_start(rq.data, sizeof(rq.data));
|
||||
break;
|
||||
|
||||
case INIT_CMD_STOP_SVC:
|
||||
result = do_pause(rq.data, sizeof(rq.data));
|
||||
break;
|
||||
|
||||
case INIT_CMD_RESTART_SVC:
|
||||
result = do_restart(rq.data, sizeof(rq.data));
|
||||
break;
|
||||
|
||||
#ifndef INETD_DISABLED
|
||||
case INIT_CMD_QUERY_INETD:
|
||||
result = do_query_inetd(rq.data, sizeof(rq.data));
|
||||
break;
|
||||
#endif
|
||||
|
||||
case INIT_CMD_EMIT:
|
||||
result = do_handle_emit(rq.data, sizeof(rq.data));
|
||||
break;
|
||||
|
||||
case INIT_CMD_GET_RUNLEVEL:
|
||||
rq.runlevel = runlevel;
|
||||
break;
|
||||
|
||||
case INIT_CMD_ACK:
|
||||
_d("Client failed reading ACK");
|
||||
goto leave;
|
||||
|
||||
case INIT_CMD_WDOG_HELLO:
|
||||
if (rq.runlevel <= 0) {
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (wdogpid > 0 && wdogpid != rq.runlevel) {
|
||||
kill(wdogpid, SIGTERM);
|
||||
do_sleep(1);
|
||||
}
|
||||
wdogpid = rq.runlevel;
|
||||
break;
|
||||
|
||||
default:
|
||||
_d("Unsupported cmd: %d", rq.cmd);
|
||||
break;
|
||||
}
|
||||
|
||||
if (result)
|
||||
rq.cmd = INIT_CMD_NACK;
|
||||
else
|
||||
rq.cmd = INIT_CMD_ACK;
|
||||
len = write(sd, &rq, sizeof(rq));
|
||||
if (len != sizeof(rq))
|
||||
_d("Failed sending ACK/NACK back to client");
|
||||
}
|
||||
|
||||
leave:
|
||||
close(sd);
|
||||
}
|
||||
|
||||
int api_init(uev_ctx_t *ctx)
|
||||
{
|
||||
int sd;
|
||||
mode_t oldmask;
|
||||
struct sockaddr_un sun = {
|
||||
.sun_family = AF_UNIX,
|
||||
.sun_path = INIT_SOCKET,
|
||||
};
|
||||
|
||||
sd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
if (-1 == sd) {
|
||||
_pe("Failed starting external API socket");
|
||||
return 1;
|
||||
}
|
||||
|
||||
erase(INIT_SOCKET);
|
||||
oldmask = umask(0077);
|
||||
if (-1 == bind(sd, (struct sockaddr*)&sun, sizeof(sun)))
|
||||
goto error;
|
||||
|
||||
if (-1 == listen(sd, 10))
|
||||
goto error;
|
||||
|
||||
umask(oldmask);
|
||||
if (!uev_io_init(ctx, &api_watcher, cb, NULL, sd, UEV_READ))
|
||||
return 0;
|
||||
|
||||
error:
|
||||
_pe("Failed intializing API socket");
|
||||
umask(oldmask);
|
||||
close(sd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int api_exit(void)
|
||||
{
|
||||
return shutdown(api_watcher.fd, SHUT_RDWR) ||
|
||||
close(api_watcher.fd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
autoreconf -W portability -vifm
|
||||
@@ -0,0 +1,160 @@
|
||||
/* Simple telinit client
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2015 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h" /* Generated by configure script */
|
||||
|
||||
#include <ctype.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "util.h"
|
||||
|
||||
static int do_send(struct init_request *rq)
|
||||
{
|
||||
static int fd = -1;
|
||||
int result = 255;
|
||||
ssize_t len;
|
||||
|
||||
if (fd == -1) {
|
||||
if (!fexist(FINIT_FIFO)) {
|
||||
fprintf(stderr, "%s does not support %s!\n", prognm, FINIT_FIFO);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fd = open(FINIT_FIFO, O_RDWR);
|
||||
if (-1 == fd) {
|
||||
perror("Failed opening " FINIT_FIFO);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
len = write(fd, rq, sizeof(*rq));
|
||||
if (sizeof(*rq) == len)
|
||||
result = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int do_reload(void)
|
||||
{
|
||||
struct init_request rq = {
|
||||
.magic = INIT_MAGIC,
|
||||
.cmd = INIT_CMD_RELOAD,
|
||||
};
|
||||
|
||||
return do_send(&rq);
|
||||
}
|
||||
|
||||
static int set_env(int runlevel)
|
||||
{
|
||||
struct init_request rq = {
|
||||
.magic = INIT_MAGIC,
|
||||
.cmd = INIT_CMD_SETENV,
|
||||
};
|
||||
|
||||
if (runlevel == 0) {
|
||||
strlcpy(rq.data, "INIT_HALT=POWERDOWN", sizeof(rq.data));
|
||||
return do_send(&rq);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_runlevel(int runlevel)
|
||||
{
|
||||
struct init_request rq = {
|
||||
.magic = INIT_MAGIC,
|
||||
.cmd = INIT_CMD_RUNLVL,
|
||||
.runlevel = runlevel,
|
||||
};
|
||||
|
||||
return set_env(runlevel) || do_send(&rq);
|
||||
}
|
||||
|
||||
/* telinit q | telinit <0-9> */
|
||||
static int usage(int rc)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [OPTIONS] [q | Q | 0-9]\n\n"
|
||||
"Options:\n"
|
||||
" -h, --help This help text\n"
|
||||
" -V, --version Show Finit version\n\n"
|
||||
"Commands:\n"
|
||||
" 0 Power-off the system, same as initctl poweroff\n"
|
||||
" 6 Reboot the system, same as initctl reboot\n"
|
||||
" 2, 3, 4, 5 Change runlevel. Starts services in new runlevel, stops any\n"
|
||||
" services in prev. runlevel that are not allowed in new.\n"
|
||||
" q, Q Reload *.conf in /etc/finit.d/, same as initctl reload or\n"
|
||||
" sending SIGHUP to PID 1\n"
|
||||
" 1, s, S Enter system rescue mode, runlevel 1\n"
|
||||
"\n", prognm);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int client(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
struct option long_options[] = {
|
||||
{"help", 0, NULL, 'h'},
|
||||
{"version", 0, NULL, 'v'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
silent = 1;
|
||||
progname(argv[0]);
|
||||
while ((c = getopt_long(argc, argv, "h?v", long_options, NULL)) != EOF) {
|
||||
switch(c) {
|
||||
case 'v':
|
||||
return puts("v" VERSION) == EOF;
|
||||
|
||||
case 'h':
|
||||
case '?':
|
||||
return usage(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc) {
|
||||
int req = (int)argv[optind][0];
|
||||
|
||||
if (isdigit(req))
|
||||
return set_runlevel(req);
|
||||
|
||||
if (req == 'q' || req == 'Q')
|
||||
return do_reload();
|
||||
|
||||
if (req == 's' || req == 'S')
|
||||
return set_runlevel(1);
|
||||
}
|
||||
|
||||
return usage(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,30 @@
|
||||
# Top directory for building complete system, fall back to this directory
|
||||
ROOTDIR ?= $(TOPDIR)
|
||||
|
||||
# Strip binaries unless user explicitly disables it
|
||||
STRIPARGS ?= -s --strip-program=$(CROSS)strip -m 0755
|
||||
|
||||
# Some junk files we always want to be removed when doing a make clean.
|
||||
JUNK = *~ *.bak *.map .*.d *.d DEADJOE semantic.cache *.gdb *.elf core core.*
|
||||
MAKE := @$(MAKE)
|
||||
MAKEFLAGS = --no-print-directory --silent
|
||||
CHECK := cppcheck $(CPPFLAGS) --quiet --enable=all
|
||||
INSTALL := install --backup=off
|
||||
STRIPINST := $(INSTALL) $(STRIPARGS)
|
||||
ARFLAGS := crus
|
||||
|
||||
export libdir plugindir incdir ROOTDIR CPPFLAGS LDFLAGS LDLIBS STATIC
|
||||
|
||||
|
||||
# Override default implicit rules
|
||||
%.o: %.c
|
||||
@printf " CC $(subst $(ROOTDIR)/,,$(shell pwd)/$@)\n"
|
||||
@$(CC) $(CFLAGS) $(CPPFLAGS) -c -MMD -MP -o $@ $<
|
||||
|
||||
%: %.o
|
||||
@printf " LINK $(subst $(ROOTDIR)/,,$(shell pwd)/$@)\n"
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -Wl,-Map,$@.map -o $@ $^ $(LDLIBS$(LDLIBS-$(@)))
|
||||
|
||||
%.so: %.o
|
||||
@printf " PLUGIN $(subst $(ROOTDIR)/,,$(shell pwd)/$@)\n"
|
||||
@$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
|
||||
@@ -0,0 +1,132 @@
|
||||
/* Condition engine (write)
|
||||
*
|
||||
* Copyright (c) 2015-2016 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 <libgen.h>
|
||||
#include <lite/lite.h>
|
||||
#include <stdio.h>
|
||||
#include <utime.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "cond.h"
|
||||
#include "service.h"
|
||||
|
||||
int cond_set_path(const char *path, enum cond_state new)
|
||||
{
|
||||
char buf[MAX_ARG_LEN], *dir;
|
||||
enum cond_state old;
|
||||
|
||||
old = cond_get_path(path);
|
||||
|
||||
switch (new) {
|
||||
case COND_ON:
|
||||
strlcpy(buf, path, sizeof(buf));
|
||||
dir = dirname(buf);
|
||||
if (!dir) {
|
||||
_e("Invalid path '%s' for condition", path);
|
||||
return 0;
|
||||
}
|
||||
if (makepath(dir) && errno != EEXIST) {
|
||||
_pe("Failed creating dir '%s' for condition '%s'", dir, path);
|
||||
return 0;
|
||||
}
|
||||
touch(path);
|
||||
utime(path, NULL);
|
||||
break;
|
||||
|
||||
case COND_OFF:
|
||||
unlink(path);
|
||||
break;
|
||||
|
||||
default:
|
||||
_e("Invalid condition state");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return new != old;
|
||||
}
|
||||
|
||||
/* Has condition in configuration and cond is allowed? */
|
||||
static int svc_has_cond(svc_t *svc)
|
||||
{
|
||||
if (!svc->cond[0])
|
||||
return 0;
|
||||
|
||||
switch (svc->type) {
|
||||
case SVC_TYPE_SERVICE:
|
||||
case SVC_TYPE_TASK:
|
||||
case SVC_TYPE_RUN:
|
||||
return 1;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cond_update(const char *name)
|
||||
{
|
||||
svc_t *svc;
|
||||
|
||||
_d("%s", name);
|
||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
||||
if (!svc_has_cond(svc) || !cond_affects(name, svc->cond))
|
||||
continue;
|
||||
|
||||
_d("%s: match <%s> %s", name ?: "nil", svc->cond, svc->cmd);
|
||||
service_step(svc);
|
||||
}
|
||||
}
|
||||
|
||||
void cond_set(const char *name)
|
||||
{
|
||||
_d("%s", name);
|
||||
if (!cond_set_path(cond_path(name), COND_ON))
|
||||
return;
|
||||
|
||||
cond_update(name);
|
||||
}
|
||||
|
||||
void cond_clear(const char *name)
|
||||
{
|
||||
_d("%s", name);
|
||||
if (!cond_set_path(cond_path(name), COND_OFF))
|
||||
return;
|
||||
|
||||
cond_update(name);
|
||||
}
|
||||
|
||||
void cond_reload(void)
|
||||
{
|
||||
_d("");
|
||||
cond_set_path(COND_RECONF, COND_ON);
|
||||
|
||||
cond_update(NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,117 @@
|
||||
/* Condition engine (read)
|
||||
*
|
||||
* Copyright (c) 2015-2016 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 <lite/lite.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "cond.h"
|
||||
#include "service.h"
|
||||
|
||||
static inline int timespec_newer(const struct timespec *a,
|
||||
const struct timespec *b)
|
||||
{
|
||||
if (a->tv_sec != b->tv_sec)
|
||||
return a->tv_sec > b->tv_sec;
|
||||
|
||||
return a->tv_nsec > b->tv_nsec;
|
||||
}
|
||||
|
||||
const char *condstr(enum cond_state s)
|
||||
{
|
||||
static const char *strs[] = {
|
||||
[COND_OFF] = "off",
|
||||
[COND_FLUX] = "flux",
|
||||
[COND_ON] = "on",
|
||||
};
|
||||
|
||||
return strs[s];
|
||||
}
|
||||
|
||||
const char *cond_path(const char *name)
|
||||
{
|
||||
static char file[MAX_ARG_LEN];
|
||||
|
||||
snprintf(file, sizeof(file), COND_PATH "/%s", name);
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
enum cond_state cond_get_path(const char *path)
|
||||
{
|
||||
struct stat st, st_reconf;
|
||||
|
||||
if (stat(path, &st))
|
||||
return COND_OFF;
|
||||
|
||||
if (stat(COND_RECONF, &st_reconf) ||
|
||||
timespec_newer(&st.st_mtim, &st_reconf.st_mtim))
|
||||
return COND_ON;
|
||||
|
||||
return COND_FLUX;
|
||||
}
|
||||
|
||||
enum cond_state cond_get(const char *name)
|
||||
{
|
||||
return cond_get_path(cond_path(name));
|
||||
}
|
||||
|
||||
enum cond_state cond_get_agg(const char *names)
|
||||
{
|
||||
char *cond;
|
||||
enum cond_state s = COND_ON;
|
||||
static char conds[MAX_ARG_LEN];
|
||||
|
||||
if (!names)
|
||||
return COND_ON;
|
||||
|
||||
strlcpy(conds, names, sizeof(conds));
|
||||
for (cond = strtok(conds, ","); s && cond; cond = strtok(NULL, ","))
|
||||
s = min(s, cond_get(cond));
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int cond_affects(const char *name, const char *names)
|
||||
{
|
||||
char *cond;
|
||||
static char conds[MAX_ARG_LEN];
|
||||
|
||||
if (!name || !names)
|
||||
return 0;
|
||||
|
||||
strlcpy(conds, names, sizeof(conds));
|
||||
for (cond = strtok(conds, ","); cond; cond = strtok(NULL, ",")) {
|
||||
if (!strcmp(cond, name))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef FINIT_COND_H_
|
||||
#define FINIT_COND_H_
|
||||
|
||||
#include <paths.h>
|
||||
|
||||
#define COND_PATH _PATH_VARRUN "finit/cond"
|
||||
#define COND_SVC_PATH COND_PATH "/svc/"
|
||||
#define COND_RECONF COND_PATH "/reconf"
|
||||
|
||||
typedef enum cond_state {
|
||||
COND_OFF = 0,
|
||||
COND_FLUX,
|
||||
COND_ON
|
||||
} cond_state_t;
|
||||
|
||||
const char *condstr (enum cond_state s);
|
||||
const char *cond_path (const char *name);
|
||||
enum cond_state cond_get_path(const char *path);
|
||||
enum cond_state cond_get (const char *name);
|
||||
enum cond_state cond_get_agg (const char *names);
|
||||
int cond_affects (const char *name, const char *names);
|
||||
|
||||
int cond_set_path(const char *path, enum cond_state new);
|
||||
void cond_set (const char *name);
|
||||
void cond_clear (const char *name);
|
||||
void cond_reload (void);
|
||||
|
||||
#endif /* FINIT_COND_H_ */
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,524 @@
|
||||
/* Parser for /etc/finit.conf and /etc/finit.d/<SVC>.conf
|
||||
*
|
||||
* Copyright (c) 2012-2015 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h" /* Generated by configure script */
|
||||
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <sys/resource.h>
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "cond.h"
|
||||
#include "service.h"
|
||||
#include "tty.h"
|
||||
#include "helpers.h"
|
||||
|
||||
#define MATCH_CMD(l, c, x) \
|
||||
(!strncasecmp(l, c, strlen(c)) && (x = (l) + strlen(c)))
|
||||
|
||||
static int parse_conf(char *file);
|
||||
|
||||
|
||||
void conf_parse_cmdline(void)
|
||||
{
|
||||
FILE *fp;
|
||||
char line[LINE_SIZE];
|
||||
|
||||
fp = fopen("/proc/cmdline", "r");
|
||||
if (fp) {
|
||||
fgets(line, sizeof(line), fp);
|
||||
_d("Kernel command line: %s", line);
|
||||
|
||||
if (strstr(line, "finit_debug") || strstr(line, "--debug"))
|
||||
debug = 1;
|
||||
|
||||
if (!debug && strstr(line, "quiet"))
|
||||
quiet = 1;
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert optional "[!123456789S]" string into a bitmask */
|
||||
int conf_parse_runlevels(char *runlevels)
|
||||
{
|
||||
int i, not = 0, bitmask = 0;
|
||||
|
||||
if (!runlevels)
|
||||
runlevels = "[234]";
|
||||
i = 1;
|
||||
while (i) {
|
||||
int level;
|
||||
char lvl = runlevels[i++];
|
||||
|
||||
if (']' == lvl || 0 == lvl)
|
||||
break;
|
||||
if ('!' == lvl) {
|
||||
not = 1;
|
||||
bitmask = 0x3FE;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ('s' == lvl || 'S' == lvl)
|
||||
lvl = '0';
|
||||
|
||||
level = lvl - '0';
|
||||
if (level > 9 || level < 0)
|
||||
continue;
|
||||
|
||||
if (not)
|
||||
CLRBIT(bitmask, level);
|
||||
else
|
||||
SETBIT(bitmask, level);
|
||||
}
|
||||
|
||||
return bitmask;
|
||||
}
|
||||
|
||||
void conf_parse_cond(svc_t *svc, char *cond)
|
||||
{
|
||||
size_t i = 0;
|
||||
char *ptr;
|
||||
|
||||
if (!svc) {
|
||||
_e("Invalid service pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
/* By default we assume UNIX daemons support SIGHUP */
|
||||
if (svc_is_daemon(svc))
|
||||
svc->sighup = 1;
|
||||
|
||||
if (!cond)
|
||||
return;
|
||||
|
||||
/* First character must be '!' if SIGHUP is not supported. */
|
||||
ptr = cond;
|
||||
if (ptr[i] == '!') {
|
||||
svc->sighup = 0;
|
||||
ptr++;
|
||||
}
|
||||
|
||||
while (ptr[i] != '>' && ptr[i] != 0)
|
||||
i++;
|
||||
ptr[i] = 0;
|
||||
|
||||
if (i >= sizeof(svc->cond)) {
|
||||
logit(LOG_WARNING, "Too long event list in declaration of %s: %s", svc->cmd, ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
strlcpy(svc->cond, ptr, sizeof(svc->cond));
|
||||
}
|
||||
|
||||
struct rlimit_name {
|
||||
char *name;
|
||||
int val;
|
||||
};
|
||||
|
||||
static const struct rlimit_name rlimit_names[] = {
|
||||
{ "as", RLIMIT_AS },
|
||||
{ "core", RLIMIT_CORE },
|
||||
{ "cpu", RLIMIT_CPU },
|
||||
{ "data", RLIMIT_DATA },
|
||||
{ "fsize", RLIMIT_FSIZE },
|
||||
{ "locks", RLIMIT_LOCKS },
|
||||
{ "memlock", RLIMIT_MEMLOCK },
|
||||
{ "msgqueue", RLIMIT_MSGQUEUE },
|
||||
{ "nice", RLIMIT_NICE },
|
||||
{ "nofile", RLIMIT_NOFILE },
|
||||
{ "nproc", RLIMIT_NPROC },
|
||||
{ "rss", RLIMIT_RSS },
|
||||
{ "rtprio", RLIMIT_RTPRIO },
|
||||
#ifdef RLIMIT_RTTIME
|
||||
{ "rttime", RLIMIT_RTTIME },
|
||||
#endif
|
||||
{ "sigpending", RLIMIT_SIGPENDING },
|
||||
{ "stack", RLIMIT_STACK },
|
||||
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
void conf_parse_rlimit(char *line)
|
||||
{
|
||||
struct rlimit rlim;
|
||||
rlim_t new, *set;
|
||||
const struct rlimit_name *name;
|
||||
int resource = -1;
|
||||
|
||||
char *tok = strtok(line, " \t");
|
||||
|
||||
if (tok && !strcmp(tok, "soft"))
|
||||
set = &rlim.rlim_cur;
|
||||
else if (tok && !strcmp(tok, "hard"))
|
||||
set = &rlim.rlim_max;
|
||||
else
|
||||
goto error;
|
||||
|
||||
tok = strtok(NULL, " \t");
|
||||
if (!tok)
|
||||
goto error;
|
||||
|
||||
for (name = rlimit_names; name->name; name++) {
|
||||
if (!strcmp(tok, name->name))
|
||||
resource = name->val;
|
||||
}
|
||||
|
||||
if (resource < 0)
|
||||
goto fail;
|
||||
|
||||
tok = strtok(NULL, " \t");
|
||||
if (!tok)
|
||||
goto fail;
|
||||
|
||||
if (!strcmp(tok, "infinity")) {
|
||||
new = RLIM_INFINITY;
|
||||
} else {
|
||||
const char *err = NULL;
|
||||
|
||||
new = strtonum(tok, 0, (long long)2 << 31, &err);
|
||||
if (err)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (getrlimit(resource, &rlim))
|
||||
goto fail;
|
||||
|
||||
*set = new;
|
||||
if (setrlimit(resource, &rlim))
|
||||
goto fail;
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
logit(LOG_WARNING, "rlimit: Failed setting rlimit %s", name->name ? : "unknown");
|
||||
return;
|
||||
error:
|
||||
logit(LOG_WARNING, "rlimit: parse error");
|
||||
}
|
||||
|
||||
static void parse_static(char *line)
|
||||
{
|
||||
char *x;
|
||||
char cmd[CMD_SIZE];
|
||||
|
||||
/* Do this before mounting / read-write
|
||||
* XXX: Move to plugin which checks /etc/fstab instead */
|
||||
if (MATCH_CMD(line, "check ", x)) {
|
||||
char *dev = strip_line(x);
|
||||
|
||||
strcpy(cmd, "/sbin/fsck -C -a ");
|
||||
strlcat(cmd, dev, sizeof(cmd));
|
||||
run_interactive(cmd, "Checking file system %s", dev);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (MATCH_CMD(line, "user ", x)) {
|
||||
if (username) free(username);
|
||||
username = strdup(strip_line(x));
|
||||
return;
|
||||
}
|
||||
|
||||
if (MATCH_CMD(line, "host ", x)) {
|
||||
if (hostname) free(hostname);
|
||||
hostname = strdup(strip_line(x));
|
||||
return;
|
||||
}
|
||||
|
||||
if (MATCH_CMD(line, "module ", x)) {
|
||||
char *mod = strip_line(x);
|
||||
|
||||
strcpy(cmd, "/sbin/modprobe ");
|
||||
strlcat(cmd, mod, sizeof(cmd));
|
||||
run_interactive(cmd, "Loading kernel module %s", mod);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (MATCH_CMD(line, "mknod ", x)) {
|
||||
char *dev = strip_line(x);
|
||||
|
||||
strcpy(cmd, "/bin/mknod ");
|
||||
strlcat(cmd, dev, sizeof(cmd));
|
||||
run_interactive(cmd, "Creating device node %s", dev);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (MATCH_CMD(line, "network ", x)) {
|
||||
if (network) free(network);
|
||||
network = strdup(strip_line(x));
|
||||
return;
|
||||
}
|
||||
|
||||
if (MATCH_CMD(line, "runparts ", x)) {
|
||||
if (runparts) free(runparts);
|
||||
runparts = strdup(strip_line(x));
|
||||
return;
|
||||
}
|
||||
|
||||
if (MATCH_CMD(line, "include ", x)) {
|
||||
char *file = strip_line(x);
|
||||
|
||||
strlcpy(cmd, file, sizeof(cmd));
|
||||
if (!fexist(cmd)) {
|
||||
_e("Cannot find include file %s, absolute path required!", x);
|
||||
return;
|
||||
}
|
||||
|
||||
parse_conf(cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (MATCH_CMD(line, "startx ", x)) {
|
||||
service_register(SVC_TYPE_SERVICE, strip_line(x), 0, username);
|
||||
return;
|
||||
}
|
||||
|
||||
if (MATCH_CMD(line, "shutdown ", x)) {
|
||||
if (sdown) free(sdown);
|
||||
sdown = strdup(strip_line(x));
|
||||
return;
|
||||
}
|
||||
|
||||
/* The desired runlevel to start when leaving bootstrap (S).
|
||||
* Finit supports 1-9, but most systems only use 1-6, where
|
||||
* 6 is reserved for reboot */
|
||||
if (MATCH_CMD(line, "runlevel ", x)) {
|
||||
char *token = strip_line(x);
|
||||
const char *err = NULL;
|
||||
|
||||
cfglevel = strtonum(token, 1, 9, &err);
|
||||
if (err)
|
||||
cfglevel = RUNLEVEL;
|
||||
if (cfglevel < 1 || cfglevel > 9 || cfglevel == 6)
|
||||
cfglevel = 2; /* Fallback */
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: Make console & tty dynamically loadable from /etc/finit.d */
|
||||
if (MATCH_CMD(line, "console ", x)) {
|
||||
if (console) free(console);
|
||||
console = strdup(strip_line(x));
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: Make console & tty dynamically loadable from /etc/finit.d */
|
||||
if (MATCH_CMD(line, "tty ", x)) {
|
||||
tty_register(strip_line(x));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_dynamic(char *line, time_t mtime)
|
||||
{
|
||||
char *x;
|
||||
|
||||
/* Skip comments, i.e. lines beginning with # */
|
||||
if (MATCH_CMD(line, "#", x))
|
||||
return;
|
||||
|
||||
/* Monitored daemon, will be respawned on exit */
|
||||
if (MATCH_CMD(line, "service ", x)) {
|
||||
service_register(SVC_TYPE_SERVICE, x, mtime, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
/* One-shot task, will not be respawned */
|
||||
if (MATCH_CMD(line, "task ", x)) {
|
||||
service_register(SVC_TYPE_TASK, x, mtime, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Like task but waits for completion, useful w/ [S] */
|
||||
if (MATCH_CMD(line, "run ", x)) {
|
||||
service_register(SVC_TYPE_RUN, x, mtime, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Classic inetd service */
|
||||
if (MATCH_CMD(line, "inetd ", x)) {
|
||||
#ifndef INETD_DISABLED
|
||||
service_register(SVC_TYPE_INETD, x, mtime, NULL);
|
||||
#else
|
||||
_e("Finit built with inetd support disabled, cannot register service inetd %s!", x);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if (MATCH_CMD(line, "rlimit ", x)) {
|
||||
conf_parse_rlimit(x);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void tabstospaces(char *line)
|
||||
{
|
||||
if (!line)
|
||||
return;
|
||||
|
||||
for (int i = 0; line[i]; i++) {
|
||||
if (line[i] == '\t')
|
||||
line[i] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_conf_dynamic(char *file, time_t mtime)
|
||||
{
|
||||
FILE *fp = fopen(file, "r");
|
||||
|
||||
if (!fp) {
|
||||
_pe("Failed opening %s", file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (!feof(fp)) {
|
||||
char line[LINE_SIZE] = "";
|
||||
|
||||
if (!fgets(line, sizeof(line), fp))
|
||||
continue;
|
||||
|
||||
chomp(line);
|
||||
tabstospaces(line);
|
||||
_d("dyn conf: %s", line);
|
||||
|
||||
parse_dynamic(line, mtime);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_conf(char *file)
|
||||
{
|
||||
FILE *fp;
|
||||
char line[LINE_SIZE] = "";
|
||||
char *x;
|
||||
|
||||
fp = fopen(file, "r");
|
||||
if (!fp)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* If not standard finit.conf, then we want to show just the base name
|
||||
* Loading configuration ............. vs
|
||||
* Loading services configuration ....
|
||||
*/
|
||||
if (!string_match (file, FINIT_CONF)) {
|
||||
/* Remove leading path */
|
||||
x = strrchr(file, '/');
|
||||
if (!x) x = file;
|
||||
else x++;
|
||||
|
||||
/* Remove ending .conf */
|
||||
strlcpy(line, x, sizeof(line));
|
||||
x = strstr(line, ".conf");
|
||||
if (x) *x = 0;
|
||||
|
||||
/* Add empty space. */
|
||||
strcat(line, " ");
|
||||
}
|
||||
|
||||
if (!silent)
|
||||
print(0, "Loading %sconfiguration", line);
|
||||
while (!feof(fp)) {
|
||||
if (!fgets(line, sizeof(line), fp))
|
||||
continue;
|
||||
|
||||
chomp(line);
|
||||
tabstospaces(line);
|
||||
_d("conf: %s", line);
|
||||
|
||||
parse_static(line);
|
||||
parse_dynamic(line, 0);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reload all *.conf in /etc/finit.d/ */
|
||||
void conf_reload_dynamic(void)
|
||||
{
|
||||
int i, num;
|
||||
char *dir = rcsd;
|
||||
struct dirent **e;
|
||||
|
||||
/* Mark and sweep */
|
||||
svc_mark_dynamic();
|
||||
|
||||
num = scandir(dir, &e, NULL, alphasort);
|
||||
if (num < 0) {
|
||||
_d("No files found in %s, skipping ...", dir);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
char *name = e[i]->d_name;
|
||||
char path[CMD_SIZE];
|
||||
struct stat st;
|
||||
|
||||
snprintf(path, sizeof(path), "%s/%s", dir, name);
|
||||
|
||||
/* Check that it's an actual file ... */
|
||||
if (stat(path, &st)) {
|
||||
_d("Cannot even read .conf file %s, skipping ...", path);
|
||||
continue;
|
||||
}
|
||||
if (S_ISEXEC(st.st_mode) || S_ISDIR(st.st_mode))
|
||||
continue;
|
||||
|
||||
/* Check that file ends with '.conf' */
|
||||
if (strcmp(&path[strlen(path) - 5], ".conf")) {
|
||||
_d("File %s is not a .conf, skipping ... ", path);
|
||||
continue;
|
||||
}
|
||||
|
||||
parse_conf_dynamic(path, st.st_mtime);
|
||||
}
|
||||
|
||||
while (num--)
|
||||
free(e[num]);
|
||||
free(e);
|
||||
|
||||
set_hostname(&hostname);
|
||||
}
|
||||
|
||||
int conf_parse_config(void)
|
||||
{
|
||||
username = strdup(DEFUSER);
|
||||
hostname = strdup(DEFHOST);
|
||||
|
||||
return parse_conf(FINIT_CONF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,42 @@
|
||||
/* Parser for /etc/finit.conf and /etc/finit.d/<SVC>.conf
|
||||
*
|
||||
* Copyright (c) 2012-2015 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef FINIT_CONF_H_
|
||||
#define FINIT_CONF_H_
|
||||
|
||||
#include "svc.h"
|
||||
|
||||
void conf_parse_cmdline (void);
|
||||
int conf_parse_runlevels (char *runlevels);
|
||||
void conf_parse_cond (svc_t *svc, char *cond);
|
||||
int conf_parse_config (void);
|
||||
void conf_reload_dynamic (void);
|
||||
|
||||
#endif /* FINIT_CONF_H_ */
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
+215
@@ -0,0 +1,215 @@
|
||||
AC_INIT(Finit, 3.0-rc2, https://github.com/troglobit/finit/issues, finit, http://troglobit.com/finit.html)
|
||||
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz subdir-objects])
|
||||
AM_SILENT_RULES([yes])
|
||||
|
||||
AC_CONFIG_SRCDIR([finit.c])
|
||||
AC_CONFIG_HEADER([config.h])
|
||||
AC_CONFIG_FILES([Makefile plugins/Makefile])
|
||||
|
||||
# Older versions of autoconf (<2.58) do not have AC_CONFIG_MACRO_DIR()
|
||||
#m4_include([m4/plugin.m4])
|
||||
#m4_include([m4/expand.m4])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
||||
# Change default prefix, we're PID 1 after all ...
|
||||
AC_PREFIX_DEFAULT([])
|
||||
|
||||
# Handle building plugins either as dynamically loadable, or built-in
|
||||
LT_INIT([shared disable-static dlopen aix-soname=both disable-fast-install])
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_LN_S
|
||||
AC_PROG_INSTALL
|
||||
|
||||
# Configuration.
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS(fstaby.h)
|
||||
AC_CHECK_FUNCS(strstr getopt getfsenty)
|
||||
|
||||
# Check for uint[8,16,32]_t
|
||||
AC_TYPE_UINT8_T
|
||||
AC_TYPE_UINT16_T
|
||||
AC_TYPE_UINT32_T
|
||||
|
||||
# Check for required libraries
|
||||
PKG_CHECK_MODULES([uev], [libuev >= 1.5.2])
|
||||
PKG_CHECK_MODULES([lite], [libite >= 1.8.2])
|
||||
|
||||
# Check for configured Finit features
|
||||
AC_ARG_ENABLE(emergency_shell,
|
||||
AS_HELP_STRING([--enable-emergency-shell], [Experimental emergency fallback at boot.
|
||||
Only use this for debugging very early boot problems with Finit.]))
|
||||
|
||||
AC_ARG_ENABLE(fallback_shell,
|
||||
AS_HELP_STRING([--enable-fallback-shell], [Start a shell if no TTYs can start.]))
|
||||
|
||||
AC_ARG_ENABLE(rw-rootfs,
|
||||
AS_HELP_STRING([--enable-rw-rootfs], [Remount / R/W at boot, usually not for embedded]))
|
||||
|
||||
AC_ARG_ENABLE(silent,
|
||||
AS_HELP_STRING([--enable-silent], [Completely silent operation, not even boot messages]))
|
||||
|
||||
AC_ARG_ENABLE(watchdog,
|
||||
AS_HELP_STRING([--enable-watchdog], [Enable built-in watchdog, uses /dev/watchdog]))
|
||||
|
||||
AC_ARG_ENABLE(inetd,
|
||||
AS_HELP_STRING([--disable-inetd], [Disable built-in inetd super server, default enabled]))
|
||||
|
||||
AC_ARG_ENABLE(quiet,
|
||||
AS_HELP_STRING([--disable-quiet], [Default Finit obeys the kernel quiet option]))
|
||||
|
||||
# Check for extra plugins to enable
|
||||
enable_all_plugins=auto
|
||||
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([inetd-echo], [no], [Inetd plugin: echo server, RFC862])
|
||||
AC_PLUGIN([inetd-chargen], [no], [Inetd plugin: character generator, RFC864])
|
||||
AC_PLUGIN([inetd-daytime], [no], [Inetd plugin: daytime server, RFC867])
|
||||
AC_PLUGIN([inetd-discard], [no], [Inetd plugin: discard server, RFC863])
|
||||
AC_PLUGIN([inetd-time], [no], [Inetd plugin: time (rdate) server, RFC868])
|
||||
AC_PLUGIN([lost], [no], [Example HOOK_SVC_LOST plugin, very noisy as-is!])
|
||||
AC_PLUGIN([resolvconf], [no], [Setup necessary files for resolvconf])
|
||||
AC_PLUGIN([x11-common], [no], [Console setup (for X)])
|
||||
AC_PLUGIN([netlink], [yes], [Basic netlink plugin for IFUP/IFDN and GW events. Can be replaced with externally built plugin that links with libnl or similar.])
|
||||
|
||||
# Check for extra arguments or packages
|
||||
AC_ARG_WITH(heading,
|
||||
AS_HELP_STRING([--with-heading=GREET], [Display GREET instead of Finit version at boot]),
|
||||
[heading=$withval], [heading="$PACKAGE_NAME v$PACKAGE_VERSION"])
|
||||
|
||||
AC_ARG_WITH(fifo,
|
||||
AS_HELP_STRING([--with-fifo=FIFO], [FIFO for init/telinit clients, default /var/run/initctl]),
|
||||
[fifo=$withval], [fifo=/var/run/initctl])
|
||||
|
||||
AC_ARG_WITH(plugindir,
|
||||
AS_HELP_STRING([--with-plugindir=DIR], [Finit plugin directory, default /lib/finit/plugins]),
|
||||
[pkglibdir=$withval], [pkglibdir=$libdir/finit/plugins])
|
||||
AC_SUBST([pkglibdir])
|
||||
|
||||
AC_ARG_WITH(config,
|
||||
AS_HELP_STRING([--with-config=CONFIG], [Finit bootstrap config file, default /etc/finit.conf]),
|
||||
[conf=$withval], [conf=$sysconfdir/finit.conf])
|
||||
|
||||
AC_ARG_WITH(rcsd,
|
||||
AS_HELP_STRING([--with-rcsd=DIR], [Finit rcS.d/ directory, default /etc/finit.d]),
|
||||
[rcsd=$withval], [rcsd=$sysconfdir/finit.d])
|
||||
|
||||
AC_ARG_WITH(rc-local,
|
||||
AS_HELP_STRING([--with-rc-local=FILE], [SysV init /etc/rc.local file, default /etc/rc.local]),
|
||||
[rclocal=$withval], [rclocal=$sysconfdir/rc.local])
|
||||
|
||||
AC_ARG_WITH(console,
|
||||
AS_HELP_STRING([--with-console=DEV], [Console to use, default: /dev/console]),
|
||||
[console=$withval], [console=/dev/console])
|
||||
|
||||
AC_ARG_WITH(username,
|
||||
AS_HELP_STRING([--with-username=USER], [User for 'startx' .conf option, default: root]),
|
||||
[username=$withval], [username=root])
|
||||
|
||||
AC_ARG_WITH(hostname,
|
||||
AS_HELP_STRING([--with-hostname=NAME], [If /etc/hostname is missing, default: noname]),
|
||||
[hostname=$withval], [hostname=noname])
|
||||
|
||||
AC_ARG_WITH(runlevel,
|
||||
AS_HELP_STRING([--with-runlevel=N], [Runlevel to switch to after bootstrap, default: 2]),
|
||||
[runlevel=$withval], [runlevel=2])
|
||||
|
||||
AC_ARG_WITH(random-seed,
|
||||
AS_HELP_STRING([--with-random-seed=FILE], [Save a random seed for /dev/urandom across reboots, default /var/lib/misc/random-seed]),
|
||||
[random_seed=$withval], [random_seed=/var/lib/misc/random-seed])
|
||||
|
||||
|
||||
### Enable features ###########################################################################
|
||||
|
||||
# Create config.h from selected features and fallback defautls
|
||||
AS_IF([test "x$enable_emergency_shell" = "xyes"], [
|
||||
AC_DEFINE(EMERGENCY_SHELL, 1, [Fork off init and let PID 1 wait and start /bin/sh if init crashes.])])
|
||||
|
||||
AS_IF([test "x$enable_fallback_shell" = "xyes"], [
|
||||
AC_DEFINE(FALLBACK_SHELL, 1, [Start /bin/sh on console if no TTYs.])])
|
||||
|
||||
AS_IF([test "x$enable_rw_rootfs" = "xyes"], [
|
||||
AC_DEFINE(REMOUNT_ROOTFS, 1, [Remount / as rw at boot])])
|
||||
|
||||
AS_IF([test "x$enable_silent" = "xyes"], [
|
||||
AC_DEFINE(SILENT_MODE, 1, [Completely silent operation, not even boot messages])
|
||||
], [
|
||||
AC_DEFINE(SILENT_MODE, 0, [Normal output, default])])
|
||||
|
||||
AS_IF([test "x$enable_watchdog" = "xyes"], [
|
||||
AC_DEFINE(BUILTIN_WATCHDOG, 1, [Enable built-in watchdog, kicks on /dev/watchdog])])
|
||||
|
||||
### Disable features ###########################################################################
|
||||
AS_IF([test "x$enable_inetd" != "xno"],
|
||||
enable_inetd="yes", [
|
||||
AC_DEFINE(INETD_DISABLED, 1, [Disable built-in inetd])])
|
||||
|
||||
AS_IF([test "x$enable_quiet" != "xno"], [
|
||||
AC_DEFINE(QUIET_MODE, 1, [Silent, after initial boot, no stopping/starting messages. Default: 1])
|
||||
], [
|
||||
AC_DEFINE(QUIET_MODE, 0, [Silent, after initial boot, no stopping/starting messages. Default: 1])])
|
||||
|
||||
### With features ##############################################################################
|
||||
AS_IF([test "x$with_fifo" != "xno"], [
|
||||
AS_IF([test "x$fifo" = "xyes"], [
|
||||
fifo='/var/run/initctl'])])
|
||||
AC_EXPAND_DIR(lurvig, "$fifo")
|
||||
AC_DEFINE_UNQUOTED(FINIT_FIFO, "$lurvig", [FIFO for old style init/telinit client programs])
|
||||
|
||||
AS_IF([test "x$with_config" != "xno"], [
|
||||
AS_IF([test "x$config" = "xyes"], [
|
||||
conf=$sysconfdir/finit.conf])])
|
||||
AC_EXPAND_DIR(lurvig, "$conf")
|
||||
AC_DEFINE_UNQUOTED(FINIT_CONF, "$lurvig", [Main Finit configuration file, default /etc/finit.conf])
|
||||
|
||||
AS_IF([test "x$with_rcsd" != "xno"], [
|
||||
AS_IF([test "x$rcsd" = "xyes"], [
|
||||
rcsd=$sysconfdir/finit.d])])
|
||||
AC_EXPAND_DIR(lurvig, "$rcsd")
|
||||
AC_DEFINE_UNQUOTED(FINIT_RCSD, "$lurvig", [Finit rcS.d/, default /etc/finit.d])
|
||||
|
||||
AS_IF([test "x$with_rc_local" != "xno"], [
|
||||
AS_IF([test "x$rclocal" = "xyes"], [
|
||||
rclocal=$sysconfdir/rc.local])])
|
||||
AC_EXPAND_DIR(lurvig, "$rclocal")
|
||||
AC_DEFINE_UNQUOTED(FINIT_RC_LOCAL, "$lurvig", [Compat SysV /etc/rc.local file to run last at boot.])
|
||||
|
||||
AS_IF([test "x$with_heading" != "xno"], [
|
||||
AS_IF([test "x$heading" = "xyes"], [
|
||||
heading="$PACKAGE_NAME v$PACKAGE_VERSION"])])
|
||||
AC_DEFINE_UNQUOTED(INIT_HEADING, "$heading", [Displayed by Finit at boot])
|
||||
|
||||
AS_IF([test "x$with_console" != "xno"], [
|
||||
AS_IF([test "x$console" = "xyes"], [
|
||||
console=/dev/console])])
|
||||
AC_DEFINE_UNQUOTED(CONSOLE, "$console", [Default console to use])
|
||||
|
||||
AS_IF([test "x$with_username" != "xno"], [
|
||||
AS_IF([test "x$username" = "xyes"], [
|
||||
username=root])])
|
||||
AC_DEFINE_UNQUOTED(DEFUSER, "$username", [Used for startx .conf option])
|
||||
|
||||
AS_IF([test "x$with_hostname" != "xno"], [
|
||||
AS_IF([test "x$hostname" = "xyes"], [
|
||||
hostname=noname])])
|
||||
AC_DEFINE_UNQUOTED(DEFHOST, "$hostname", [For /etc/hostname])
|
||||
|
||||
AS_IF([test "x$with_runlevel" != "xno"], [
|
||||
AS_IF([test "x$runlevel" = "xyes"], [
|
||||
AC_DEFINE_UNQUOTED(RUNLEVEL, 2, [Default runlevel to start after S])])
|
||||
AC_DEFINE_UNQUOTED(RUNLEVEL, $runlevel, [Runlevel to start after S])])
|
||||
|
||||
AS_IF([test "x$with_random_seed" != "xno"], [
|
||||
AS_IF([test "x$random_seed" = "xyes"], [
|
||||
random_seed=/var/lib/misc/random-seed])
|
||||
AC_EXPAND_DIR(lurvig, "$random_seed")
|
||||
AC_DEFINE_UNQUOTED(RANDOMSEED, "$lurvig", [Improve random at boot by seeding it with sth from before.])])
|
||||
|
||||
# Control build with automake flags
|
||||
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
||||
AM_CONDITIONAL(INETD, [test "x$enable_inetd" = "xyes"])
|
||||
AM_CONDITIONAL(WATCHDOGD, [test "x$enable_watchdog" = "xyes"])
|
||||
|
||||
# Generate all files
|
||||
AC_OUTPUT
|
||||
@@ -0,0 +1,12 @@
|
||||
Finit Examples
|
||||
==============
|
||||
|
||||
This section provides configuration examples and helpful tools to
|
||||
install and try out Finit on various Linux distributions.
|
||||
|
||||
* [Alpine](alpine/)
|
||||
* [Debian](debian/)
|
||||
|
||||
If you have ideas on how to simplify, extend, or even add new example
|
||||
configurations for other distributions you are most welcome! :)
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
HowTo: Finit on Alpine Linux 3.4
|
||||
================================
|
||||
|
||||
Mini HowTo using Finit to boot an Alpine Linux system. It is assumed
|
||||
that the user has already installed a compiler, C library header files,
|
||||
and other tools needed to build a GNU configure based project.
|
||||
|
||||
To start with you need to first install [libuEv][] and [libite][], by
|
||||
default they install to `/usr/local` and Alpine's `pkg-config` does not
|
||||
look for libraries and header files there. So the `PKG_CONFIG_LIBDIR`
|
||||
environment variable has to be used:
|
||||
|
||||
alpine:~/finit# PKG_CONFIG_LIBDIR=/usr/local/lib/pkgconfig ./configure \
|
||||
--enable-rw-rootfs --enable-x11-common-plugin \
|
||||
--enable-alsa-utils-plugin --enable-inetd-echo-plugin \
|
||||
--enable-inetd-chargen-plugin --enable-inetd-daytime-plugin \
|
||||
--enable-inetd-discard-plugin --enable-inetd-time-plugin \
|
||||
--with-heading="Alpine Linux 3.4" --with-hostname=alpine
|
||||
|
||||
The plugins are optional, but the other configure flags are *not*.
|
||||
|
||||
alpine:~/finit# make all install
|
||||
|
||||
The installation skips `/sbin/init`, because it already exists, and
|
||||
Alpine is hard coded to use it. So you have to change the symlink
|
||||
yourself to point to `finit` instead of `/bin/busybox`.
|
||||
|
||||
alpine:~/finit# cd /sbin
|
||||
alpine:/sbin# rm init
|
||||
alpine:/sbin# ln -s finit init
|
||||
|
||||
Before rebooting, make sure to set up a [/etc/finit.conf](finit.conf),
|
||||
and possibly also an [/etc/rc.local](rc.local) for one-shot set up and
|
||||
initialization like keyboard language etc. You can use the files in
|
||||
this directory as templates -- check them both if they need to be
|
||||
tweaked for your installation, you may not run Dropbear SSH or speak
|
||||
Swedish ...
|
||||
|
||||
[libuEv]: https://github.com/troglobit/libuev
|
||||
[libite]: https://github.com/troglobit/libite
|
||||
|
||||
<!--
|
||||
-- Local Variables:
|
||||
-- mode: markdown
|
||||
-- End:
|
||||
-->
|
||||
@@ -0,0 +1,40 @@
|
||||
# /etc/finit.conf: Example for Alpine Linux 3.4
|
||||
|
||||
# Modules to load
|
||||
#module qxl
|
||||
#module fbcon
|
||||
module button
|
||||
module evdev
|
||||
|
||||
# Runlevel to start after bootstrap, runlevel 'S'
|
||||
runlevel 2
|
||||
|
||||
# Services to be monitored and respawned as needed
|
||||
service [S12345] /sbin/klogd -n -- Kernel log daemon
|
||||
service [S12345] /sbin/syslogd -n -- Syslog daemon
|
||||
|
||||
# Network bringup script, blocks boot like run stanza, use below task instead
|
||||
#network /sbin/ifup -a
|
||||
|
||||
### Every line below can be a service/task per file in /etc/finit.d/*.conf ###
|
||||
|
||||
# Network bringup not needed if /etc/network/interfaces is used.
|
||||
task [2345] log <svc/sbin/syslogd> /sbin/ifup -a -- Networking
|
||||
|
||||
# Depends on syslogd having started. Redirect any output to log.
|
||||
service [2345] log <svc/sbin/syslogd> /usr/sbin/acpid -f -- ACPI daemon
|
||||
|
||||
# Silly Busybox ntpd has no option to use syslog when running in foreground
|
||||
service [2345] log <svc/sbin/syslogd> /usr/sbin/ntpd -n -N -p pool.ntp.org
|
||||
|
||||
# Start SSH daemon as soon as basic networking comes up
|
||||
service [2345] <net/lo/up> /usr/sbin/dropbear -R -F -p 22 -- Dropbear SSH daemon
|
||||
service [2345] <svc/sbin/syslogd> /usr/sbin/crond -f -S -c /etc/crontabs -- Cron daemon
|
||||
|
||||
# Handle PWR button to shutdown/reboot -- useful in Qemu (virt-manager)
|
||||
service [2345] /sbin/acpid -f -- ACPI daemon
|
||||
|
||||
# Consoles to start getty on when system is up
|
||||
tty /dev/tty1
|
||||
tty /dev/tty2
|
||||
tty /dev/tty3
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
zcat /etc/keymap/sv-latin1.bmap.gz | loadkmap
|
||||
@@ -0,0 +1,52 @@
|
||||
HowTo: Finit on Debian Jessie
|
||||
=============================
|
||||
|
||||
Mini HowTo using Finit to boot Debian GNU/Linux 8.5 (Jessie). It is
|
||||
assumed that the user has already installed a compiler, C library header
|
||||
files, and other tools needed to build a GNU configure based project.
|
||||
|
||||
Also, Finit has only been verified to work with the Debian *Server* ed.
|
||||
I.e., during install — skip GNOME and other X stuff to get a plain and
|
||||
usable Debian server install, which we can add X-Window to later :-)
|
||||
|
||||
Now, I started off by replacing systemd from the base install with the
|
||||
old SysV init, using [this HowTo][1], you may not need to do that, but
|
||||
for me it was easier — and also a great rebuttal to all the systemd
|
||||
haters out there (yeah, even though I speak for the alternative PID 1
|
||||
movement I don't hate systemd :P) it is possible to still run Debian
|
||||
without systemd! Anyway, this text was based on that experience.
|
||||
|
||||
Like the [Alpine HowTo](../alpine/), you need to install [libuEv][] and
|
||||
[libite][], but since this is Debian — which takes infinite care of its
|
||||
users ♥ ♥ ♥ we don't need to worry about `pkg-config`, except for having
|
||||
it installed so it can locate the uEv and lite libraries.
|
||||
|
||||
> With Debian everything just works!™
|
||||
|
||||
The following build and install script can be used to configure, build,
|
||||
install and set up your system to run Finit:
|
||||
|
||||
debian:~/finit$ contrib/debian/build.sh
|
||||
|
||||
Since `/sbin/init` already exists on your system the script creates
|
||||
another entry in your GRUB config, in `/etc/grub.d/40_custom`, where
|
||||
`init=/sbin/finit` is added to your kernel line. You could of course
|
||||
also change the `/sbin/init` symlink and uninstall systemd/SysV init if
|
||||
everything works fine, but that's up to you.
|
||||
|
||||
Before rebooting, read up on [/etc/finit.conf](finit.conf) and notice
|
||||
how `/etc/start.d/` and `/etc/rc.local` can be used to extend the boot
|
||||
with simpler setup tasks on your system — see the docu for details.
|
||||
|
||||
Have fun!
|
||||
/Joachim ツ
|
||||
|
||||
[1]: http://without-systemd.org/wiki/index.php/How_to_remove_systemd_from_a_Debian_jessie/sid_installation
|
||||
[libuEv]: https://github.com/troglobit/libuev
|
||||
[libite]: https://github.com/troglobit/libite
|
||||
|
||||
<!--
|
||||
-- Local Variables:
|
||||
-- mode: markdown
|
||||
-- End:
|
||||
-->
|
||||
Executable
+62
@@ -0,0 +1,62 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# This script configures Finit for Debian, which needs a few more plugins
|
||||
# and tweaks than an embedded system usually does.
|
||||
#
|
||||
# Usage:
|
||||
# user@jessie:~/finit$ contrib/debian/build.sh
|
||||
#
|
||||
|
||||
echo
|
||||
echo "*** Configuring Finit for Debian"
|
||||
|
||||
if [ ! -e configure ]; then
|
||||
echo " The configure script is missing, maybe you're using a GIT checkout?"
|
||||
echo " Attempting to run the autogen.sh script, you need these tools:"
|
||||
echo " autoconf, automake, libtool, pkg-config ..."
|
||||
echo
|
||||
./autogen.sh
|
||||
fi
|
||||
echo
|
||||
|
||||
./configure --enable-rw-rootfs --enable-dbus-plugin --enable-x11-common-plugin \
|
||||
--enable-alsa-utils-plugin --with-random-seed=/var/lib/urandom/random-seed \
|
||||
--with-heading="Debian GNU/Linux 8.5" --with-hostname=jessie \
|
||||
--enable-inetd-echo-plugin --enable-inetd-chargen-plugin \
|
||||
--enable-inetd-daytime-plugin --enable-inetd-discard-plugin \
|
||||
--enable-inetd-time-plugin
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo
|
||||
echo "*** Configure script failed, have you installed libuEV and libite?"
|
||||
echo
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "*** Building ..."
|
||||
echo
|
||||
make
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo
|
||||
echo "*** The build failed for some reason"
|
||||
echo
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "*** Done"
|
||||
echo
|
||||
|
||||
read -p "*** Run (sudo) install script (y/N)? " yorn
|
||||
if [ "x$yorn" = "xy" -o "x$yorn" = "xY" ]; then
|
||||
sudo contrib/debian/install.sh
|
||||
else
|
||||
echo
|
||||
echo "*** Use 'sudo contrib/debian/install.sh' later to install Finit"
|
||||
echo
|
||||
fi
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
# /etc/finit.conf: Example for Debian GNU/Linux 8.5
|
||||
# Here we use one big (?) finit.conf, but all non-bootstrap services
|
||||
# can just as easily be listed in a separate /etc/finit.d/*.conf
|
||||
|
||||
# The host directive is a fallback if /etc/hostname is missing
|
||||
host jessie
|
||||
|
||||
# The user directive is only for the startx directive, which in turn is
|
||||
# just like a service but with a different user. Services can also run
|
||||
# with a different user, using the @username syntax
|
||||
user root
|
||||
|
||||
# Linux kernel modules to load, /etc/modprobe is not used
|
||||
module button
|
||||
module evdev
|
||||
module loop
|
||||
module psmouse
|
||||
|
||||
# Runlevel to start after bootstrap, runlevel 'S'.
|
||||
# Change this to 3 to start XDM at boot.
|
||||
runlevel 2
|
||||
|
||||
# Some services may need to start very early, e.g. a watchdog daemon.
|
||||
# Runlevel [S] (bootStrap) is useful for that. It cannot be switched
|
||||
# to at runtime either, so tasks and run directives usually live here.
|
||||
# Please note, the run directive is blocking, so be careful!
|
||||
#service [S12345] /sbin/watchdogd -n -- Watchdog daemon
|
||||
#run [S] /sbin/probe -- system probe
|
||||
#run [S] /sbin/setupd --bootstrap -- system bootstrap
|
||||
service [S12345] /usr/sbin/rsyslogd -n -- Syslog daemon
|
||||
|
||||
# Network bringup script not needed if /etc/network/interfaces is used
|
||||
#network service networking start
|
||||
|
||||
# Regular services to be monitored and respawned as needed. Here we use
|
||||
# a (svc) condition, the listed service must be started (waits for the
|
||||
# PID file to be created in /run/*.pid) before starting either service,
|
||||
# (net) conditions are also available.
|
||||
service [2345] <svc/usr/sbin/rsyslogd> log /usr/sbin/acpid -f -- ACPI daemon
|
||||
service [2345] <svc/usr/sbin/rsyslogd> /usr/sbin/sshd -D -- SSH daemon
|
||||
|
||||
# Here we use XDM since it has few dependencies (relatively speaking).
|
||||
# It is also an example of a service (startx is an alias for service)
|
||||
# that does not have a -- description.
|
||||
#service [3] /usr/sbin/lightdm -- X-Window Display Manager
|
||||
startx [3] /usr/bin/xdm -nodaemon
|
||||
|
||||
# Run old-style start scripts from this directory. Very similar to how
|
||||
# SysV init works: 01first, 02second, etc. see run-parsts(8) for details
|
||||
runparts /etc/start.d
|
||||
# |-- S03keyboard-setup
|
||||
# |-- S17kbd
|
||||
# `- S18console-setup
|
||||
|
||||
# Virtual consoles to start getty on. Runlevels, speed & $TERM optional
|
||||
# TTYs are also services, sort of, but they are guaranteed to start at
|
||||
# the very end of the boot sequence. Finit comes with a built-in getty.
|
||||
tty [12345] /dev/tty1 115200 vt100
|
||||
tty [2345] /dev/tty2 38400 linux
|
||||
tty [2345] /dev/tty3 38400 linux
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
exec tail -n +3 $0
|
||||
# This file provides an easy way to add custom menu entries. Simply type the
|
||||
# menu entries you want to add after this comment. Be careful not to change
|
||||
# the 'exec tail' line above.
|
||||
|
||||
menuentry '$MENU with Finit' --class $TYPE --class gnu-linux --class gnu --class os --user {
|
||||
insmod gzio
|
||||
insmod part_msdos
|
||||
insmod ext2
|
||||
search --no-floppy --fs-uuid --set=root $BOOT
|
||||
linux /vmlinuz root=UUID=$ROOT ro quiet init=/sbin/finit
|
||||
initrd /initrd.img
|
||||
}
|
||||
Executable
+55
@@ -0,0 +1,55 @@
|
||||
#!/bin/sh
|
||||
|
||||
SYMLINKS="start.d/*"
|
||||
FILES="finit.conf"
|
||||
|
||||
if [ "x`id -u`" != "x0" ]; then
|
||||
echo
|
||||
echo "=> Unfortunately this script must run as root (sudo) <="
|
||||
echo
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Adjust base directory
|
||||
grep -q Debian os-release 2>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
cd ../..
|
||||
elif [ ! -e finit.c ]; then
|
||||
echo "Please run this script from the Finit base directory."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Install Finit on Debian 8 (jessie)"
|
||||
echo "========================================================================"
|
||||
echo "/sbin/finit - PID 1"
|
||||
echo "/lib/finit/plugins/* - All enabled Finit plugins"
|
||||
echo "/etc/finit.conf - Instead of units or /etc/init.d Finit can have"
|
||||
echo " one config for your system. Or you can split"
|
||||
echo " it in service(s) per file in /etc/finit.d/"
|
||||
echo "/etc/start.d/ - Simple Debian setup scripts run with run-parts(8)"
|
||||
echo "/etc/grub.d/40_custom - Add menu entry to the Grub boot loader"
|
||||
echo
|
||||
read -p "Do you want to continue (y/N)? " yorn
|
||||
echo
|
||||
|
||||
if [ "x$yorn" = "xy" -o "x$yorn" = "xY" ]; then
|
||||
echo "Installing Finit files ..."
|
||||
make install
|
||||
cd `dirname $0`
|
||||
mkdir -p /etc/start.d
|
||||
for file in $FILES; do
|
||||
install -vbD $file /etc/$file
|
||||
done
|
||||
for link in $SYMLINKS; do
|
||||
cp -va $link /etc/$link
|
||||
done
|
||||
echo "Setting up a GRUB boot entry ..."
|
||||
MENU=`grep gnu-linux /boot/grub/grub.cfg |head -1 |sed "s/menuentry '\([^']*\).*/\1/"`
|
||||
TYPE=`grep gnu-linux /boot/grub/grub.cfg |head -1 |sed "s/.*' --class \([a-z]*\).*/\1/"`
|
||||
BOOT=`grep set=root /boot/grub/grub.cfg |head -1 |sed 's/.* \([a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*\).*/\1/'`
|
||||
ROOT=`grep root=UUID /boot/grub/grub.cfg |head -1 |sed 's/.*UUID=\([a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*-[a-f0-9]*\).*/\1/'`
|
||||
cat grub.d/40_custom | sed "s,\$BOOT,$BOOT,;s,\$ROOT,$ROOT,;s,\$TYPE,$TYPE,;s,\$MENU,$MENU," >/etc/grub.d/40_custom
|
||||
update-grub
|
||||
else
|
||||
echo "Aborting install."
|
||||
fi
|
||||
@@ -0,0 +1,8 @@
|
||||
PRETTY_NAME="Debian GNU/Linux 8 (jessie)"
|
||||
NAME="Debian GNU/Linux"
|
||||
VERSION_ID="8"
|
||||
VERSION="8 (jessie)"
|
||||
ID=debian
|
||||
HOME_URL="http://www.debian.org/"
|
||||
SUPPORT_URL="http://www.debian.org/support"
|
||||
BUG_REPORT_URL="https://bugs.debian.org/"
|
||||
@@ -0,0 +1 @@
|
||||
../init.d/keyboard-setup
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../init.d/kbd
|
||||
+1
@@ -0,0 +1 @@
|
||||
../init.d/console-setup
|
||||
Executable
+65
@@ -0,0 +1,65 @@
|
||||
#!/bin/sh
|
||||
### BEGIN INIT INFO
|
||||
# Provides: keyboard-setup
|
||||
# Required-Start: mountkernfs
|
||||
# Required-Stop:
|
||||
# Should-Start: keymap udev
|
||||
# X-Start-Before: checkroot
|
||||
# Default-Start: S
|
||||
# Default-Stop:
|
||||
# X-Interactive: true
|
||||
# Short-Description: Set preliminary keymap
|
||||
# Description: Set the console keyboard as early as possible
|
||||
# so during the file systems checks the administrator
|
||||
# can interact. At this stage of the boot process
|
||||
# only the ASCII symbols are supported.
|
||||
### END INIT INFO
|
||||
|
||||
set -e
|
||||
|
||||
# This script is not used by keyboard-configuration. It is used
|
||||
# jointly by console-setup and console-setup-mini
|
||||
|
||||
test -f /bin/setupcon || exit 0
|
||||
|
||||
if [ -f /lib/lsb/init-functions ]; then
|
||||
. /lib/lsb/init-functions
|
||||
else
|
||||
log_action_begin_msg () {
|
||||
echo -n "$@... "
|
||||
}
|
||||
|
||||
log_action_end_msg () {
|
||||
if [ "$1" -eq 0 ]; then
|
||||
echo done.
|
||||
else
|
||||
echo failed.
|
||||
fi
|
||||
}
|
||||
fi
|
||||
|
||||
case "$1" in
|
||||
stop)
|
||||
# keyboard-setup isn't a daemon
|
||||
;;
|
||||
start|force-reload|restart|reload)
|
||||
case `readlink /proc/self/fd/2` in
|
||||
/dev/tty[0-9]*|/dev/vc/[0-9]*|/dev/console)
|
||||
log_action_begin_msg "Setting preliminary keymap"
|
||||
if setupcon -k; then
|
||||
log_action_end_msg 0
|
||||
else
|
||||
log_action_end_msg $?
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
echo 'Usage: /etc/init.d/keyboard-setup {start|reload|restart|force-reload|stop}'
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
Executable
+81
@@ -0,0 +1,81 @@
|
||||
#!/bin/sh
|
||||
### BEGIN INIT INFO
|
||||
# Provides: acpid
|
||||
# Required-Start: $remote_fs $syslog
|
||||
# Required-Stop: $remote_fs $syslog
|
||||
# X-Start-Before: kdm gdm xdm hal
|
||||
# X-Stop-After: kdm gdm xdm hal
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop:
|
||||
# Short-Description: Start the Advanced Configuration and Power Interface daemon
|
||||
# Description: Provide a socket for X11, hald and others to multiplex
|
||||
# kernel ACPI events.
|
||||
### END INIT INFO
|
||||
|
||||
set -e
|
||||
|
||||
ACPID="/usr/sbin/acpid"
|
||||
DEFAULTS="/etc/default/acpid"
|
||||
|
||||
# Check for daemon presence
|
||||
[ -x "$ACPID" ] || exit 0
|
||||
|
||||
OPTIONS=""
|
||||
MODULES=""
|
||||
# Include acpid defaults if available
|
||||
[ -r "$DEFAULTS" ] && . "$DEFAULTS"
|
||||
|
||||
# Get lsb functions
|
||||
. /lib/lsb/init-functions
|
||||
|
||||
# As the name says. If the kernel supports modules, it'll try to load
|
||||
# the ones listed in "MODULES".
|
||||
load_modules() {
|
||||
[ -f /proc/modules ] || return 0
|
||||
if [ "$MODULES" = "all" ]; then
|
||||
MODULES="$(sed -rn 's#^(/lib/modules/[^/]+/)?kernel/(drivers|ubuntu)/acpi/([^/]+/)*(.*)\.ko:.*#\4#p' "/lib/modules/$(uname -r)/modules.dep")"
|
||||
fi
|
||||
|
||||
if [ -z "$MODULES" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
log_begin_msg "Loading ACPI kernel modules..."
|
||||
# work around a bug in initramfs which leaks this env var Launchpad #291619
|
||||
# and a bug in modprobe --all --quiet which doesn't load all modules and
|
||||
# exits with non-zero exit status Debian #504088
|
||||
unset MODPROBE_OPTIONS
|
||||
modprobe --all --use-blacklist $MODULES 2>/dev/null
|
||||
log_end_msg $?
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
load_modules || true
|
||||
log_begin_msg "Starting ACPI services..."
|
||||
start-stop-daemon --start --quiet --oknodo --exec "$ACPID" -- $OPTIONS
|
||||
log_end_msg $?
|
||||
;;
|
||||
stop)
|
||||
log_begin_msg "Stopping ACPI services..."
|
||||
start-stop-daemon --stop --quiet --oknodo --retry 2 --exec "$ACPID"
|
||||
log_end_msg $?
|
||||
;;
|
||||
restart)
|
||||
$0 stop
|
||||
sleep 1
|
||||
$0 start
|
||||
;;
|
||||
reload|force-reload)
|
||||
log_begin_msg "Reloading ACPI services..."
|
||||
start-stop-daemon --stop --signal 1 --exec "$ACPID"
|
||||
log_end_msg $?
|
||||
;;
|
||||
status)
|
||||
status_of_proc "$ACPID" acpid
|
||||
;;
|
||||
*)
|
||||
log_success_msg "Usage: /etc/init.d/acpid {start|stop|restart|reload|force-reload|status}"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
Executable
+259
@@ -0,0 +1,259 @@
|
||||
#!/bin/sh
|
||||
### BEGIN INIT INFO
|
||||
# Provides: kbd
|
||||
# Required-Start: $remote_fs
|
||||
# Required-Stop:
|
||||
# Default-Start: S
|
||||
# Default-Stop:
|
||||
# X-Interactive: true
|
||||
# Description: Set console screen modes and fonts
|
||||
# Short-Description: Prepare console
|
||||
### END INIT INFO
|
||||
|
||||
# This is the boot script for the `kbd' package.
|
||||
# It loads parameters from /etc/kbd/config and maybe loads
|
||||
# default font and map.
|
||||
# (c) 1997 Yann Dirson
|
||||
|
||||
PKG=kbd
|
||||
if [ -r /etc/$PKG/config ]; then
|
||||
. /etc/$PKG/config
|
||||
fi
|
||||
|
||||
if [ -d /etc/$PKG/config.d ]; then
|
||||
for i in `run-parts --list /etc/$PKG/config.d `; do
|
||||
. $i
|
||||
done
|
||||
fi
|
||||
|
||||
# do some magic with the variables for compatibility with the config
|
||||
# file of console-tools
|
||||
for vc in '' `set | grep "^.*_vc[0-9][0-9]*=" | sed 's/^.*\(_vc[0-9][0-9]*\)=.*/\1/'`
|
||||
do
|
||||
eval [ '"'\${SCREEN_FONT$vc}'"' ] && eval CONSOLE_FONT$vc=\${CONSOLE_FONT$vc:-\${SCREEN_FONT$vc}}
|
||||
eval [ '"'\${SCREEN_FONT_MAP$vc}'"' ] && eval FONT_MAP$vc=\${FONT_MAP$vc:-\${SCREEN_FONT_MAP$vc}}
|
||||
eval [ '"'\${APP_CHARSET_MAP$vc}'"' ] && eval CONSOLE_MAP$vc=\${CONSOLE_MAP$vc:-\${APP_CHARSET_MAP$vc}}
|
||||
done
|
||||
|
||||
. /lib/lsb/init-functions
|
||||
|
||||
PATH=/sbin:/bin:/usr/sbin:/usr/bin
|
||||
SETFONT_OPT="-v"
|
||||
|
||||
if which setupcon >/dev/null
|
||||
then
|
||||
HAVE_SETUPCON=yes
|
||||
fi
|
||||
|
||||
# set DEVICE_PREFIX depending on devfs/udev
|
||||
if [ -d /dev/vc ]; then
|
||||
DEVICE_PREFIX="/dev/vc/"
|
||||
else
|
||||
DEVICE_PREFIX="/dev/tty"
|
||||
fi
|
||||
|
||||
# determine the system charmap
|
||||
ENV_FILE=''
|
||||
[ -r /etc/environment ] && ENV_FILE="/etc/environment"
|
||||
[ -r /etc/default/locale ] && ENV_FILE="/etc/default/locale"
|
||||
[ "$ENV_FILE" ] && CHARMAP=$(set -a && . "$ENV_FILE" && locale charmap)
|
||||
if [ "$CHARMAP" = "UTF-8" -a -z "$CONSOLE_MAP" ]
|
||||
then
|
||||
UNICODE_MODE=yes
|
||||
fi
|
||||
|
||||
reset_vga_palette ()
|
||||
{
|
||||
if [ -f /proc/fb ]; then
|
||||
# They have a framebuffer device.
|
||||
# That means we have work to do...
|
||||
echo -n "]R"
|
||||
fi
|
||||
}
|
||||
|
||||
unicode_start_stop ()
|
||||
{
|
||||
vc=$1
|
||||
if [ -n "$UNICODE_MODE" -a -z "`eval echo \\$CONSOLE_MAP_vc$vc`" ]; then
|
||||
action=unicode_start
|
||||
else
|
||||
action=unicode_stop
|
||||
fi
|
||||
if [ "${CONSOLE_FONT}" ]; then
|
||||
$action "${CONSOLE_FONT}" < ${DEVICE_PREFIX}$vc > ${DEVICE_PREFIX}$vc 2> /dev/null || true
|
||||
else
|
||||
$action < ${DEVICE_PREFIX}$vc > ${DEVICE_PREFIX}$vc 2> /dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
setup ()
|
||||
{
|
||||
# be sure the main program is installed
|
||||
which setfont >/dev/null || return
|
||||
|
||||
VT="no"
|
||||
# If we can't access the console, quit
|
||||
CONSOLE_TYPE=`fgconsole 2>/dev/null` || return
|
||||
|
||||
if [ ! $CONSOLE_TYPE = "serial" ]; then
|
||||
readlink /proc/self/fd/0 | grep -q -e /dev/vc -e '/dev/tty[^p]' -e /dev/console
|
||||
if [ $? -eq 0 ]; then
|
||||
VT="yes"
|
||||
reset_vga_palette
|
||||
fi
|
||||
fi
|
||||
|
||||
[ $VT = "no" ] && return
|
||||
|
||||
# start vcstime
|
||||
if [ "${DO_VCSTIME}" = "yes" ] && which vcstime >/dev/null; then
|
||||
[ "$VERBOSE" != "no" ] && log_action_begin_msg "Starting clock on text console"
|
||||
vcstime &
|
||||
[ "$VERBOSE" != "no" ] && log_action_end_msg 0
|
||||
fi
|
||||
|
||||
if [ -d /etc/init ] && which initctl >/dev/null; then
|
||||
# Upstart
|
||||
LIST_CONSOLES=`cd /etc/init; find -name 'tty*.conf' -printf '%f ' | sed -e 's/[^0-9 ]//g'`
|
||||
else
|
||||
# traditional SysV init
|
||||
LIST_CONSOLES=`sed -e '/^ *#/d' /etc/inittab | grep -e '\<tty[0-9]*\>' | awk -F: '{printf "%s ", $1}'`
|
||||
fi
|
||||
|
||||
# Global default font+map
|
||||
if [ -z "${HAVE_SETUPCON}" -a "${CONSOLE_FONT}" ]; then
|
||||
[ "$VERBOSE" != "no" ] && log_action_begin_msg "Setting up general console font"
|
||||
sfm="${FONT_MAP}" && [ "$sfm" ] && sfm="-u $sfm"
|
||||
acm="${CONSOLE_MAP}" && [ "$acm" ] && acm="-m $acm"
|
||||
|
||||
# Set for the first 6 VCs (as they are allocated in /etc/inittab)
|
||||
for vc in $LIST_CONSOLES
|
||||
do
|
||||
if ! ( unicode_start_stop $vc \
|
||||
&& setfont -C ${DEVICE_PREFIX}$vc ${SETFONT_OPT} $sfm ${CONSOLE_FONT} $acm )
|
||||
then
|
||||
[ "$VERBOSE" != "no" ] && log_action_end_msg 1
|
||||
break
|
||||
fi
|
||||
done
|
||||
[ "$VERBOSE" != "no" ] && log_action_end_msg 0
|
||||
fi
|
||||
|
||||
# Default to Unicode mode for new VTs?
|
||||
if [ -f /sys/module/vt/parameters/default_utf8 ]; then
|
||||
if [ -n "$UNICODE_MODE" ]; then
|
||||
echo 1
|
||||
else
|
||||
echo 0
|
||||
fi > /sys/module/vt/parameters/default_utf8
|
||||
fi
|
||||
|
||||
# Per-VC font+sfm
|
||||
PERVC_FONTS="`set | grep "^CONSOLE_FONT_vc[0-9]*=" | tr -d \' `"
|
||||
if [ -z "${HAVE_SETUPCON}" -a "${PERVC_FONTS}" ]; then
|
||||
[ "$VERBOSE" != "no" ] && log_action_begin_msg "Setting up per-VC fonts"
|
||||
for font in ${PERVC_FONTS}
|
||||
do
|
||||
# extract VC and FONTNAME info from variable setting
|
||||
vc=`echo $font | cut -b16- | cut -d= -f1`
|
||||
eval font=\$CONSOLE_FONT_vc$vc
|
||||
# eventually find an associated SFM
|
||||
eval sfm=\${FONT_MAP_vc${vc}}
|
||||
[ "$sfm" ] && sfm="-u $sfm"
|
||||
if ! ( unicode_start_stop $vc \
|
||||
&& setfont -C ${DEVICE_PREFIX}$vc ${SETFONT_OPT} $sfm $font )
|
||||
then
|
||||
[ "$VERBOSE" != "no" ] && log_action_end_msg 1
|
||||
break
|
||||
fi
|
||||
done
|
||||
[ "$VERBOSE" != "no" ] && log_action_end_msg 0
|
||||
fi
|
||||
|
||||
|
||||
# Per-VC ACMs
|
||||
PERVC_ACMS="`set | grep "^CONSOLE_MAP_vc[0-9]*=" | tr -d \' `"
|
||||
if [ -z "${HAVE_SETUPCON}" -a "${PERVC_ACMS}" ]; then
|
||||
[ "$VERBOSE" != "no" ] && log_action_begin_msg "Setting up per-VC ACM's"
|
||||
for acm in ${PERVC_ACMS}
|
||||
do
|
||||
# extract VC and ACM_FONTNAME info from variable setting
|
||||
vc=`echo $acm | cut -b15- | cut -d= -f1`
|
||||
eval acm=\$CONSOLE_MAP_vc$vc
|
||||
if ! setfont -C "${DEVICE_PREFIX}$vc" ${SETFONT_OPT} -m "$acm"; then
|
||||
[ "$VERBOSE" != "no" ] && log_action_end_msg 1
|
||||
break
|
||||
fi
|
||||
done
|
||||
[ "$VERBOSE" != "no" ] && log_action_end_msg 0
|
||||
fi
|
||||
|
||||
|
||||
# screensaver stuff
|
||||
setterm_args=""
|
||||
if [ "$BLANK_TIME" ]; then
|
||||
setterm_args="$setterm_args -blank $BLANK_TIME"
|
||||
fi
|
||||
if [ "$BLANK_DPMS" ]; then
|
||||
setterm_args="$setterm_args -powersave $BLANK_DPMS"
|
||||
fi
|
||||
if [ "$POWERDOWN_TIME" ]; then
|
||||
setterm_args="$setterm_args -powerdown $POWERDOWN_TIME"
|
||||
fi
|
||||
if [ "$setterm_args" ]; then
|
||||
setterm $setterm_args
|
||||
fi
|
||||
|
||||
# Keyboard rate and delay
|
||||
KBDRATE_ARGS=""
|
||||
if [ -n "$KEYBOARD_RATE" ]; then
|
||||
KBDRATE_ARGS="-r $KEYBOARD_RATE"
|
||||
fi
|
||||
if [ -n "$KEYBOARD_DELAY" ]; then
|
||||
KBDRATE_ARGS="$KBDRATE_ARGS -d $KEYBOARD_DELAY"
|
||||
fi
|
||||
if [ -n "$KBDRATE_ARGS" ]; then
|
||||
[ "$VERBOSE" != "no" ] && log_action_begin_msg "Setting keyboard rate and delay"
|
||||
kbdrate -s $KBDRATE_ARGS
|
||||
[ "$VERBOSE" != "no" ] && log_action_end_msg 0
|
||||
fi
|
||||
|
||||
# Inform gpm if present, of potential changes.
|
||||
if [ -f /var/run/gpm.pid ]; then
|
||||
kill -s WINCH `cat /var/run/gpm.pid` 2> /dev/null
|
||||
fi
|
||||
|
||||
# Allow user to remap keys on the console
|
||||
if [ -z "${HAVE_SETUPCON}" -a -r /etc/$PKG/remap ]; then
|
||||
dumpkeys < ${DEVICE_PREFIX}1 | sed -f /etc/$PKG/remap | loadkeys --quiet
|
||||
fi
|
||||
|
||||
# Set LEDS here
|
||||
if [ -n "$LEDS" ]; then
|
||||
for i in $LIST_CONSOLES
|
||||
do
|
||||
setleds -D $LEDS < $DEVICE_PREFIX$i
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start|reload|restart|force-reload)
|
||||
if [ -n "$HAVE_SETUPCON" ]
|
||||
then
|
||||
log_action_msg "Setting console screen modes"
|
||||
else
|
||||
log_action_msg "Setting console screen modes and fonts"
|
||||
fi
|
||||
setup
|
||||
[ -z "$HAVE_SETUPCON" ] || log_action_msg "Skipping font and keymap setup (handled by console-setup)"
|
||||
;;
|
||||
stop)
|
||||
;;
|
||||
*)
|
||||
setup
|
||||
;;
|
||||
esac
|
||||
|
||||
:
|
||||
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#!/bin/sh
|
||||
# Alternative boot method for other distributions than Debian 6.0
|
||||
# Place this file in a /etc/start.d/ directory and add the following
|
||||
# line to /etc/finit.conf:
|
||||
#
|
||||
# runparts /etc/start.d
|
||||
#
|
||||
# At boot finit will run all files, using its built-in run_parts(),
|
||||
# in that directory.
|
||||
#
|
||||
# Here we chain load Debian /etc/rcS.d and /etc/rc2.d directories
|
||||
# in sequence using the standard run-parts tool.
|
||||
run-parts /etc/rcS.d --arg=start
|
||||
run-parts /etc/rc2.d --arg=start
|
||||
|
||||
# You can also place other commands in this services file, akin to
|
||||
# the old finit /usr/sbin/services.sh (not supported anymore).
|
||||
#service acpid start
|
||||
#service networking start
|
||||
#service ssh start
|
||||
@@ -1,20 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Example /usr/sbin/services.sh that can be used in a Mandriva 2008 system
|
||||
# running KDE
|
||||
|
||||
mkdir /var/lock/subsys
|
||||
chmod 1777 /var/lock/subsys
|
||||
/sbin/start_udev
|
||||
mkdir /var/run/dbus
|
||||
/etc/init.d/messagebus start
|
||||
/etc/init.d/haldaemon start
|
||||
/etc/init.d/alsa start
|
||||
/etc/init.d/sound start
|
||||
/etc/init.d/crond start
|
||||
/etc/init.d/network-up start
|
||||
/etc/init.d/network start
|
||||
#/etc/init.d/sshd start
|
||||
/etc/init.d/syslog start
|
||||
/sbin/pam_console_apply
|
||||
#kbuildsycoca --noincremental
|
||||
@@ -0,0 +1,53 @@
|
||||
Bootstrap
|
||||
=========
|
||||
|
||||
1. Populate `/dev`
|
||||
2. Parse `/etc/finit.conf`
|
||||
3. Load all `.so` plugins
|
||||
4. Remount/Pivot `/` to get R+W
|
||||
5. Call 1st level hooks, `HOOK_ROOTFS_UP`
|
||||
6. Mount `/etc/fstab` and swap, if available
|
||||
7. Cleanup stale files from `/tmp/*` et al
|
||||
8. Enable SysV init signals
|
||||
9. Call 2nd level hooks, `HOOK_BASEFS_UP`
|
||||
10. Start all 'S' runlevel tasks and services
|
||||
11. Load kernel params from `/etc/sysctl.d/*.conf`, `/etc/sysctl.conf`
|
||||
et al. (Supports all locations that SysV init does.)
|
||||
12. Set hostname and bring up loopback interface
|
||||
13. Call `network` script, if set in `/etc/finit.conf`
|
||||
14. Call 3rd level hooks, `HOOK_NETWORK_UP`
|
||||
15. 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.
|
||||
16. Call 4th level hooks, `HOOK_SVC_UP`
|
||||
17. If `runparts <DIR>` is set, [run-parts(8)][] is called on `<DIR>`
|
||||
18. Call `/etc/rc.local`, if it exists and is an executable shell script
|
||||
19. Call 5th level (last) hooks, `HOOK_SYSTEM_UP`
|
||||
20. Start TTYs defined in `/etc/finit.conf`, or rescue on `/dev/console`
|
||||
|
||||
In (10) and (15) tasks and services defined in `/etc/finit.conf` are
|
||||
started. Remember, all `service` and `task` stanzas are started in
|
||||
parallel and `run` in sequence, and in the order listed. Hence, to
|
||||
emulate a SysV `/etc/init.d/rcS` one could write a long file with only
|
||||
`run` statements.
|
||||
|
||||
Notice the five 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.
|
||||
|
||||
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
|
||||
|
||||
<!--
|
||||
-- Local Variables:
|
||||
-- mode: markdown
|
||||
-- End:
|
||||
-->
|
||||
@@ -0,0 +1,99 @@
|
||||
Building
|
||||
========
|
||||
|
||||
Finit comes with a traditional configure script to control features and
|
||||
optional plugins to enable. It does however depend on two external
|
||||
libraries that provide some frog DNA needed:
|
||||
|
||||
- [libuEv][]
|
||||
- [libite][] (-lite)
|
||||
|
||||
Like most free/open source software that uses `configure` they deafult
|
||||
to install to `/usr/local`. However, some Linux distributions do no
|
||||
longer search that path for installed software, e.g. Fedora and Alpine
|
||||
Linux. To get finit's configure script to find its dependencies you
|
||||
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
|
||||
|
||||
Below are a few of the main switches to
|
||||
configure:
|
||||
|
||||
* `--disable-inetd`: Disable the built-in inetd server.
|
||||
|
||||
* `--enable-embedded`: Target finit for BusyBox getty and mdev instead
|
||||
of a standard Linux distribution with GNU tools and udev.
|
||||
|
||||
* `--enable-rw-rootfs`: Most desktop and server systems boot with the
|
||||
root file stystem read-only. With this setting Finit will remount it
|
||||
as read-write early at boot so the `bootmisc.so` plugin can run.
|
||||
Usually not needed on embedded systems.
|
||||
|
||||
* `--enable-static`: Build Finit statically. The plugins will be
|
||||
built-ins (.o files) and all external libraries, except the C library
|
||||
will be linked statically.
|
||||
|
||||
* `--enable-alsa-utils`: Enable the optional `alsa-utils.so` sound plugin.
|
||||
|
||||
* `--enable-dbus`: Enable the optional D-Bus `dbus.so` plugin.
|
||||
|
||||
* `--enable-lost`: Enable noisy example plugin for `HOOK_SVC_LOST`.
|
||||
|
||||
* `--enable-resolvconf`: Enable the `resolvconf.so` optional plugin.
|
||||
|
||||
* `--enable-x11-common`: Enable the optional X Window `x11-common.so` plugin.
|
||||
|
||||
For more configure flags, see <kbd>./configure --help</kbd>
|
||||
|
||||
**Example**
|
||||
|
||||
First, unpack the archive:
|
||||
|
||||
```shell
|
||||
$ tar xf finit-3.0.tar.xz
|
||||
$ cd finit-3.0/
|
||||
```
|
||||
|
||||
Then configure, build and install:
|
||||
|
||||
```shell
|
||||
$ ./configure --enable-embedded --enable-rw-rootfs --enable-inetd-echo-plugin \
|
||||
--enable-inetd-chargen-plugin --enable-inetd-daytime-plugin \
|
||||
--enable-inetd-discard-plugin --enable-inetd-time-plugin \
|
||||
--with-heading="Alpine Linux 3.4" --with-hostname=alpine
|
||||
$ make
|
||||
.
|
||||
.
|
||||
.
|
||||
$ DESTDIR=/tmp/finit make install
|
||||
```
|
||||
|
||||
In this example the [finit-3.0.tar.xz][1] archive is unpacked to the
|
||||
user's home directory, configured, built and installed to a temporary
|
||||
staging directory. The environment variable `DESTDIR` controls the
|
||||
destination directory when installing, very useful for building binary
|
||||
standalone packages.
|
||||
|
||||
To target an embedded Linux system, usally a system that use BusyBox
|
||||
tools instead of udev & C:o, add <kbd>--enable-embedded</kbd> to the
|
||||
configure command above. This enables `mdev` instead of `udev` and the
|
||||
BusyBox `getty` syntax. Remember to also change the Linux config to:
|
||||
|
||||
CONFIG_UEVENT_HELPER_PATH="/sbin/mdev"
|
||||
|
||||
**Note:** If you run into problems starting Finit, take a look at
|
||||
`finit.c`. One of the most common problems is a custom Linux kernel
|
||||
build that lack `CONFIG_DEVTMPFS`. Another is too much cruft in the
|
||||
system `/etc/fstab`.
|
||||
|
||||
|
||||
[1]: ftp://troglobit.com/finit/finit-3.0.tar.xz
|
||||
[libuEv]: https://github.com/troglobit/libuev
|
||||
[libite]: https://github.com/troglobit/libite
|
||||
|
||||
<!--
|
||||
-- Local Variables:
|
||||
-- mode: markdown
|
||||
-- End:
|
||||
-->
|
||||
@@ -0,0 +1,162 @@
|
||||
Finit Conditions
|
||||
================
|
||||
|
||||

|
||||
|
||||
|
||||
Table of Contents
|
||||
-----------------
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [Triggering](#triggering)
|
||||
* [Built-in Conditions](#built-in--conditions)
|
||||
* [Debugging](#debugging)
|
||||
* [Internals](#internals)
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
In addition to declaring allowed runlevels per service, it is also
|
||||
possible to declare user-defined conditions as dependencies. Conditions
|
||||
are specified within angle brackets (<>) in the service stanza.
|
||||
Multiple conditions may be specified separated by comma. Conditions are
|
||||
AND'ed during evaluation, i.e. all conditions must be satisfied in order
|
||||
for a service to run.
|
||||
|
||||
|
||||
**Example:**
|
||||
|
||||
```shell
|
||||
service [2345] <svc/sbin/setupd,svc/sbin/zebra> /sbin/netd -- Network monitor
|
||||
```
|
||||
|
||||
In this example the Network monitor daemon `netd` is not started until
|
||||
both the `svc/sbin/setupd` *and* `svc/sbin/zebra` conditions are
|
||||
satisfied. An `svc` condition is satisfied by the corresponding
|
||||
service's pidfile being created.
|
||||
|
||||
|
||||
Triggering
|
||||
----------
|
||||
|
||||
Conditions are triggered either by plugins or by using the `cond`
|
||||
command of the `initctl` control tool.
|
||||
|
||||
* `initctl cond set your/cond/here`
|
||||
|
||||
To set a condition
|
||||
|
||||
* `initctl cond clear your/cond/here`
|
||||
|
||||
To clear a condition
|
||||
|
||||
Conditions retain their current state until the next reconfiguration or
|
||||
runlevel change. At that point all set conditions transition into the
|
||||
`flux` state, meaning the condition's state is unknown. (See
|
||||
[Internals](#internals) for the rationale behind this.) Thus, after a
|
||||
reconfiguration it is up to the "owner" of the condition to convey the
|
||||
new (or possibly unchanged) state of it.
|
||||
|
||||
|
||||
Built-in Conditions
|
||||
-------------------
|
||||
|
||||
Finit is distributed with a `pidfile` and `netlink` plugin. If enabled,
|
||||
the `pidfile` plugin watches `/var/run/` for PID files created by
|
||||
monitored services, and sets a corresponding condition in the `svc/`
|
||||
namespace. Similarily, the `netlink` plugin provides basic conditions
|
||||
for when an interface is brought up/down and when a default route
|
||||
(gateway) is set.
|
||||
|
||||
With the example listed above, finit does not start the `/sbin/netd`
|
||||
daemon until `setupd` and `zebra` has started *and* created their PID
|
||||
files. Which they do when they completed their main tasks of setting up
|
||||
VLANs, bridge, interfaces, etc. When `netd` in turn starts up it
|
||||
creates the file `/var/run/netd.pid`, and the condition `svc/sbin/netd`
|
||||
is satisfied. When the file is removed, the condition is cleared.
|
||||
|
||||
The full path to the dependency is needed by finit to match the PID file
|
||||
to a monitored process.
|
||||
|
||||
Built-in conditions:
|
||||
|
||||
- `svc/<PATH>`
|
||||
- `net/route/default`
|
||||
- `net/<IFNAME>/exist`
|
||||
- `net/<IFNAME>/up`
|
||||
|
||||
Note: `up` is administratively up, `IFF_UP`, not link up, `IFF_RUNNING`.
|
||||
|
||||
|
||||
Debugging
|
||||
---------
|
||||
|
||||
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
|
||||
command `initctl status` to inspect service status. Services in the
|
||||
`ready` state are pending a condition.
|
||||
|
||||
In that situation, running `initctl cond show` reveals which of the
|
||||
conditions that are not satisfied. Listed as `off` below.
|
||||
|
||||
**Example:**
|
||||
|
||||
```shell
|
||||
~ # initctl cond show
|
||||
PID Service Status Condition (+ on, ~ flux, - off)
|
||||
===============================================================================
|
||||
1419 /sbin/netd on <+svc/sbin/setupd,+svc/sbin/zebra>
|
||||
0 /sbin/udhcpc off <-net/vlan1/exist>
|
||||
```
|
||||
|
||||
Here we can see that `netd` is allowed to run since both its conditions
|
||||
are in the `on` state, as indicated by the `+`-prefix. `udhcpc` however
|
||||
is not allowed to run since `net/vlan1/exist` condition is not satsifed.
|
||||
As indicated by the `-`-prefix.
|
||||
|
||||
To fake interface `vlan1` suddenly appearing, and test what happens to
|
||||
`udhcpc` we can enable debug mode and assert the condition, like this:
|
||||
|
||||
```shell
|
||||
~ # initctl debug
|
||||
~ # initctl cond set net/vlan1/exist
|
||||
```
|
||||
|
||||
Then watch the console for the debug messages and then check the output
|
||||
from `initctl cond show` again. (The client will likely have failed to
|
||||
start, but at least the condition is now satisfied.)
|
||||
|
||||
|
||||
Internals
|
||||
---------
|
||||
|
||||
A condition is always in one of three states:
|
||||
|
||||
* `on` (+): The condition is asserted.
|
||||
* `off` (-): The condition is deasserted.
|
||||
* `flux` (~): The conditions state is unknown.
|
||||
|
||||
All conditions that have not explicitly been set are interpreted as
|
||||
being in the `off` state.
|
||||
|
||||
When a reconfiguration is requested, Finit transitions all conditions to
|
||||
the `flux` state. As a result, services that depend on a condition are
|
||||
sent `SIGSTOP`. Once the new state of the condition is asserted, the
|
||||
service receives `SIGCONT`. If the condition is no longer satisfied the
|
||||
service will then be stopped, otherwise no further action is taken.
|
||||
|
||||
This STOP/CONT handling minimizes the number of unnecessary service
|
||||
restarts that would otherwise occur because a depending service was sent
|
||||
`SIGHUP` for example.
|
||||
|
||||
Therefore, any plugin that supplies Finit with conditions must ensure
|
||||
that their state is updated after each reconfiguration. This can be
|
||||
done by binding to the `HOOK_SVC_RECONF` hook. For an example of how
|
||||
to do this, see `plugins/pidfile.c`.
|
||||
|
||||
<!--
|
||||
-- Local Variables:
|
||||
-- mode: markdown
|
||||
-- End:
|
||||
-->
|
||||
+219
@@ -0,0 +1,219 @@
|
||||
Configuration
|
||||
=============
|
||||
|
||||
Table of Contents
|
||||
-----------------
|
||||
|
||||
* [/etc/finit.conf](#etcfinitconf)
|
||||
* [/etc/finit.d](#etcfinitd)
|
||||
|
||||
/etc/finit.conf
|
||||
---------------
|
||||
|
||||
Contrary to most other script based init alternatives (SysV [init][],
|
||||
[upstart][], [systemd][], [OpenRC][], etc.) Finit relies on its main
|
||||
configuration file `/etc/finit.conf` and `/etc/finit.d/`.
|
||||
|
||||
The command line arguments given in `/etc/finit.conf` to each service
|
||||
provide a default. A plugin can be used to register a callback to a
|
||||
service and then modify the behavior to suit the current runlevel and
|
||||
system configuration.
|
||||
|
||||
For instance, before starting a heavily resource intensive service like
|
||||
IPsec or OpenVPN, a callback can check if the outbound interface is up
|
||||
and has an IP address, or just check if the service is disabled — much
|
||||
like what a SysV init start script usually does.
|
||||
|
||||
Syntax:
|
||||
|
||||
* `check <DEV>`
|
||||
Run fsck on a file system. Only needed if not listed in `/etc/fstab`,
|
||||
Finit 3.0 and later check all file systems automatically at boot.
|
||||
|
||||
* `module <MODULE>`
|
||||
Load a kernel module, with optional arguments
|
||||
|
||||
* `network <PATH>`
|
||||
Script or program to bring up networking, with optional arguments
|
||||
|
||||
* `rlimit <hard|soft> RESOURCE <LIMIT|infinity>`
|
||||
Modify the specified resource's hard or soft limit to be the
|
||||
specifed limit. `RESOURCE` is a lower-case string matching the
|
||||
constants in `setrlimit(2)` with the `RLIMIT_` prefix
|
||||
removed. E.g. to select `RLIMIT_CPU`, `RESOURCE` would be
|
||||
`cpu`. `LIMIT` is an integer whose unit depends on the resource
|
||||
being modified, see `setrlimit(2)` for more information. The special
|
||||
limit `infinity` means the there should be no limit on the resource,
|
||||
i.e. `RLIM_INFINITY` is passed to `setrlimit(2)`.
|
||||
|
||||
```shell
|
||||
# No process is allowed more than 8MB of address space
|
||||
rlimit hard as 8388608
|
||||
|
||||
# Core dumps may be arbitrarily large
|
||||
rlimit soft core infinity
|
||||
```
|
||||
|
||||
* `runlevel <N>`
|
||||
N is the runlevel number 1-9, where 6 is reserved for reboot.
|
||||
Default is 2.
|
||||
|
||||
* `run [LVLS] <COND> /path/to/cmd ARGS -- Optional description`
|
||||
One-shot command to run in sequence when entering a runlevel, with
|
||||
optional arguments and description. This command is guaranteed to be
|
||||
completed before running the next command.
|
||||
|
||||
* `task [LVLS] <COND> /path/to/cmd ARGS -- Optional description`
|
||||
One-shot like 'run', but starts in parallel with the next command
|
||||
|
||||
* `service [LVLS] <COND> /path/to/daemon ARGS -- Optional description`
|
||||
Service, or daemon, to be monitored and automatically restarted if it
|
||||
exits prematurely. Please note that you often need to provide a
|
||||
`--foreground` or `--no-background` argument to most daemons to
|
||||
prevent them from forking off a sub-process in the background.
|
||||
|
||||
```shell
|
||||
service [2345] <svc/sbin/zebra> /sbin/ospfd -- OSPF daemon
|
||||
```
|
||||
|
||||
For a detailed description of conditions, and how to debug them,
|
||||
see the [Finit Conditions](conditions.md) document.
|
||||
|
||||
* `inetd service/proto[@iflist] <wait|nowait> [LVLS] /path/to/daemon args`
|
||||
Launch a daemon when a client initiates a connection on an Internet
|
||||
port. Available services are listed in the UNIX `/etc/services` file.
|
||||
Finit can filter access to from a list of interfaces, `@iflist`, per
|
||||
inetd service as well as listen to custom ports.
|
||||
|
||||
```shell
|
||||
inetd ftp/tcp nowait @root /usr/sbin/uftpd -i -f
|
||||
inetd tftp/udp wait @root /usr/sbin/uftpd -i -t
|
||||
```
|
||||
|
||||
The following example listens to port 2323 for telnet connections and
|
||||
only allows clients connecting from `eth0`:
|
||||
|
||||
```shell
|
||||
inetd 2323/tcp@eth0 nowait [2345] /sbin/telnetd -i -F
|
||||
```
|
||||
|
||||
The interface list, `@iflist`, is of the format `@iface,!iface,iface`,
|
||||
where a single `!` means to deny access. Notice how interfaces are
|
||||
comma separated with no spaces.
|
||||
|
||||
The `inetd` directive can also have ` -- Optional Description`, only
|
||||
Finit does not output this text on the console when launching inetd
|
||||
services. Instead this text is sent to syslog and also shown by the
|
||||
`initctl` tool. More on inetd below.
|
||||
|
||||
* `runparts <DIR>`
|
||||
Call [run-parts(8)][] on `DIR` to run start scripts. All executable
|
||||
files, or scripts, in the directory are called, in alphabetic order.
|
||||
|
||||
It can be beneficial to use `S01name`, `S02othername`, etc. if there
|
||||
is a dependency order between the scripts. Symlinks to existing
|
||||
daemons can talso be used, but make sure they daemonize by default.
|
||||
|
||||
As the optional `/etc/rc.local` shell script, make sure that all your
|
||||
services and programs either terminate or start in the background or
|
||||
you will block Finit.
|
||||
|
||||
* `include <CONF>`
|
||||
Include another configuration file. Absolute path required.
|
||||
|
||||
* `tty [LVLS] <DEV> [BAUD] [TERM]`
|
||||
Start a getty on the given TTY device DEV, in the given runlevels. If
|
||||
no tty setting is given in `finit.conf` no login is possible. Use the
|
||||
`service` stanza to start a stand-alone shell for really bare bones
|
||||
systems.
|
||||
|
||||
Finit comes with a lightweight built-in getty, which after it has
|
||||
opened a TTY and the user has input a username, calls `/bin/login`
|
||||
like any other getty.
|
||||
|
||||
* `console <DEV>`
|
||||
Use this, along with a matching `tty DEV` line, to mark this TTY as a
|
||||
special "console" port with with `prctl()`. Useful in use-cases when
|
||||
all logins except the console must be stopped, e.g. when performing a
|
||||
flash upgrade on an embedded system.
|
||||
|
||||
When running <kbd>make install</kbd> no default `/etc/finit.conf` will
|
||||
be installed since system requirements differ too much. Try out the
|
||||
Debian 6.0 example `/usr/share/doc/finit/finit.conf` configuration that
|
||||
is capable of service monitoring SSH, sysklogd, gdm and a console getty!
|
||||
|
||||
Every `run`, `task`, `service`, or `inetd` can also list the privileges
|
||||
the `/path/to/cmd` should be executed with. Simply prefix the path with
|
||||
`[@USR[:GRP]]` like this:
|
||||
|
||||
```shell
|
||||
run [2345] @joe:users /usr/bin/logger "Hello world"
|
||||
```
|
||||
|
||||
For multiple instances of the same command, e.g. a DHCP client or
|
||||
multiple web servers, add `:ID` somewhere between the `run`, `task`,
|
||||
`service` keyword and the command, like this:
|
||||
|
||||
```shell
|
||||
service :1 [2345] /sbin/httpd -f -h /http -p 80 -- Web server
|
||||
service :2 [2345] /sbin/httpd -f -h /http -p 8080 -- Old web server
|
||||
```
|
||||
|
||||
Without the `:ID` to the service the latter will overwrite the former
|
||||
and only the old web server would be started and supervised.
|
||||
|
||||
The `run`, `task`, `service`, or `inetd` stanzas also allow the keyword
|
||||
`log` to redirect `stderr` and `stdout` of the application to syslog,
|
||||
using `logger`.
|
||||
|
||||
Worth noting is that conditions is allowed for all these stanzas. For a
|
||||
detailed description, see the [Conditions](conditions.md) document.
|
||||
|
||||
|
||||
/etc/finit.d
|
||||
------------
|
||||
|
||||
Finit supports changes to the overall system configuration at runtime.
|
||||
For this purpose the (configurable) directory `/etc/finit.d` is used.
|
||||
Here you can put configuration file snippets, one per service if you
|
||||
like, which are all sourced automatically by finit at boot when loading
|
||||
the static configuration from `/etc/finit.conf`. This is the default
|
||||
behavior, so no include directives are necessary.
|
||||
|
||||
To add a new service, simply drop a `.conf` file in `/etc/finit.d` and
|
||||
run `initctl reload`. (It is also possible to `SIGHUP` to PID 1, or
|
||||
call `finit q`, but that has been deprecated with the `initctl` tool).
|
||||
Any service read from this directory is flagged as a dynamic service, so
|
||||
changes to or removal of `/etc/finit.d/*.conf` files, is detected.
|
||||
|
||||
On `initctl reload` the following is checked for all services:
|
||||
|
||||
- If a service's `.conf` file has been removed, or its conditions are no
|
||||
longer satisifed, the service is stopped.
|
||||
- If the file is modified, or a service it depends on has been reloaded,
|
||||
the service is reloaded (stopped and started).
|
||||
- If a new service is added it is automatically started — respecting
|
||||
runlevels and return values from any callbacks.
|
||||
|
||||
For more info on the different states of a service, see the separate
|
||||
document [Finit Services](service.md).
|
||||
|
||||
The `/etc/finit.d` directory was previously the default Finit `runparts`
|
||||
directory. Finit no longer has a default `runparts`, so make sure to
|
||||
update your setup, or the finit configuration, accordingly.
|
||||
|
||||
**Note:** Configurations read from `/etc/finit.d` are read *after*
|
||||
initial bootstrap, runlevel S(1). Hence, bootstrap services *must* be
|
||||
in `/etc/finit.conf`!
|
||||
|
||||
[init]: http://en.wikipedia.org/wiki/Init
|
||||
[upstart]: http://upstart.ubuntu.com/
|
||||
[systemd]: http://www.freedesktop.org/wiki/Software/systemd/
|
||||
[openrc]: http://www.gentoo.org/proj/en/base/openrc/
|
||||
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
||||
|
||||
<!--
|
||||
-- Local Variables:
|
||||
-- mode: markdown
|
||||
-- End:
|
||||
-->
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
Internet Super Server
|
||||
=====================
|
||||
|
||||
Inetd
|
||||
-----
|
||||
|
||||
A built-in *Internet Super Server* support was added in Finit v1.12 and
|
||||
v1.13, along with an internal `time` inetd service, RFC 868 (rdate).
|
||||
The latter is supplied as a plugin to illustrate how simple it is to
|
||||
extend finit with more internal inetd services. Today more built-in
|
||||
services are available.
|
||||
|
||||
> Please note, not all UNIX daemons are prepared to run as inetd services.
|
||||
> In the example below `sshd` also need the command line argument `-i`.
|
||||
|
||||
The inetd support in finit is quite advanced. Not only does it launch
|
||||
services on demand, it can do so on custom ports and also filter inbound
|
||||
traffic using a poor man's [TCP wrappers][]. The syntax is very similar
|
||||
to the traditional `/etc/inetd.conf`, yet keeping with the style of
|
||||
Finit:
|
||||
|
||||
```shell
|
||||
# Launch SSH on demand, in runlevels 2-5 as root
|
||||
inetd ssh/tcp nowait [2345] @root:root /usr/sbin/sshd -i
|
||||
```
|
||||
|
||||
A more advanced example is listed below, please note the *incompatible
|
||||
syntax change* that was made between Finit v1.12 and v1.13 to support
|
||||
deny filters:
|
||||
|
||||
```shell
|
||||
# Start sshd if inbound connection on eth0, port 222, or
|
||||
# inbound on eth1, port 22. Ignore on other interfaces.
|
||||
inetd 222/tcp@eth0 nowait [2345] /usr/sbin/sshd -i
|
||||
inetd ssh/tcp@eth1,eth1 nowait [2345] /usr/sbin/sshd -i
|
||||
```
|
||||
|
||||
If `eth0` is your Internet interface you may want to avoid using the
|
||||
default port. To run ssh on port 222, and all others on port 22:
|
||||
|
||||
```shell
|
||||
inetd 222/tcp@eth0 nowait [2345] /usr/sbin/sshd -i
|
||||
inetd ssh/tcp@*,!eth0 nowait [2345] /usr/sbin/sshd -i
|
||||
```
|
||||
|
||||
Compared to Finit v1.12 you must *explicitly deny* access from `eth0`!
|
||||
|
||||
To protect against looping attacks, the inetd server will refuse UDP
|
||||
service if the reply port corresponds to any internal service. Similar
|
||||
to how the FreeBSD inetd operates.
|
||||
|
||||
|
||||
**Internal Services**
|
||||
|
||||
Like the original `inetd`, Finit has a few standard services built-in.
|
||||
They are realized as plugins to provide a simple means of testing the
|
||||
inetd functionality stand-alone. But this also provides both a useful
|
||||
network testing/availability, as well as a rudimentary time server for
|
||||
`rdate` clients.
|
||||
|
||||
- echo
|
||||
- chargen
|
||||
- daytime
|
||||
- discard
|
||||
- time
|
||||
|
||||
For security reasons they are all disabled by default and have to be
|
||||
enabled with both the `configure` script and a special `inetd` stanza in
|
||||
the `finit.conf` or `finit.d/*.conf` like this:
|
||||
|
||||
```shell
|
||||
inetd echo/udp wait [2345] internal
|
||||
inetd echo/tcp nowait [2345] internal
|
||||
inetd chargen/udp wait [2345] internal
|
||||
inetd chargen/tcp nowait [2345] internal
|
||||
inetd daytime/udp wait [2345] internal
|
||||
inetd daytime/tcp nowait [2345] internal
|
||||
inetd discard/udp wait [2345] internal
|
||||
inetd discard/tcp nowait [2345] internal
|
||||
inetd time/udp wait [2345] internal
|
||||
inetd time/tcp nowait [2345] internal
|
||||
```
|
||||
|
||||
Then call `rdate` from a remote machine (or use localhost):
|
||||
|
||||
```shell
|
||||
rdate -p <IP>
|
||||
rdate -up <IP>
|
||||
```
|
||||
|
||||
Or `echoping` to reach the echo service:
|
||||
|
||||
```shell
|
||||
echoping -v <IP>
|
||||
echoping -uv <IP>
|
||||
```
|
||||
|
||||
Or `echoping -d` to reach the discard service:
|
||||
|
||||
```shell
|
||||
echoping -dv <IP>
|
||||
echoping -duv <IP>
|
||||
```
|
||||
|
||||
Or `echoping -c` to reach the chargen service:
|
||||
|
||||
```shell
|
||||
echoping -cv <IP>
|
||||
echoping -cuv <IP>
|
||||
```
|
||||
|
||||
If you use `time/udp` you must use the standard rdate implementation and
|
||||
then call it with `rdate -up` to connect using UDP. Without the `-p`
|
||||
argument rdate will try to set the system clock. Please note that rdate
|
||||
has been deprecated by the NTP protocol and this plugin should only be
|
||||
used for testing or environments where NTP for some reason is blocked.
|
||||
Also, remember the UNIX year 2038 bug, or in the case of RFC 868 (and
|
||||
some NTP implementations), year 2036!
|
||||
|
||||
**Note:** There is currently no verification that the same port is used
|
||||
more than once. So a standard `inetd http/tcp` service will clash
|
||||
with an ssh entry for the same port `inetd 80/tcp` …
|
||||
|
||||
|
||||
[TCP Wrappers]: https://en.wikipedia.org/wiki/TCP_Wrapper
|
||||
|
||||
<!--
|
||||
-- Local Variables:
|
||||
-- mode: markdown
|
||||
-- End:
|
||||
-->
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
Hooks & Plugins
|
||||
===============
|
||||
|
||||
Finit can be extended to add general functionality in the form of I/O
|
||||
monitors, built-in inetd services, or hook plugins.
|
||||
|
||||
The following sections detail existing plugins and hook points. For
|
||||
more information, see the plugins listed below.
|
||||
|
||||
|
||||
Plugins
|
||||
-------
|
||||
|
||||
For your convenience a set of *optional* plugins are available:
|
||||
|
||||
* *alsa-utils.so*: Restore and save ALSA sound settings on
|
||||
startup/shutdown. _Optional plugin._
|
||||
|
||||
* *bootmisc.so*: Setup necessary files and system directories for, e.g.,
|
||||
UTMP (tracks logins at boot). This plugin is central to get a working
|
||||
system and runs at `HOOK_BASEFS_UP`. The `/var`, `/run`, and `/dev`
|
||||
file systems must be writable for this plugin to work.
|
||||
|
||||
Note: On an embedded system both `/var` and `/run` can be `tmpfs` RAM
|
||||
disks and `/dev` is usually a `devtmpfs`. This must be defined in the
|
||||
`/etc/fstab` file and in the Linux kernel config.
|
||||
|
||||
* *dbus.so*: Setup and start system message bus, D-Bus, at boot.
|
||||
_Optional plugin._
|
||||
|
||||
* *echo.so*: RFC 862 plugin. Start as inetd service, like time below.
|
||||
|
||||
* *chargen.so*: RFC 864 plugin. Start as inetd service, like time below.
|
||||
|
||||
* *daytime.so*: RFC 867 plugin. Start as inetd service, like time below.
|
||||
|
||||
* *discard.so*: RFC 863 plugin. Start as inetd service, like time below.
|
||||
|
||||
* *hwclock.so*: Restore and save system clock from/to RTC on
|
||||
startup/shutdown.
|
||||
|
||||
* *initctl.so*: Extends finit with a traditional `initctl` functionality.
|
||||
|
||||
* *lost.so*: Very simple `HOOK_SVC_LOST` example. Logs process ID and
|
||||
name to syslog. _Optional plugin._
|
||||
|
||||
* *netlink.so*: Listens to Linux kernel Netlink events for gateway and
|
||||
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
|
||||
interfaces going up/down.
|
||||
|
||||
* *resolvconf.so*: Setup necessary files for `resolvconf` at startup.
|
||||
_Optional plugin._
|
||||
|
||||
* *time.so*: RFC 868 (rdate) plugin. Start as inetd service. Useful
|
||||
for testing inetd filtering — BusyBox has an rdate (TCP) client.
|
||||
|
||||
* *tty.so*: Watches `/dev`, using inotify, for new device nodes (TTY's)
|
||||
to start/stop getty consoles on them on demand. Useful when plugging
|
||||
in a usb2serial converter to login to your embedded device.
|
||||
|
||||
* *urandom.so*: Setup random seed at startup.
|
||||
|
||||
* *x11-common.so*: Setup necessary files for X-Window. _Optional plugin._
|
||||
|
||||
Usually you want to hook into the boot process once, simple hook plugins
|
||||
like `bootmisc.so` are great for that purpose. They are called at each
|
||||
hook point in the boot process, useful to insert some pre-bootstrap
|
||||
mechanisms, like generating configuration files, restoring HW device
|
||||
state, etc. Available hook points are:
|
||||
|
||||
|
||||
Hooks
|
||||
-----
|
||||
|
||||
### Bootstrap Hooks
|
||||
|
||||
* `HOOK_ROOTFS_UP`: When `finit.conf` has been read and `/` has is
|
||||
mounted — very early
|
||||
|
||||
* `HOOK_BASEFS_UP`: All of `/etc/fstab` is mounted, swap is available
|
||||
and default init signals are setup
|
||||
|
||||
* `HOOK_NETWORK_UP`: System bootstrap, runlevel S, has completed and
|
||||
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_SYSTEM_UP`: All services *and* everything in `/etc/finit.d`
|
||||
has been launched
|
||||
|
||||
### Runtime Hooks
|
||||
|
||||
* `HOOK_SVC_RECONF`: Called when the user has changed something in the
|
||||
`/etc/finit.d` directory and issued `SIGHUP`. The hook is called when
|
||||
all modified/removed services have been stopped. When the hook has
|
||||
completed, Finit continues to start all modified and new services.
|
||||
|
||||
* `HOOK_SVC_LOST`: Called when a process is lost. When reconfiguring
|
||||
services at runtime this hook may be called a lot. However, it may be
|
||||
a quite useful hook to monitor a system post bootstrap when no, or
|
||||
few, services are expected to exit. A default plugin `lost.so` is
|
||||
available in the `plugins/` subdirectory as an example.
|
||||
|
||||
**NOTE:** This hook callback gets the lost PID as argument.
|
||||
|
||||
* `HOOK_SVC_START`: Like `HOOK_SVC_LOST`, but called when a process is
|
||||
started. Same caveats apply.
|
||||
|
||||
**NOTE:** This hook callback gets the new PID as argument.
|
||||
|
||||
* `HOOK_RUNLEVEL_CHANGE`: Called when the user has issued a runlevel
|
||||
change. The hook is called when services not matching the new
|
||||
runlevel have been been stopped. When the hook has completed, Finit
|
||||
continues to start all services in the new runlevel.
|
||||
|
||||
### Shutdown Hooks
|
||||
|
||||
* `HOOK_SHUTDOWN`: Called at shutdown/reboot, right before all
|
||||
services are sent `SIGTERM`
|
||||
|
||||
Plugins like `initctl.so` and `tty.so` extend finit by acting on events,
|
||||
they are called I/O plugins and are called from the finit main loop when
|
||||
`poll()` detects an event. See the source code for `plugins/*.c` for
|
||||
more help and ideas.
|
||||
|
||||
|
||||
<!--
|
||||
-- Local Variables:
|
||||
-- mode: markdown
|
||||
-- End:
|
||||
-->
|
||||
@@ -0,0 +1,38 @@
|
||||
Finit Services
|
||||
==============
|
||||
|
||||

|
||||
|
||||
State Machine
|
||||
-------------
|
||||
|
||||
A service is bound to a state machine that is in one of six (6) states.
|
||||
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`
|
||||
state.
|
||||
|
||||
The current state depends on the two following conditions:
|
||||
|
||||
* `E`: Service enabled. In order for `E` to be satisfied, the service
|
||||
must be allowed to run in the current runlevel and must not be
|
||||
blocked. A service may be blocked for several reasons:
|
||||
|
||||
- The user has manually stopped the service using `initctl stop JOB`
|
||||
- The program exits immediately. I.e. keeps crashing (make sure to use
|
||||
the 'run this service in the foreground' command line option)
|
||||
- The binary is missing in the filesystem
|
||||
|
||||
* `C`: Service conditions are satisfied:
|
||||
|
||||
- `on` (+): The condition is asserted.
|
||||
- `off` (-): The condition is deasserted.
|
||||
- `flux` (~): The conditions state is unknown.
|
||||
|
||||
For a detailed description of conditions, and how to debug them,
|
||||
see the [Finit Conditions](conditions.md) document.
|
||||
|
||||
<!--
|
||||
-- Local Variables:
|
||||
-- mode: markdown
|
||||
-- End:
|
||||
-->
|
||||
@@ -0,0 +1,41 @@
|
||||
Finit Signals
|
||||
=============
|
||||
|
||||
Finit is often used on embedded and small Linux systems with BusyBox.
|
||||
Though Finit comes with its own tools for (poweroff, halt, reboot), for
|
||||
compatibility with the existing BusyBox toolset the following signals
|
||||
have been adopted:
|
||||
|
||||
* `SIGUSR1`
|
||||
Same effect as `finit q`, reloads all *.conf files in `/etc/finit.d/`
|
||||
* `SIGUSR1`
|
||||
Calls shutdown hooks, including HOOK_SHUTDOWN, stops all running
|
||||
processes, and unmounts all file systems. Then tells kernel to
|
||||
halt. Most people these days want SIGUSR2 though.
|
||||
|
||||
SysV init and systemd use this to re-open their FIFO/D-Bus.
|
||||
* `SIGUSR2`
|
||||
Like SIGUSR1, but tell kernel to power-off the system, if ACPI
|
||||
or similar exists to actually do this. If the kernel fails
|
||||
power-off, Finit falls back to halt.
|
||||
|
||||
SysV init N/A, systemd dumps its internal state to log.
|
||||
* `SIGTERM`
|
||||
Like `SIGUSR1`, but tell kernel to reboot the system when done.
|
||||
|
||||
SysV init N/A, systemd rexecutes itself.
|
||||
* `SIGINT`
|
||||
Sent from kernel when the CTRL-ALT-DEL key combo is pressed.
|
||||
SysV init and systemd default to reboot with `shutdown -r`.
|
||||
Finit currently forwards this to `SIGTERM`.
|
||||
* `SIGPWR`
|
||||
Sent from a power daemon, like `powstatd(8)`, on changes to the
|
||||
UPS status. Traditionally SysV init read /etc/powerstatus and
|
||||
acted on "OK", "FAIL", or "LOW" and then removed the file.
|
||||
Finit currently forwards this to `SIGUSR2`.
|
||||
|
||||
<!--
|
||||
-- Local Variables:
|
||||
-- mode: markdown
|
||||
-- End:
|
||||
-->
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,307 @@
|
||||
/* Functions for exec'ing processes
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2015 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h" /* Generated by configure script */
|
||||
|
||||
#include <ctype.h> /* isdigit() */
|
||||
#include <dirent.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/wait.h>
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "sig.h"
|
||||
#include "utmp-api.h"
|
||||
|
||||
#define NUM_ARGS 16
|
||||
|
||||
int getty(char *tty, char *baud, char *term, char *user);
|
||||
|
||||
|
||||
/* Wait for process completion, returns status of waitpid(2) syscall */
|
||||
int complete(char *cmd, int pid)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if (waitpid(pid, &status, 0) == -1) {
|
||||
if (errno == EINTR)
|
||||
_e("Caught unblocked signal waiting for %s, aborting", cmd);
|
||||
else if (errno == ECHILD)
|
||||
_e("Caught SIGCHLD waiting for %s, aborting", cmd);
|
||||
else
|
||||
_e("Failed starting %s, error %d: %s", cmd, errno, strerror (errno));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int run(char *cmd)
|
||||
{
|
||||
int status, result, i = 0;
|
||||
char *args[NUM_ARGS + 1], *arg, *backup;
|
||||
pid_t pid;
|
||||
|
||||
/* We must create a copy that is possible to modify. */
|
||||
backup = arg = strdup(cmd);
|
||||
if (!arg)
|
||||
return 1; /* Failed allocating a string to be modified. */
|
||||
|
||||
/* Split command line into tokens of an argv[] array. */
|
||||
args[i++] = strsep(&arg, "\t ");
|
||||
while (arg && i < NUM_ARGS) {
|
||||
/* Handle run("su -c \"dbus-daemon --system\" messagebus");
|
||||
* => "su", "-c", "\"dbus-daemon --system\"", "messagebus" */
|
||||
if (*arg == '\'' || *arg == '"') {
|
||||
char *p, delim[2] = " ";
|
||||
|
||||
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;
|
||||
|
||||
if (i == NUM_ARGS && args[i]) {
|
||||
_e("Command too long: %s", cmd);
|
||||
free(backup);
|
||||
errno = EOVERFLOW;
|
||||
return 1;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (0 == pid) {
|
||||
FILE *fp;
|
||||
|
||||
/* Reset signal handlers that were set by the parent process */
|
||||
sig_unblock();
|
||||
setsid();
|
||||
|
||||
/* Always redirect stdio for run() */
|
||||
fp = fopen("/dev/null", "w");
|
||||
if (fp) {
|
||||
int fd = fileno(fp);
|
||||
|
||||
dup2(fd, STDIN_FILENO);
|
||||
dup2(fd, STDOUT_FILENO);
|
||||
dup2(fd, STDERR_FILENO);
|
||||
}
|
||||
|
||||
sig_unblock();
|
||||
execvp(args[0], args);
|
||||
|
||||
_exit(1); /* Only if execv() fails. */
|
||||
} else if (-1 == pid) {
|
||||
_pe("%s", args[0]);
|
||||
free(backup);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = complete(args[0], pid);
|
||||
if (-1 == status) {
|
||||
free(backup);
|
||||
return 1;
|
||||
}
|
||||
|
||||
result = WEXITSTATUS(status);
|
||||
if (WIFEXITED(status)) {
|
||||
_d("Started %s and ended OK: %d", args[0], result);
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
_d("Process %s terminated by signal %d", args[0], WTERMSIG(status));
|
||||
if (!result)
|
||||
result = 1; /* Must alert callee that the command did complete successfully.
|
||||
* This is necessary since not all programs trap signals and
|
||||
* change their return code accordingly. --Jocke */
|
||||
}
|
||||
|
||||
free(backup);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int run_interactive(char *cmd, char *fmt, ...)
|
||||
{
|
||||
int status, oldout = 1, olderr = 2;
|
||||
char line[LINE_SIZE];
|
||||
va_list ap;
|
||||
FILE *fp;
|
||||
|
||||
if (!cmd) {
|
||||
errno = EINVAL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!silent && fmt) {
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(line, sizeof(line), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
print_desc("", line);
|
||||
}
|
||||
|
||||
/* Redirect output from cmd to a tempfile */
|
||||
fp = tempfile();
|
||||
if (fp && !debug) {
|
||||
oldout = dup(STDOUT_FILENO);
|
||||
olderr = dup(STDERR_FILENO);
|
||||
dup2(fileno(fp), STDOUT_FILENO);
|
||||
dup2(fileno(fp), STDERR_FILENO);
|
||||
}
|
||||
|
||||
/* Run cmd ... */
|
||||
status = run(cmd);
|
||||
|
||||
/* Restore stderr/stdout */
|
||||
if (fp && !debug) {
|
||||
if (oldout >= 0) {
|
||||
dup2(oldout, STDOUT_FILENO);
|
||||
close(oldout);
|
||||
}
|
||||
if (olderr >= 0) {
|
||||
dup2(olderr, STDERR_FILENO);
|
||||
close(olderr);
|
||||
}
|
||||
}
|
||||
|
||||
if (!silent && fmt)
|
||||
print_result(status);
|
||||
|
||||
/* Dump any results of cmd on stderr after we've printed [ OK ] or [FAIL] */
|
||||
if (fp && !debug) {
|
||||
size_t len, written;
|
||||
|
||||
rewind(fp);
|
||||
do {
|
||||
len = fread(line, 1, sizeof(line), fp);
|
||||
written = fwrite(line, len, sizeof(char), stderr);
|
||||
} while (len > 0 && written == len);
|
||||
}
|
||||
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
pid_t run_getty(char *tty, char *speed, char *term, int console)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
pid = fork();
|
||||
if (!pid) {
|
||||
/* Reset signal handlers that were set by the parent process */
|
||||
sig_unblock();
|
||||
setsid();
|
||||
|
||||
/* Set INIT_PROCESS UTMP entry */
|
||||
utmp_set_init(tty, 0);
|
||||
|
||||
if (console)
|
||||
prctl(PR_SET_NAME, "console", 0, 0, 0);
|
||||
else
|
||||
prctl(PR_SET_NAME, "finit-getty", 0, 0, 0);
|
||||
|
||||
_exit(getty(tty, speed, term, NULL));
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
|
||||
int run_parts(char *dir, char *cmd)
|
||||
{
|
||||
struct dirent **e;
|
||||
int i, num;
|
||||
|
||||
num = scandir(dir, &e, NULL, alphasort);
|
||||
if (num < 0) {
|
||||
_d("No files found in %s, skipping ...", dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
int j = 0;
|
||||
pid_t pid = 0;
|
||||
mode_t mode;
|
||||
char *args[NUM_ARGS];
|
||||
char *name = e[i]->d_name;
|
||||
char path[CMD_SIZE];
|
||||
|
||||
snprintf(path, sizeof(path), "%s/%s", dir, name);
|
||||
mode = fmode(path);
|
||||
if (!S_ISEXEC(mode) || S_ISDIR(mode)) {
|
||||
_d("Skipping %s ...", path);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Fill in args[], starting with full path to executable */
|
||||
args[j++] = path;
|
||||
|
||||
/* 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])) {
|
||||
args[j++] = "start";
|
||||
} else if (name[0] == 'K' && isdigit(name[1])) {
|
||||
args[j++] = "stop";
|
||||
}
|
||||
} else {
|
||||
args[j++] = cmd;
|
||||
}
|
||||
args[j++] = NULL;
|
||||
|
||||
pid = fork();
|
||||
if (!pid) {
|
||||
_d("Calling %s ...", path);
|
||||
sig_unblock();
|
||||
execv(path, args);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
complete(path, pid);
|
||||
}
|
||||
|
||||
while (num--)
|
||||
free(e[num]);
|
||||
free(e);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
-449
@@ -1,449 +0,0 @@
|
||||
/*
|
||||
Improved fast init
|
||||
|
||||
Copyright (c) 2008 Claudio Matsuoka
|
||||
|
||||
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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/wait.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
#ifndef DEFUSER
|
||||
#define DEFUSER "user"
|
||||
#endif
|
||||
|
||||
/* Distribution configuration */
|
||||
|
||||
#ifdef DIST_MDV /* Mandriva */
|
||||
#define RANDOMSEED "/var/lib/random-seed"
|
||||
#define SYSROOT "/sysroot"
|
||||
#define GETTY "/usr/bin/openvt /sbin/mingetty tty2"
|
||||
#define RUNPARTS "/usr/bin/run-parts"
|
||||
#define REMOUNT_ROOTFS_RW
|
||||
#define MAKE_DEVICES
|
||||
#define PAM_CONSOLE
|
||||
#else /* original Eeepc distribution */
|
||||
#define RANDOMSEED "/var/lib/urandom/random-seed"
|
||||
#define SYSROOT "/mnt"
|
||||
#define GETTY "/usr/bin/openvt /sbin/getty 38400 tty2"
|
||||
#define RUNPARTS "/bin/run-parts"
|
||||
#define TOUCH_ETC_NETWORK_RUN_IFSTATE
|
||||
#endif
|
||||
|
||||
#ifdef DIRECTISA
|
||||
#define HWCLOCK_DIRECTISA " --directisa"
|
||||
#else
|
||||
#define HWCLOCK_DIRECTISA
|
||||
#endif
|
||||
|
||||
|
||||
/* From sysvinit */
|
||||
/* Set a signal handler. */
|
||||
#define SETSIG(sa, sig, fun, flags) \
|
||||
do { \
|
||||
sa.sa_handler = fun; \
|
||||
sa.sa_flags = flags; \
|
||||
sigemptyset(&sa.sa_mask); \
|
||||
sigaction(sig, &sa, NULL); \
|
||||
} while (0)
|
||||
|
||||
#define touch(x) mknod((x), S_IFREG|0644, 0)
|
||||
#define chardev(x,m,maj,min) mknod((x), S_IFCHR|(m), makedev((maj),(min)))
|
||||
#define blkdev(x,m,maj,min) mknod((x), S_IFBLK|(m), makedev((maj),(min)))
|
||||
|
||||
#define MATCH_CMD(l,c,x) \
|
||||
((!strncmp((l), (c), strlen((c)))) && ((x) = (l) + strlen((c))))
|
||||
|
||||
#define LINE_SIZE 1024
|
||||
#define CMD_SIZE 256
|
||||
#define USERNAME_SIZE 16
|
||||
#define HOSTNAME_SIZE 32
|
||||
|
||||
void shutdown(int);
|
||||
void signal_handler(int);
|
||||
void chld_handler(int);
|
||||
|
||||
static int debug = 0;
|
||||
|
||||
static void build_cmd(char *cmd, char *x, int len)
|
||||
{
|
||||
int l;
|
||||
char *c;
|
||||
|
||||
c = cmd + strlen(cmd);
|
||||
for (; *x && (*x == ' ' || *x == '\t'); x++);
|
||||
for (l = 0; *x && *x != ' ' && *x != '\t' && l < len; l++)
|
||||
*c++ = *x++;
|
||||
*c = 0;
|
||||
if (debug)
|
||||
printf("cmd = %s\n", cmd);
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
int i;
|
||||
FILE *f;
|
||||
char line[LINE_SIZE];
|
||||
int fd;
|
||||
DIR *dir;
|
||||
struct dirent *d;
|
||||
struct sigaction sa, act;
|
||||
sigset_t nmask, nmask2;
|
||||
char username[USERNAME_SIZE] = DEFUSER;
|
||||
char hostname[HOSTNAME_SIZE] = "eviltwin";
|
||||
char cmd[CMD_SIZE];
|
||||
|
||||
puts("finit-alt " VERSION " (built " __DATE__ " by " WHOAMI ")");
|
||||
|
||||
chdir("/");
|
||||
umask(022);
|
||||
|
||||
/*
|
||||
* Signal management
|
||||
*/
|
||||
for (i = 1; i < NSIG; i++)
|
||||
SETSIG(sa, i, SIG_IGN, SA_RESTART);
|
||||
|
||||
SETSIG(sa, SIGINT, shutdown, 0);
|
||||
SETSIG(sa, SIGPWR, SIG_IGN, 0);
|
||||
SETSIG(sa, SIGUSR1, shutdown, 0);
|
||||
SETSIG(sa, SIGUSR2, shutdown, 0);
|
||||
SETSIG(sa, SIGTERM, SIG_IGN, 0);
|
||||
SETSIG(sa, SIGALRM, SIG_IGN, 0);
|
||||
SETSIG(sa, SIGHUP, SIG_IGN, 0);
|
||||
SETSIG(sa, SIGCONT, SIG_IGN, SA_RESTART);
|
||||
SETSIG(sa, SIGCHLD, chld_handler, SA_RESTART);
|
||||
|
||||
/* Block sigchild while forking */
|
||||
sigemptyset(&nmask);
|
||||
sigaddset(&nmask, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &nmask, NULL);
|
||||
|
||||
reboot(RB_DISABLE_CAD);
|
||||
|
||||
mount("none", "/proc", "proc", 0, NULL);
|
||||
|
||||
/*
|
||||
* Parse kernel parameters
|
||||
*/
|
||||
if ((f = fopen("/proc/cmdline", "r")) != NULL) {
|
||||
fgets(line, LINE_SIZE, f);
|
||||
if (strstr(line, "quiet")) {
|
||||
close(0);
|
||||
close(1);
|
||||
close(2);
|
||||
}
|
||||
if ((strstr(line, "finit_debug"))) {
|
||||
debug = 1;
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse configuration file
|
||||
*/
|
||||
if ((f = fopen("/etc/finit.conf", "r")) != NULL) {
|
||||
char *x;
|
||||
while (!feof(f)) {
|
||||
fgets(line, LINE_SIZE, f);
|
||||
chomp(line);
|
||||
|
||||
if (debug)
|
||||
printf("conf: %s\n", line);
|
||||
|
||||
if (MATCH_CMD(line, "check ", x)) {
|
||||
strcpy(cmd, "/sbin/fsck -C -a ");
|
||||
build_cmd(cmd, x, CMD_SIZE);
|
||||
system(cmd);
|
||||
continue;
|
||||
}
|
||||
if (MATCH_CMD(line, "user ", x)) {
|
||||
*username = 0;
|
||||
build_cmd(username, x, USERNAME_SIZE);
|
||||
continue;
|
||||
}
|
||||
if (MATCH_CMD(line, "host ", x)) {
|
||||
*hostname = 0;
|
||||
build_cmd(hostname, x, HOSTNAME_SIZE);
|
||||
continue;
|
||||
}
|
||||
if (MATCH_CMD(line, "module ", x)) {
|
||||
strcpy(cmd, "/sbin/modprobe ");
|
||||
build_cmd(cmd, x, CMD_SIZE);
|
||||
system(cmd);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
setsid();
|
||||
|
||||
/*
|
||||
* Mount filesystems
|
||||
*/
|
||||
#ifdef REMOUNT_ROOTFS_RW
|
||||
system("/bin/mount -n -o remount,rw /");
|
||||
#endif
|
||||
umask(0);
|
||||
|
||||
#ifdef MAKE_DEVICES
|
||||
mkdir("/dev/shm", 0755);
|
||||
mkdir("/dev/pts", 0755);
|
||||
#endif
|
||||
|
||||
mount("none", "/sys", "sysfs", 0, NULL);
|
||||
mount("none", "/dev/pts", "devpts", 0, "gid=5,mode=620");
|
||||
mount("none", "/dev/shm", "tmpfs", 0, NULL);
|
||||
mount("none", "/tmp", "tmpfs", 0, "mode=1777,size=128m");
|
||||
mount("none", "/var/run", "tmpfs", 0, "mode=0755");
|
||||
mount("none", "/var/lock", "tmpfs", 0, "mode=1777");
|
||||
mount("none", "/proc/bus/usb", "usbfs", 0, NULL);
|
||||
mount(SYSROOT, "/", NULL, MS_MOVE, NULL);
|
||||
|
||||
#ifdef MAKE_DEVICES
|
||||
mkdir("/dev/input", 0755);
|
||||
chardev("/dev/urandom", 0666, 1, 9);
|
||||
chardev("/dev/ptmx", 0666, 5, 2);
|
||||
chardev("/dev/null", 0666, 1, 3);
|
||||
chardev("/dev/mem", 0640, 1, 1);
|
||||
chmod("/dev/null", 0667);
|
||||
chmod("/dev/mem", 0640);
|
||||
chardev("/dev/tty0", 0660, 4, 0);
|
||||
chardev("/dev/input/mice", 0660, 13, 63);
|
||||
chardev("/dev/input/event0", 0660, 13, 64);
|
||||
chardev("/dev/agpgart", 0660, 10, 175);
|
||||
blkdev("/dev/loop0", 0600, 7, 0);
|
||||
#endif
|
||||
|
||||
unlink("/etc/mtab");
|
||||
system("mount -a");
|
||||
|
||||
umask(0022);
|
||||
|
||||
/*
|
||||
* Time adjustments
|
||||
*/
|
||||
if ((fd = open("/etc/adjtime", O_CREAT|O_WRONLY|O_TRUNC, 0644)) >= 0) {
|
||||
write(fd, "0.0 0 0.0\n", 10);
|
||||
close(fd);
|
||||
}
|
||||
#ifndef NO_HCTOSYS
|
||||
system("/sbin/hwclock --hctosys --localtime" HWCLOCK_DIRECTISA);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Network stuff
|
||||
*/
|
||||
makepath("/dev/shm/network");
|
||||
makepath("/dev/shm/resolvconf/interface");
|
||||
|
||||
if ((dir = opendir("/etc/resolvconf/run/interface")) != NULL) {
|
||||
while ((d = readdir(dir)) != NULL) {
|
||||
if (isalnum(d->d_name[0]))
|
||||
continue;
|
||||
snprintf(line, LINE_SIZE,
|
||||
"/etc/resolvconf/run/interface/%s", d->d_name);
|
||||
unlink(line);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
touch("/var/run/utmp");
|
||||
touch("/etc/resolvconf/run/enable-updates");
|
||||
|
||||
chdir("/etc/resolvconf/run/interface");
|
||||
#ifdef BUILTIN_RUNPARTS
|
||||
run_parts("/etc/resolvconf/update.d", "-i", NULL);
|
||||
#else
|
||||
system(RUNPARTS " --arg=i /etc/resolvconf/update.d");
|
||||
#endif
|
||||
chdir("/");
|
||||
|
||||
#ifdef TOUCH_ETC_NETWORK_RUN_IFSTATE
|
||||
touch("/etc/network/run/ifstate");
|
||||
#endif
|
||||
|
||||
if ((f = fopen("/etc/hostname", "r")) != NULL) {
|
||||
fgets(hostname, HOSTNAME_SIZE, f);
|
||||
chomp(hostname);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
sethostname(hostname, strlen(hostname));
|
||||
|
||||
ifconfig("lo", "127.0.0.1", "255.0.0.0", 1);
|
||||
|
||||
/*
|
||||
* Set random seed
|
||||
*/
|
||||
copyfile(RANDOMSEED, "/dev/urandom", 0);
|
||||
unlink(RANDOMSEED);
|
||||
umask(077);
|
||||
copyfile("/dev/urandom", RANDOMSEED, 4096);
|
||||
umask(0);
|
||||
|
||||
/*
|
||||
* Console setup (for X)
|
||||
*/
|
||||
makepath("/var/run/console");
|
||||
snprintf(line, LINE_SIZE, "/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);
|
||||
system("/sbin/pam_console_apply");
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Misc setup
|
||||
*/
|
||||
mkdir("/tmp/.X11-unix", 01777);
|
||||
mkdir("/tmp/.ICE-unix", 01777);
|
||||
umask(022);
|
||||
|
||||
system(GETTY "&");
|
||||
|
||||
if (!fork()) {
|
||||
/* child process */
|
||||
|
||||
vhangup();
|
||||
|
||||
close(2);
|
||||
close(1);
|
||||
close(0);
|
||||
|
||||
if (open("/dev/tty1", O_RDWR) != 0)
|
||||
exit(1);
|
||||
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_handler = SIG_DFL;
|
||||
|
||||
sigemptyset(&nmask2);
|
||||
sigaddset(&nmask2, SIGCHLD);
|
||||
sigprocmask(SIG_UNBLOCK, &nmask2, NULL);
|
||||
|
||||
for (i = 1; i < NSIG; i++)
|
||||
sigaction(i, &sa, NULL);
|
||||
|
||||
dup2(0, 0);
|
||||
dup2(0, 1);
|
||||
dup2(0, 2);
|
||||
|
||||
touch("/tmp/nologin");
|
||||
|
||||
#ifdef AGPDRV
|
||||
system("/sbin/modprobe agpgart");
|
||||
system("/sbin/modprobe " AGPDRV);
|
||||
#endif
|
||||
|
||||
while (access("/tmp/shutdown", F_OK) < 0) {
|
||||
if (debug) {
|
||||
printf("Starting X as %s\n", username);
|
||||
snprintf(line, LINE_SIZE,
|
||||
"su -c startx -l %s\n", username);
|
||||
system(line);
|
||||
system("/bin/sh");
|
||||
} else {
|
||||
snprintf(line, LINE_SIZE,
|
||||
"su -c startx -l %s\n &> /dev/null",
|
||||
username);
|
||||
system(line);
|
||||
}
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* parent process */
|
||||
|
||||
sleep(1);
|
||||
system("/usr/sbin/services.sh &>/dev/null&");
|
||||
|
||||
while (1) {
|
||||
sigemptyset(&nmask);
|
||||
pselect(0, NULL, NULL, NULL, NULL, &nmask);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Shut down on INT USR1 USR2
|
||||
*/
|
||||
void shutdown(int sig)
|
||||
{
|
||||
touch("/tmp/shutdown");
|
||||
|
||||
kill(-1, SIGTERM);
|
||||
|
||||
write(1, "\033[?25l\033[30;40m", 14);
|
||||
copyfile("/boot/shutdown.fb", "/dev/fb/0", 0);
|
||||
sleep(2);
|
||||
|
||||
system("/usr/sbin/alsactl store > /dev/null 2>&1");
|
||||
system("/sbin/hwclock --systohc --localtime" HWCLOCK_DIRECTISA);
|
||||
|
||||
kill(-1, SIGKILL);
|
||||
|
||||
sync();
|
||||
sync();
|
||||
system("/bin/mount -n -o remount,ro /");
|
||||
system("/sbin/unionctl.static / --remove / > /dev/null 2>&1");
|
||||
|
||||
if (sig == SIGINT || sig == SIGUSR1)
|
||||
reboot(RB_AUTOBOOT);
|
||||
|
||||
reboot(RB_POWER_OFF);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SIGCHLD: one of our children has died
|
||||
*/
|
||||
void chld_handler(int sig)
|
||||
{
|
||||
int status;
|
||||
|
||||
while (waitpid(-1, &status, WNOHANG) != 0) {
|
||||
if (errno == ECHILD)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
-323
@@ -1,323 +0,0 @@
|
||||
/*
|
||||
Improved fast init
|
||||
|
||||
Copyright (c) 2008 Claudio Matsuoka
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Changelog from the original Eeepc fastinit:
|
||||
|
||||
- Use mknod() instead of close(open()) call to create empty file
|
||||
- Fix random seed initialization
|
||||
- Don't try to handle signal 0, SIGKILL or SIGSTOP
|
||||
- Implement makepath() to avoid system("mkdir -p")
|
||||
- Omit first hwclock if user has CONFIG_RTC_HCTOSYS in kernel (by Metalshark)
|
||||
- Add –directisa to hwclock if user has disabled CONFIG_GENRTC and enabled
|
||||
CONFIG_RTC but not CONFIG_HPET_TIMER and CONFIG_HPET_RTC_IRQ (by Metalshark)
|
||||
- Drop system() call to clean /tmp, it's a fresh mounted tmpfs
|
||||
- Change /proc/acpi/sleep to /sys/power/state (by Metalshark)
|
||||
- Set loopback interface using direct calls instead of system("ifconfig")
|
||||
- Copy 4096 data block in C instead of system("cat") or system("dd")
|
||||
- Draw shutdown splash screen using C calls instead of system("echo;cat")
|
||||
- Change poweroff method from writing 5 to /sys/power/state to
|
||||
reboot(RB_POWER_OFF) (by Metalshark)
|
||||
- Mount /var/run and /var/lock as tmpfs
|
||||
- Use SIG_IGN instead of empty signal handler (by Metalshark)
|
||||
- Add built-in run-parts option to be used instead of system("run-parts")
|
||||
- Reuse cmdline buffer as hostname and filename buffers
|
||||
- Open terminal in vt2 using openvt
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/wait.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
#ifdef DIRECTISA
|
||||
#define HWCLOCK_DIRECTISA " --directisa"
|
||||
#else
|
||||
#define HWCLOCK_DIRECTISA
|
||||
#endif
|
||||
|
||||
|
||||
/* From sysvinit */
|
||||
/* Set a signal handler. */
|
||||
#define SETSIG(sa, sig, fun, flags) \
|
||||
do { \
|
||||
sa.sa_handler = fun; \
|
||||
sa.sa_flags = flags; \
|
||||
sigemptyset(&sa.sa_mask); \
|
||||
sigaction(sig, &sa, NULL); \
|
||||
} while(0)
|
||||
|
||||
#define touch(x) mknod((x), S_IFREG|0644, 0)
|
||||
|
||||
#define LINE_SIZE 1024
|
||||
|
||||
void shutdown(int);
|
||||
void chld_handler(int);
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
int i;
|
||||
FILE *f;
|
||||
char line[LINE_SIZE];
|
||||
int fd;
|
||||
DIR *dir;
|
||||
struct dirent *d;
|
||||
struct sigaction sa, act;
|
||||
char *x;
|
||||
sigset_t nmask, nmask2;
|
||||
|
||||
puts("finit-mod " VERSION " (built " __DATE__ " by " WHOAMI ")");
|
||||
|
||||
chdir("/");
|
||||
umask(022);
|
||||
|
||||
/*
|
||||
* Signal management
|
||||
*/
|
||||
for (i = 1; i < NSIG; i++)
|
||||
SETSIG(sa, i, SIG_IGN, SA_RESTART);
|
||||
|
||||
SETSIG(sa, SIGINT, shutdown, 0);
|
||||
SETSIG(sa, SIGPWR, SIG_IGN, 0);
|
||||
SETSIG(sa, SIGUSR1, shutdown, 0);
|
||||
SETSIG(sa, SIGUSR2, shutdown, 0);
|
||||
SETSIG(sa, SIGTERM, SIG_IGN, 0);
|
||||
SETSIG(sa, SIGALRM, SIG_IGN, 0);
|
||||
SETSIG(sa, SIGHUP, SIG_IGN, 0);
|
||||
SETSIG(sa, SIGCONT, SIG_IGN, SA_RESTART);
|
||||
SETSIG(sa, SIGCHLD, chld_handler, SA_RESTART);
|
||||
|
||||
/* Block sigchild while forking */
|
||||
sigemptyset(&nmask);
|
||||
sigaddset(&nmask, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &nmask, NULL);
|
||||
|
||||
reboot(RB_DISABLE_CAD);
|
||||
|
||||
/*
|
||||
* Parse kernel parameters
|
||||
*/
|
||||
if ((f = fopen("/proc/cmdline", "r")) != NULL) {
|
||||
fgets(line, LINE_SIZE, f);
|
||||
if (strstr(line, "quiet")) {
|
||||
close(0);
|
||||
close(1);
|
||||
close(2);
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
setsid();
|
||||
|
||||
/*
|
||||
* Mount filesystems
|
||||
*/
|
||||
mount("proc", "/proc", "proc", 0, NULL);
|
||||
mount("sysfs", "/sys", "sysfs", 0, NULL);
|
||||
mount("devpts", "/dev/pts", "devpts", 0, "gid=5,mode=620");
|
||||
mount("tmpfs", "/dev/shm", "tmpfs", 0, NULL);
|
||||
mount("tmpfs", "/tmp", "tmpfs", 0, "mode=1777,size=128m");
|
||||
mount("tmpfs", "/var/run", "tmpfs", 0, "mode=0755");
|
||||
mount("tmpfs", "/var/lock", "tmpfs", 0, "mode=1777");
|
||||
mount("/mnt", "/", NULL, MS_MOVE, NULL);
|
||||
|
||||
/*
|
||||
* Time adjustments
|
||||
*/
|
||||
if ((fd = open("/etc/adjtime", O_CREAT|O_WRONLY|O_TRUNC, 0644)) >= 0) {
|
||||
write(fd, "0.0 0 0.0\n", 10);
|
||||
close(fd);
|
||||
}
|
||||
#ifndef NO_HCTOSYS
|
||||
system("/sbin/hwclock --hctosys --localtime" HWCLOCK_DIRECTISA);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Network stuff
|
||||
*/
|
||||
makepath("/dev/shm/network");
|
||||
makepath("/dev/shm/resolvconf/interface");
|
||||
|
||||
if ((dir = opendir("/etc/resolvconf/run/interface")) != NULL) {
|
||||
while ((d = readdir(dir)) != NULL) {
|
||||
if (isalnum(d->d_name[0]))
|
||||
continue;
|
||||
snprintf(line, LINE_SIZE,
|
||||
"/etc/resolvconf/run/interface/%s", d->d_name);
|
||||
unlink(line);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
touch("/var/run/utmp");
|
||||
touch("/etc/resolvconf/run/enable-updates");
|
||||
|
||||
chdir("/etc/resolvconf/run/interface");
|
||||
#ifdef BUILTIN_RUNPARTS
|
||||
run_parts("/etc/resolvconf/update.d", "-i", NULL);
|
||||
#else
|
||||
system("/bin/run-parts --arg=-i /etc/resolvconf/update.d");
|
||||
#endif
|
||||
chdir("/");
|
||||
|
||||
touch("/etc/network/run/ifstate");
|
||||
|
||||
if ((f = fopen("/etc/hostname", "r")) != NULL) {
|
||||
fgets(line, LINE_SIZE, f);
|
||||
if ((x = strchr(line, 0x0a)) != NULL)
|
||||
*x = 0;
|
||||
|
||||
sethostname(line, strlen(line));
|
||||
fclose(f);
|
||||
|
||||
}
|
||||
|
||||
ifconfig("lo", "127.0.0.1", "255.0.0.0", 1);
|
||||
|
||||
/*
|
||||
* Set random seed
|
||||
*/
|
||||
copyfile("/var/lib/urandom/random-seed", "/dev/urandom", 0);
|
||||
unlink("/var/lib/urandom/random-seed");
|
||||
umask(077);
|
||||
copyfile("/dev/urandom", "/var/lib/urandom/random-seed", 4096);
|
||||
|
||||
/*
|
||||
* Misc setup
|
||||
*/
|
||||
unlink("/var/run/.clean");
|
||||
unlink("/var/lock/.clean");
|
||||
umask(0);
|
||||
mkdir("/tmp/.X11-unix", 01777);
|
||||
mkdir("/tmp/.ICE-unix", 01777);
|
||||
umask(022);
|
||||
|
||||
system("/usr/bin/openvt /sbin/getty 38400 tty2&");
|
||||
|
||||
if (!fork()) {
|
||||
/* child process */
|
||||
|
||||
vhangup();
|
||||
|
||||
close(2);
|
||||
close(1);
|
||||
close(0);
|
||||
|
||||
if (open("/dev/tty1", O_RDWR) != 0)
|
||||
exit(1);
|
||||
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_handler = SIG_DFL;
|
||||
|
||||
sigemptyset(&nmask2);
|
||||
sigaddset(&nmask2, SIGCHLD);
|
||||
sigprocmask(SIG_UNBLOCK, &nmask2, NULL);
|
||||
|
||||
for (i = 1; i < NSIG; i++)
|
||||
sigaction(i, &sa, NULL);
|
||||
|
||||
dup2(0, 0);
|
||||
dup2(0, 1);
|
||||
dup2(0, 2);
|
||||
|
||||
touch("/tmp/nologin");
|
||||
|
||||
while (access("/tmp/shutdown", F_OK) < 0)
|
||||
system("su -c startx -l user &> /dev/null");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* parent process */
|
||||
|
||||
sleep(1);
|
||||
system("/usr/sbin/services.sh &>/dev/null&");
|
||||
|
||||
while (1) {
|
||||
sigemptyset(&nmask);
|
||||
pselect(0, NULL, NULL, NULL, NULL, &nmask);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Shut down on INT USR1 USR2
|
||||
*/
|
||||
void shutdown(int sig)
|
||||
{
|
||||
touch("/tmp/shutdown");
|
||||
|
||||
kill(-1, SIGTERM);
|
||||
|
||||
write(1, "\033[?25l\033[30;40m", 14);
|
||||
copyfile("/boot/shutdown.fb", "/dev/fb/0", 0);
|
||||
sleep(2);
|
||||
|
||||
system("/usr/sbin/alsactl store > /dev/null 2>&1");
|
||||
system("/sbin/hwclock --systohc --localtime" HWCLOCK_DIRECTISA);
|
||||
|
||||
kill(-1, SIGKILL);
|
||||
|
||||
sync();
|
||||
sync();
|
||||
system("/bin/mount -n -o remount,ro /");
|
||||
system("/sbin/unionctl.static / --remove / > /dev/null 2>&1");
|
||||
|
||||
if (sig == SIGINT || sig == SIGUSR1)
|
||||
reboot(RB_AUTOBOOT);
|
||||
|
||||
reboot(RB_POWER_OFF);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SIGCHLD: one of our children has died
|
||||
*/
|
||||
void chld_handler(int sig)
|
||||
{
|
||||
int status;
|
||||
|
||||
while (waitpid(-1, &status, WNOHANG) != 0) {
|
||||
if (errno == ECHILD)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,282 +1,432 @@
|
||||
/* Finit - Fast /sbin/init replacement w/ I/O, hook & service plugins
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2015 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h" /* Generated by configure script */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/reboot.h>
|
||||
#ifdef HAVE_FSTAB_H
|
||||
#include <fstab.h>
|
||||
#endif
|
||||
#include <mntent.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h> /* umask(), mkdir() */
|
||||
#include <sys/wait.h>
|
||||
#include <linux/fs.h>
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "conf.h"
|
||||
#include "helpers.h"
|
||||
#include "private.h"
|
||||
#include "plugin.h"
|
||||
#include "service.h"
|
||||
#include "sig.h"
|
||||
#include "sm.h"
|
||||
#include "tty.h"
|
||||
#include "utmp-api.h"
|
||||
#include "watchdog.h"
|
||||
|
||||
/* From sysvinit */
|
||||
/* Set a signal handler. */
|
||||
#define SETSIG(sa, sig, fun, flags) \
|
||||
do { \
|
||||
sa.sa_handler = fun; \
|
||||
sa.sa_flags = flags; \
|
||||
sigemptyset(&sa.sa_mask); \
|
||||
sigaction(sig, &sa, NULL); \
|
||||
} while(0)
|
||||
int debug = 0;
|
||||
int quiet = QUIET_MODE; /* Delayed disable of silent mode. */
|
||||
int silent = SILENT_MODE; /* Completely silent, including boot */
|
||||
int wdogpid = 0; /* No watchdog by default */
|
||||
int runlevel = 0; /* Bootstrap 'S' */
|
||||
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
|
||||
int prevlevel = -1;
|
||||
char *sdown = NULL;
|
||||
char *network = NULL;
|
||||
char *username = NULL;
|
||||
char *hostname = NULL;
|
||||
char *rcsd = FINIT_RCSD;
|
||||
char *runparts = NULL;
|
||||
char *console = NULL;
|
||||
|
||||
#define touch(x) close(open((x), O_CREAT|O_WRONLY|O_TRUNC, 0644))
|
||||
uev_ctx_t *ctx = NULL; /* Main loop context */
|
||||
|
||||
|
||||
void shutdown(int);
|
||||
void signal_handler(int);
|
||||
void chld_handler(int);
|
||||
|
||||
|
||||
int main()
|
||||
static int banner(void)
|
||||
{
|
||||
int i;
|
||||
FILE *f;
|
||||
char line[2096];
|
||||
int fd;
|
||||
DIR *dir;
|
||||
struct dirent *d;
|
||||
char filename[1024];
|
||||
struct sigaction sa, act;
|
||||
char hline[1024];
|
||||
char *x;
|
||||
sigset_t nmask, nmask2;
|
||||
char buf[42] = INIT_HEADING;
|
||||
const char separator[] = "========================================================================";
|
||||
|
||||
if (silent)
|
||||
return 0;
|
||||
|
||||
fprintf(stderr, "\e[2K\e[1m%s %.*s\e[0m\n", buf, 66 - (int)strlen(buf), separator);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check all filesystems in /etc/fstab with a fs_passno > 0
|
||||
*/
|
||||
static int fsck(int pass)
|
||||
{
|
||||
int save;
|
||||
struct fstab *fs;
|
||||
|
||||
if (!setfsent()) {
|
||||
_pe("Failed opening fstab");
|
||||
return 1;
|
||||
}
|
||||
|
||||
save = debug;
|
||||
debug = 0;
|
||||
|
||||
while ((fs = getfsent())) {
|
||||
char cmd[80];
|
||||
struct stat st;
|
||||
|
||||
if (fs->fs_passno != pass)
|
||||
continue;
|
||||
|
||||
errno = 0;
|
||||
if (stat(fs->fs_spec, &st) || !S_ISBLK(st.st_mode)) {
|
||||
if (!string_match(fs->fs_spec, "UUID=") && !string_match(fs->fs_spec, "LABEL=")) {
|
||||
_d("Cannot fsck %s, not a block device: %s", fs->fs_spec, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(cmd, sizeof(cmd), "/sbin/fsck -a %s", fs->fs_spec);
|
||||
run_interactive(cmd, "Checking filesystem %.13s", fs->fs_spec);
|
||||
}
|
||||
|
||||
debug = save;
|
||||
endfsent();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void networking(void)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
/* Run user network start script if enabled */
|
||||
if (network) {
|
||||
run_interactive(network, "Starting networking: %s", network);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Debian/Ubuntu/Busybox interfaces file */
|
||||
fp = fopen("/etc/network/interfaces", "r");
|
||||
if (fp) {
|
||||
int i = 0;
|
||||
char buf[160];
|
||||
|
||||
/* Bring up all 'auto' interfaces */
|
||||
while (fgets(buf, sizeof(buf), fp)) {
|
||||
char cmd[80];
|
||||
char *line, *ifname = NULL;
|
||||
|
||||
chomp(buf);
|
||||
line = strip_line(buf);
|
||||
|
||||
if (!strncmp(line, "auto", 4))
|
||||
ifname = &line[5];
|
||||
if (!strncmp(line, "allow-hotplug", 13))
|
||||
ifname = &line[14];
|
||||
|
||||
if (!ifname)
|
||||
continue;
|
||||
|
||||
snprintf(cmd, 80, "/sbin/ifup %s", ifname);
|
||||
run_interactive(cmd, "Bringing up interface %s", ifname);
|
||||
i++;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
if (i)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Fall back to bring up at least loopback */
|
||||
ifconfig("lo", "127.0.0.1", "255.0.0.0", 1);
|
||||
}
|
||||
|
||||
/* Requires /proc to be mounted */
|
||||
static int fismnt(char *dir)
|
||||
{
|
||||
FILE *fp;
|
||||
int found = 0;
|
||||
struct mntent *mnt;
|
||||
|
||||
fp = setmntent("/proc/mounts", "r");
|
||||
if (!fp)
|
||||
return 0; /* Dunno, maybe not */
|
||||
|
||||
while ((mnt = getmntent(fp))) {
|
||||
if (!strcmp(mnt->mnt_dir, dir)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
endmntent(fp);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/*
|
||||
* If everything goes south we can use this to give the operator an
|
||||
* emergency shell to debug the problem -- Finit should not crash!
|
||||
*/
|
||||
static void emergency_shell(void)
|
||||
{
|
||||
#ifdef EMERGENCY_SHELL
|
||||
pid_t pid;
|
||||
|
||||
pid = fork();
|
||||
if (pid) {
|
||||
waitpid(pid, NULL, 0);
|
||||
fprintf(stderr, "\n=> Embarrassingly, Finit has crashed. Check /dev/kmsg for details.\n");
|
||||
fprintf(stderr, "=> For more, remove 'quiet' and add '--debug' to the kernel command line.\n\n");
|
||||
|
||||
/*
|
||||
* Become session leader and set controlling TTY
|
||||
* to enable Ctrl-C and job control in shell.
|
||||
*/
|
||||
setsid();
|
||||
ioctl(STDIN_FILENO, TIOCSCTTY, 1);
|
||||
|
||||
execl(_PATH_BSHELL, _PATH_BSHELL, NULL);
|
||||
}
|
||||
#endif /* EMERGENCY_SHELL */
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
char *devfsd;
|
||||
uev_ctx_t loop;
|
||||
|
||||
chdir("/");
|
||||
umask(022);
|
||||
|
||||
/*
|
||||
* Signal management
|
||||
* finit/init/telinit client tool uses /dev/initctl pipe
|
||||
* for compatibility but initctl client tool uses socket
|
||||
*/
|
||||
for (i = 1; i < NSIG; i++)
|
||||
SETSIG(sa, i, SIG_IGN, SA_RESTART);
|
||||
if (getpid() != 1)
|
||||
return client(argc, argv);
|
||||
|
||||
SETSIG(sa, SIGINT, shutdown, 0);
|
||||
SETSIG(sa, SIGPWR, signal_handler, 0);
|
||||
SETSIG(sa, SIGUSR1, shutdown, 0);
|
||||
SETSIG(sa, SIGUSR2, shutdown, 0);
|
||||
SETSIG(sa, SIGTERM, signal_handler, 0);
|
||||
SETSIG(sa, SIGKILL, signal_handler, 0);
|
||||
SETSIG(sa, SIGALRM, signal_handler, 0);
|
||||
SETSIG(sa, SIGHUP, signal_handler, 0);
|
||||
SETSIG(sa, SIGSTOP, signal_handler, SA_RESTART);
|
||||
SETSIG(sa, SIGCONT, signal_handler, SA_RESTART);
|
||||
SETSIG(sa, SIGCHLD, chld_handler, SA_RESTART);
|
||||
|
||||
/* Block sigchild while forking */
|
||||
sigemptyset(&nmask);
|
||||
sigaddset(&nmask, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &nmask, NULL);
|
||||
/*
|
||||
* In case of emergency.
|
||||
*/
|
||||
emergency_shell();
|
||||
|
||||
reboot(RB_DISABLE_CAD);
|
||||
/*
|
||||
* Hello world.
|
||||
*/
|
||||
banner();
|
||||
|
||||
/*
|
||||
* Initial setup of signals, ignore all until we're up.
|
||||
*/
|
||||
sig_init();
|
||||
|
||||
/*
|
||||
* Initalize event context.
|
||||
*/
|
||||
uev_init(&loop);
|
||||
ctx = &loop;
|
||||
|
||||
/*
|
||||
* Check file filesystems in /etc/fstab
|
||||
*/
|
||||
for (int pass = 1; pass < 10; pass++) {
|
||||
if (fsck(pass))
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mount base file system, kernel is assumed to run devtmpfs for /dev
|
||||
*/
|
||||
chdir("/");
|
||||
umask(0);
|
||||
mount("none", "/proc", "proc", 0, NULL);
|
||||
mount("none", "/proc/bus/usb", "usbfs", 0, NULL);
|
||||
mount("none", "/sys", "sysfs", 0, NULL);
|
||||
|
||||
/*
|
||||
* Some non-embedded systems without an initramfs may not have /dev mounted yet
|
||||
* If they do, check if system has udevadm and perform cleanup from initramfs
|
||||
*/
|
||||
if (!fismnt("/dev"))
|
||||
mount("udev", "/dev", "devtmpfs", MS_RELATIME, "size=10%,nr_inodes=61156,mode=755");
|
||||
else if (fexist("/sbin/udevadm"))
|
||||
run_interactive("/sbin/udevadm info --cleanup-db", "Cleaning up udev db");
|
||||
|
||||
/* Some systems use /dev/pts */
|
||||
makedir("/dev/pts", 0755);
|
||||
mount("devpts", "/dev/pts", "devpts", 0, "gid=5,mode=620");
|
||||
|
||||
makedir("/dev/shm", 0755);
|
||||
if (!fismnt("/dev/shm"))
|
||||
mount("shm", "/dev/shm", "tmpfs", 0, NULL);
|
||||
|
||||
/*
|
||||
* New tmpfs based /run for volatile runtime data
|
||||
* For details, see http://lwn.net/Articles/436012/
|
||||
*/
|
||||
if (fisdir("/run") && !fismnt("/run"))
|
||||
mount("tmpfs", "/run", "tmpfs", MS_NODEV, "mode=0755,size=10%");
|
||||
umask(022);
|
||||
|
||||
/*
|
||||
* Parse kernel parameters
|
||||
*/
|
||||
if ((f = fopen("/proc/cmdline", "r")) != NULL) {
|
||||
fgets(line, 2095, f);
|
||||
if (strstr(line, "quiet")) {
|
||||
close(0);
|
||||
close(1);
|
||||
close(2);
|
||||
}
|
||||
fclose(f);
|
||||
conf_parse_cmdline();
|
||||
|
||||
/*
|
||||
* Populate /dev and prepare for runtime events from kernel.
|
||||
*/
|
||||
if (fexist("/sbin/mdev")) {
|
||||
/* Embedded Linux systems usually have BusyBox mdev */
|
||||
if (debug)
|
||||
touch("/dev/mdev.log");
|
||||
devfsd = "/sbin/mdev -s";
|
||||
} else {
|
||||
if (fexist("/sbin/udevd"))
|
||||
devfsd = "/sbin/udevd --daemon";
|
||||
else
|
||||
devfsd = "/lib/systemd/systemd-udevd --daemon";
|
||||
}
|
||||
|
||||
setsid();
|
||||
run_interactive(devfsd, "Populating device tree");
|
||||
if (fexist("/sbin/udevadm")) {
|
||||
run("/sbin/udevadm trigger --action=add --type=subsystems");
|
||||
run("/sbin/udevadm trigger --action=add --type=devices");
|
||||
run("/sbin/udevadm settle --timeout=120");
|
||||
}
|
||||
|
||||
/*
|
||||
* Load plugins first, finit.conf may contain references to
|
||||
* features implemented by plugins.
|
||||
*/
|
||||
plugin_init(&loop, PLUGIN_PATH);
|
||||
|
||||
/*
|
||||
* Parse /etc/finit.conf, main configuration file
|
||||
*/
|
||||
conf_parse_config();
|
||||
|
||||
/*
|
||||
* Start built-in watchdog as soon as possible, if enabled
|
||||
*/
|
||||
watchdog(argv[0]);
|
||||
|
||||
/* Set hostname as soon as possible, for syslog et al. */
|
||||
set_hostname(&hostname);
|
||||
|
||||
/* Set default PATH, for uid 0 */
|
||||
setenv("PATH", _PATH_STDPATH, 1);
|
||||
|
||||
/*
|
||||
* Mount filesystems
|
||||
*/
|
||||
mount("proc", "/proc", "proc", 0, NULL);
|
||||
mount("sysfs", "/sys", "sysfs", 0, NULL);
|
||||
mount("devpts", "/dev/pts", "devpts", 0, "gid=5,mode=620");
|
||||
mount("tmpfs", "/dev/shm", "tmpfs", 0, NULL);
|
||||
mount("tmpfs", "/tmp", "tmpfs", 0, "mode=1777,size=128m");
|
||||
mount("/mnt", "/", NULL, MS_MOVE, NULL);
|
||||
#ifdef REMOUNT_ROOTFS
|
||||
run("/bin/mount -n -o remount,rw /");
|
||||
#endif
|
||||
#ifdef SYSROOT
|
||||
mount(SYSROOT, "/", NULL, MS_MOVE, NULL);
|
||||
#endif
|
||||
|
||||
/* Debian has this little script to copy generated rules while the system was read-only */
|
||||
if (fexist("/lib/udev/udev-finish"))
|
||||
run_interactive("/lib/udev/udev-finish", "Finalizing udev");
|
||||
|
||||
_d("Root FS up, calling hooks ...");
|
||||
plugin_run_hooks(HOOK_ROOTFS_UP);
|
||||
|
||||
umask(0);
|
||||
if (run_interactive("/bin/mount -na", "Mounting filesystems"))
|
||||
plugin_run_hooks(HOOK_MOUNT_ERROR);
|
||||
|
||||
run("/sbin/swapon -ea");
|
||||
umask(0022);
|
||||
|
||||
/* Base FS up, enable standard SysV init signals */
|
||||
sig_setup(&loop);
|
||||
|
||||
_d("Base FS up, calling hooks ...");
|
||||
plugin_run_hooks(HOOK_BASEFS_UP);
|
||||
|
||||
/*
|
||||
* Time adjustments
|
||||
* Initalize finit state machine and start all bootstrap tasks, no network available!
|
||||
*/
|
||||
if ((fd = open("/etc/adjtime", O_CREAT|O_WRONLY|O_TRUNC, 0644)) >= 0) {
|
||||
write(fd, "0.0 0 0.0\n", 10);
|
||||
close(fd);
|
||||
}
|
||||
system("/sbin/hwclock --hctosys --localtime");
|
||||
sm_init(&sm);
|
||||
sm_step(&sm);
|
||||
|
||||
/*
|
||||
* Network stuff
|
||||
*/
|
||||
system("mkdir -p /dev/shm/network");
|
||||
system("mkdir -p /dev/shm/resolvconf/interface");
|
||||
|
||||
if ((dir = opendir("/etc/resolvconf/run/interface")) != NULL) {
|
||||
while ((d = readdir(dir)) != NULL) {
|
||||
if (isalnum(d->d_name[0]))
|
||||
continue;
|
||||
sprintf(filename, "/etc/resolvconf/run/interface/%s",
|
||||
d->d_name);
|
||||
unlink(filename);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
touch("/var/run/utmp");
|
||||
touch("/etc/resolvconf/run/enable-updates");
|
||||
|
||||
chdir("/etc/resolvconf/run/interface");
|
||||
system("/bin/run-parts --arg=-i /etc/resolvconf/update.d");
|
||||
chdir("/");
|
||||
|
||||
touch("/etc/network/run/ifstate");
|
||||
|
||||
if ((f = fopen("/etc/hostname", "r")) != NULL) {
|
||||
fgets(hline, 1023, f);
|
||||
if ((x = strchr(hline, 0x0a)) != NULL)
|
||||
*x = 0;
|
||||
|
||||
sethostname(hline, strlen(hline));
|
||||
fclose(f);
|
||||
|
||||
}
|
||||
|
||||
system("/sbin/ifconfig lo 127.0.0.1 netmask 255.0.0.0 up > /dev/null");
|
||||
|
||||
/*
|
||||
* Set random seed
|
||||
*/
|
||||
/* Bug: the eeepc never sets its random seed from file */
|
||||
system("/bin/cat /var/lib/urandom/random-seed >/dev/urandom "
|
||||
"> /dev/null 2>&1");
|
||||
unlink("/var/lib/urandom/random-seed");
|
||||
|
||||
umask(077);
|
||||
system("/bin/dd if=/dev/urandom of=/var/lib/urandom/random-seed "
|
||||
"bs=4096 count=1 >/dev/null 2>&1");
|
||||
|
||||
/*
|
||||
* Misc setup
|
||||
*/
|
||||
/* not really needed, /tmp is a fresh mounted tmpfs */
|
||||
system("/bin/rm -rf /tmp/* /tmp/.* 2>/dev/null");
|
||||
|
||||
unlink("/var/run/.clean");
|
||||
unlink("/var/lock/.clean");
|
||||
umask(0);
|
||||
mkdir("/tmp/.X11-unix", 01777);
|
||||
mkdir("/tmp/.ICE-unix", 01777);
|
||||
networking();
|
||||
umask(022);
|
||||
|
||||
if (!fork()) {
|
||||
/* child process */
|
||||
/* Hooks that rely on loopback, or basic networking being up. */
|
||||
plugin_run_hooks(HOOK_NETWORK_UP);
|
||||
|
||||
vhangup();
|
||||
/*
|
||||
* Start all tasks/services in the configured runlevel
|
||||
*/
|
||||
service_runlevel(cfglevel);
|
||||
|
||||
close(2);
|
||||
close(1);
|
||||
close(0);
|
||||
_d("Running svc up hooks ...");
|
||||
plugin_run_hooks(HOOK_SVC_UP);
|
||||
|
||||
if (open("/dev/tty1", O_RDWR, 0))
|
||||
exit(1);
|
||||
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_handler = SIG_DFL;
|
||||
|
||||
sigemptyset(&nmask2);
|
||||
sigaddset(&nmask2, SIGCHLD);
|
||||
sigprocmask(SIG_UNBLOCK, &nmask2, NULL);
|
||||
|
||||
/* Bug: no signal 0 */
|
||||
for (i = 0; i < NSIG; i++)
|
||||
sigaction(i, &sa, NULL);
|
||||
|
||||
dup2(0, 0);
|
||||
dup2(0, 1);
|
||||
dup2(0, 2);
|
||||
|
||||
touch("/tmp/nologin");
|
||||
|
||||
while (access("/tmp/shutdown", F_OK) < 0)
|
||||
system("su -c startx -l user &> /dev/null");
|
||||
|
||||
exit(0);
|
||||
/*
|
||||
* Run startup scripts in the runparts directory, if any.
|
||||
*/
|
||||
if (runparts && fisdir(runparts)) {
|
||||
_d("Running startup scripts in %s ...", runparts);
|
||||
run_parts(runparts, NULL);
|
||||
service_reload_dynamic();
|
||||
}
|
||||
|
||||
/* parent process */
|
||||
|
||||
system("/sbin/getty 38400 tty3 &");
|
||||
sleep(1);
|
||||
system("/usr/sbin/services.sh &> /dev/null &");
|
||||
|
||||
while (1) {
|
||||
sigemptyset(&nmask);
|
||||
pselect(0, NULL, NULL, NULL, NULL, &nmask);
|
||||
/* Convenient SysV compat for when you just don't care ... */
|
||||
if (!access(FINIT_RC_LOCAL, X_OK)) {
|
||||
run_interactive(FINIT_RC_LOCAL, "Calling %s", FINIT_RC_LOCAL);
|
||||
service_reload_dynamic();
|
||||
}
|
||||
|
||||
/* Hooks that should run at the very end */
|
||||
plugin_run_hooks(HOOK_SYSTEM_UP);
|
||||
|
||||
/* Start TTYs */
|
||||
tty_runlevel(runlevel);
|
||||
|
||||
/* Enable silent mode, if selected */
|
||||
if (quiet && !debug)
|
||||
silent = 1;
|
||||
|
||||
/* Start new initctl API responder */
|
||||
api_init(&loop);
|
||||
|
||||
/*
|
||||
* Enter main loop to monior /dev/initctl and services
|
||||
*/
|
||||
return uev_run(&loop, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Shut down on INT USR1 USR2
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
void shutdown(int sig)
|
||||
{
|
||||
int fd;
|
||||
|
||||
system("/usr/bin/touch /tmp/shutdown");
|
||||
|
||||
kill(-1, SIGTERM);
|
||||
|
||||
system("/bin/echo -e \"\033[?25l\033[30;40m\"; "
|
||||
"/bin/cp /boot/shutdown.fb /dev/fb/0");
|
||||
sleep(1);
|
||||
sleep(1);
|
||||
|
||||
system("/usr/sbin/alsactl store > /dev/null 2>&1");
|
||||
system("/sbin/hwclock --systohc --localtime");
|
||||
|
||||
kill(-1, SIGKILL);
|
||||
|
||||
sync();
|
||||
sync();
|
||||
system("/bin/mount -n -o remount,ro /");
|
||||
system("/sbin/unionctl.static / --remove / > /dev/null 2>&1");
|
||||
|
||||
if (sig == SIGINT || sig == SIGUSR1)
|
||||
reboot(RB_AUTOBOOT);
|
||||
|
||||
if ((fd = open("/proc/acpi/sleep", O_WRONLY)) >= 0) {
|
||||
write(fd, "5", 1);
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SIGCHLD: one of our children has died
|
||||
*/
|
||||
void chld_handler(int sig)
|
||||
{
|
||||
int status;
|
||||
|
||||
while (waitpid(-1, &status, WNOHANG) != 0) {
|
||||
if (errno == ECHILD)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* We got a signal (PWR TERM ALRM HUP STOP CONT)
|
||||
*/
|
||||
void signal_handler(int sig)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
|
||||
+50
-5
@@ -1,5 +1,50 @@
|
||||
user fred
|
||||
module intel-agp
|
||||
module p4-clockmod
|
||||
check /dev/sda3
|
||||
host eviltwin
|
||||
# Sample finit.conf to demonstrate the syntax
|
||||
#
|
||||
user admin
|
||||
host testbed
|
||||
|
||||
# Devices to fsck at boot
|
||||
check /dev/vda1
|
||||
|
||||
# Linux kernel modules to load
|
||||
module button
|
||||
module evdev
|
||||
module loop
|
||||
module psmouse
|
||||
|
||||
# Runlevel to start after bootstrap, runlevel 'S'
|
||||
runlevel 2
|
||||
|
||||
# Network bringup script
|
||||
network service networking start
|
||||
|
||||
# Virtual consoles to start getty on
|
||||
tty /dev/tty1
|
||||
tty /dev/tty2
|
||||
tty /dev/tty3
|
||||
|
||||
# Alternative method instead of runparts
|
||||
#task [S] /etc/init.d/keyboard-setup start -- Setting up preliminary keymap
|
||||
#task [S] /etc/init.d/acpid start -- Starting ACPI Daemon
|
||||
#task [S] /etc/init.d/kbd start -- Preparing console
|
||||
#run [2] /etc/init.d/networking start -- Start networking
|
||||
|
||||
# Services to be monitored and respawned as needed
|
||||
service [2345] /sbin/klogd -n -- Kernel logging server
|
||||
service [2345] /sbin/syslogd -n -- Syslog server
|
||||
service [3] /usr/sbin/gdm -- GNOME Display Manager
|
||||
|
||||
# Run start scripts from this directory
|
||||
# runparts /etc/start.d
|
||||
|
||||
# Inetd services
|
||||
inetd time/udp wait [2345] internal -- UNIX rdate service
|
||||
inetd time/tcp nowait [2345] internal -- UNIX rdate service
|
||||
inetd ssh@eth0:222/tcp nowait [2345] /usr/sbin/sshd -i -- SSH service
|
||||
inetd ssh/tcp nowait [2345] /usr/sbin/sshd -i -- SSH service
|
||||
|
||||
# For multiple instances of the same service, add :ID somewhere between
|
||||
# the service/run/task keyword and the command.
|
||||
service :1 [2345] /sbin/httpd -f -h /http -p 80 -- Web server
|
||||
service :2 [2345] /sbin/httpd -f -h /http -p 8080 -- Old web server
|
||||
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
/* Finit - Fast /sbin/init replacement w/ I/O, hook & service plugins
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2015 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef FINIT_H_
|
||||
#define FINIT_H_
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <paths.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <lite/lite.h>
|
||||
#include <uev/uev.h>
|
||||
|
||||
#define CMD_SIZE 256
|
||||
#define LINE_SIZE 1024
|
||||
#define BUF_SIZE 4096
|
||||
|
||||
/*
|
||||
* We extend the INIT_CMD_ range for the new initctl tool, Finit only
|
||||
* support changing runlevel, reloading the configuration and setenv
|
||||
* with the old-style /dev/initctl FIFO.
|
||||
*/
|
||||
#define INIT_SOCKET _PATH_VARRUN "finit.sock"
|
||||
#define INIT_MAGIC 0x03091969
|
||||
|
||||
#define INIT_CMD_START 0
|
||||
#define INIT_CMD_RUNLVL 1
|
||||
#define INIT_CMD_POWERFAIL 2
|
||||
#define INIT_CMD_POWERFAILNOW 3
|
||||
#define INIT_CMD_POWEROK 4
|
||||
#define INIT_CMD_BSD 5
|
||||
#define INIT_CMD_SETENV 6
|
||||
#define INIT_CMD_UNSETENV 7
|
||||
|
||||
/* Finit extensions over std SysV */
|
||||
#define INIT_CMD_DEBUG 8 /* Toggle Finit debug */
|
||||
#define INIT_CMD_RELOAD 9 /* Reload *.conf in /etc/finit.d/ */
|
||||
#define INIT_CMD_START_SVC 10
|
||||
#define INIT_CMD_STOP_SVC 11
|
||||
#define INIT_CMD_RELOAD_SVC 12 /* SIGHUP service */
|
||||
#define INIT_CMD_RESTART_SVC 13 /* STOP + START service */
|
||||
#define INIT_CMD_QUERY_INETD 14
|
||||
#define INIT_CMD_EMIT 15
|
||||
#define INIT_CMD_GET_RUNLEVEL 16
|
||||
#define INIT_CMD_WDOG_HELLO 128 /* Watchdog register and hello */
|
||||
#define INIT_CMD_NACK 254
|
||||
#define INIT_CMD_ACK 255
|
||||
|
||||
struct init_request {
|
||||
int magic; /* Magic number */
|
||||
int cmd; /* What kind of request */
|
||||
int runlevel; /* Runlevel to change to */
|
||||
int sleeptime; /* Time between TERM and KILL */
|
||||
char data[368];
|
||||
};
|
||||
|
||||
extern int debug;
|
||||
extern int quiet;
|
||||
extern int silent;
|
||||
extern int wdogpid;
|
||||
extern int runlevel;
|
||||
extern int cfglevel;
|
||||
extern int prevlevel;
|
||||
extern char *rcsd;
|
||||
extern char *sdown;
|
||||
extern char *network;
|
||||
extern char *hostname;
|
||||
extern char *username;
|
||||
extern char *runparts;
|
||||
extern char *console;
|
||||
extern uev_ctx_t *ctx;
|
||||
|
||||
#endif /* FINIT_H_ */
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,347 @@
|
||||
/* Initialize and serve a login terminal
|
||||
*
|
||||
* Copyright (c) 2016 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <paths.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
|
||||
#include <termios.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "sig.h"
|
||||
#include "utmp-api.h"
|
||||
|
||||
#ifndef _PATH_LOGIN
|
||||
#define _PATH_LOGIN "/bin/login"
|
||||
#endif
|
||||
|
||||
#define print(s) (void)write(STDOUT_FILENO, s, strlen(s))
|
||||
|
||||
|
||||
/*
|
||||
* Read one character from stdin.
|
||||
*/
|
||||
static int readch(char *tty)
|
||||
{
|
||||
int st;
|
||||
char ch1;
|
||||
|
||||
st = read(STDIN_FILENO, &ch1, 1);
|
||||
if (st == 0) {
|
||||
print("\n");
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
if (st < 0)
|
||||
errx(1, "getty: %s: read error", tty);
|
||||
|
||||
return ch1 & 0xFF;
|
||||
}
|
||||
|
||||
static void stty(int fd, speed_t speed)
|
||||
{
|
||||
struct termios term;
|
||||
|
||||
tcdrain(fd);
|
||||
if (tcgetattr(fd, &term))
|
||||
return;
|
||||
|
||||
cfsetispeed(&term, speed);
|
||||
cfsetospeed(&term, speed);
|
||||
tcsetattr(fd, TCSAFLUSH, &term);
|
||||
tcflush(fd, TCIOFLUSH);
|
||||
|
||||
/* Disable modem specific flags */
|
||||
term.c_cflag &= (0|CSTOPB|PARENB|PARODD);
|
||||
term.c_cflag &= ~CRTSCTS;
|
||||
term.c_cflag |= CLOCAL;
|
||||
|
||||
/* Timeouts, minimum chars and default flags */
|
||||
term.c_cc[VTIME] = 0;
|
||||
term.c_cc[VMIN] = 1;
|
||||
term.c_iflag = ICRNL|IXON|IXOFF;
|
||||
term.c_oflag = OPOST|ONLCR;
|
||||
term.c_cflag |= CS8|CREAD|HUPCL|CBAUDEX;
|
||||
term.c_lflag |= ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOKE;
|
||||
|
||||
/* Reset special characters to defaults */
|
||||
term.c_cc[VINTR] = CTRL('C');
|
||||
term.c_cc[VQUIT] = CTRL('\\');
|
||||
term.c_cc[VEOF] = CTRL('D');
|
||||
term.c_cc[VEOL] = '\n';
|
||||
term.c_cc[VKILL] = CTRL('U');
|
||||
term.c_cc[VERASE] = CERASE;
|
||||
tcsetattr(fd, TCSANOW, &term);
|
||||
|
||||
/* Clear screen in silent mode */
|
||||
if (silent)
|
||||
print("\033[r\033[H\033[J");
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse and display a line from /etc/issue
|
||||
*/
|
||||
static void do_parse(char *line, struct utsname *uts, char *tty)
|
||||
{
|
||||
char *s, *s0;
|
||||
|
||||
s0 = line;
|
||||
for (s = line; *s != 0; s++) {
|
||||
if (*s == '\\') {
|
||||
(void)write(1, s0, s - s0);
|
||||
s0 = s + 2;
|
||||
switch (*++s) {
|
||||
case 'l':
|
||||
print(tty);
|
||||
break;
|
||||
case 'm':
|
||||
print(uts->machine);
|
||||
break;
|
||||
case 'n':
|
||||
print(uts->nodename);
|
||||
break;
|
||||
#ifdef _GNU_SOURCE
|
||||
case 'o':
|
||||
print(uts->domainname);
|
||||
break;
|
||||
#endif
|
||||
case 'r':
|
||||
print(uts->release);
|
||||
break;
|
||||
case 's':
|
||||
print(uts->sysname);
|
||||
break;
|
||||
case 'v':
|
||||
print(uts->version);
|
||||
break;
|
||||
case 0:
|
||||
goto leave;
|
||||
default:
|
||||
s0 = s - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
leave:
|
||||
(void)write(1, s0, s - s0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse and display /etc/issue
|
||||
*/
|
||||
static void do_issue(char *tty)
|
||||
{
|
||||
FILE *fp;
|
||||
char buf[BUFSIZ] = "Welcome to \\s \\v \\n \\l\n\n";
|
||||
struct utsname uts;
|
||||
|
||||
/*
|
||||
* Get data about this machine.
|
||||
*/
|
||||
uname(&uts);
|
||||
|
||||
print("\n");
|
||||
fp = fopen("/etc/issue", "r");
|
||||
if (fp) {
|
||||
while (fgets(buf, sizeof(buf), fp))
|
||||
do_parse(buf, &uts, tty);
|
||||
|
||||
fclose(fp);
|
||||
} else {
|
||||
do_parse(buf, &uts, tty);
|
||||
}
|
||||
|
||||
do_parse("\\n login: ", &uts, tty);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle the process of a GETTY.
|
||||
*/
|
||||
static void do_getty(char *tty, char *name, size_t len)
|
||||
{
|
||||
int ch;
|
||||
char *np;
|
||||
|
||||
/*
|
||||
* Clean up tty name.
|
||||
*/
|
||||
if (!strncmp(tty, _PATH_DEV, strlen(_PATH_DEV)))
|
||||
tty += 5;
|
||||
|
||||
/*
|
||||
* Display prompt.
|
||||
*/
|
||||
ch = ' ';
|
||||
*name = '\0';
|
||||
while (ch != '\n') {
|
||||
do_issue(tty);
|
||||
|
||||
np = name;
|
||||
while ((ch = readch(tty)) != '\n') {
|
||||
if (np < name + len)
|
||||
*np++ = ch;
|
||||
}
|
||||
|
||||
*np = '\0';
|
||||
if (*name == '\0')
|
||||
ch = ' '; /* blank line typed! */
|
||||
}
|
||||
|
||||
name[len - 1] = 0;
|
||||
}
|
||||
|
||||
/* Execute the login(1) command with the current
|
||||
* username as its argument. It will reply to the
|
||||
* calling user by typing "Password: "...
|
||||
*/
|
||||
static int do_login(char *name)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
execl(_PATH_LOGIN, _PATH_LOGIN, name, NULL);
|
||||
|
||||
/*
|
||||
* Failed to exec login, should be impossible. Try a starting a
|
||||
* fallback shell instead.
|
||||
*
|
||||
* Note: Add /etc/securetty handling.
|
||||
*/
|
||||
warnx("Failed exec %s, attempting fallback to %s ...", _PATH_LOGIN, _PATH_BSHELL);
|
||||
if (fstat(0, &st) == 0 && S_ISCHR(st.st_mode))
|
||||
execl(_PATH_BSHELL, _PATH_BSHELL, NULL);
|
||||
|
||||
return 1; /* We shouldn't get here ... */
|
||||
}
|
||||
|
||||
static speed_t do_parse_speed(char *baud)
|
||||
{
|
||||
char *ptr;
|
||||
size_t i;
|
||||
unsigned long val;
|
||||
struct { unsigned long val; speed_t speed; } v2s[] = {
|
||||
{ 0, B0 },
|
||||
{ 50, B50 },
|
||||
{ 75, B75 },
|
||||
{ 110, B110 },
|
||||
{ 134, B134 },
|
||||
{ 150, B150 },
|
||||
{ 200, B200 },
|
||||
{ 300, B300 },
|
||||
{ 600, B600 },
|
||||
{ 1200, B1200 },
|
||||
{ 1800, B1800 },
|
||||
{ 2400, B2400 },
|
||||
{ 4800, B4800 },
|
||||
{ 9600, B9600 },
|
||||
{ 19200, B19200 },
|
||||
{ 38400, B38400 },
|
||||
{ 57600, B57600 },
|
||||
{ 115200, B115200 },
|
||||
{ 230400, B230400 },
|
||||
{ 460800, B460800 },
|
||||
{ 500000, B500000 },
|
||||
{ 576000, B576000 },
|
||||
{ 921600, B921600 },
|
||||
{ 1000000, B1000000 },
|
||||
{ 1152000, B1152000 },
|
||||
{ 1500000, B1500000 },
|
||||
{ 2000000, B2000000 },
|
||||
{ 2500000, B2500000 },
|
||||
{ 3000000, B3000000 },
|
||||
{ 3500000, B3500000 },
|
||||
{ 4000000, B4000000 },
|
||||
};
|
||||
|
||||
errno = 0;
|
||||
val = strtoul(baud, &ptr, 10);
|
||||
if (errno || ptr == baud)
|
||||
return B0;
|
||||
|
||||
for (i = 0; i < sizeof(v2s) / sizeof(v2s[0]); i++) {
|
||||
if (v2s[i].val == val)
|
||||
return v2s[i].speed;
|
||||
}
|
||||
|
||||
return B0;
|
||||
}
|
||||
|
||||
int getty(char *tty, char *baud, char *UNUSED(term), char *user)
|
||||
{
|
||||
int fd;
|
||||
char name[30];
|
||||
speed_t speed = B38400;
|
||||
struct sigaction sa;
|
||||
|
||||
if (baud) {
|
||||
speed = do_parse_speed(baud);
|
||||
if (speed == B0) {
|
||||
logit(LOG_CRIT, "TTY %s: Invalid speed %s", tty, baud);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Detach from initial controlling TTY */
|
||||
vhangup();
|
||||
|
||||
fd = open(tty, O_RDWR);
|
||||
if (fd < 0)
|
||||
err(1, "Failed opening %s", tty);
|
||||
|
||||
dup2(fd, STDIN_FILENO);
|
||||
dup2(fd, STDOUT_FILENO);
|
||||
dup2(fd, STDERR_FILENO);
|
||||
|
||||
if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0)
|
||||
warn("Failed TIOCSCTTY");
|
||||
|
||||
/*
|
||||
* Don't let QUIT dump core.
|
||||
*/
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
sa.sa_handler = _exit;
|
||||
sigaction(SIGQUIT, &sa, NULL);
|
||||
|
||||
stty(fd, speed);
|
||||
close(fd);
|
||||
utmp_set_login(tty, NULL);
|
||||
|
||||
if (!user)
|
||||
do_getty(tty, name, sizeof(name));
|
||||
else
|
||||
strlcpy(name, user, sizeof(name));
|
||||
|
||||
return do_login(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -1,172 +1,333 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#ifdef BUILTIN_RUNPARTS
|
||||
#include <dirent.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
/*
|
||||
* Helpers to replace system() calls
|
||||
/* Misc. utility functions for finit and its plugins
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2015 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
int makepath(char *p)
|
||||
#include <ctype.h> /* isblank() */
|
||||
#include <errno.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <limits.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <lite/lite.h>
|
||||
#include <lite/conio.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "private.h"
|
||||
#include "utmp-api.h"
|
||||
|
||||
int _slup = 0; /* INTERNAL: Is syslog up yet? */
|
||||
|
||||
char *strip_line(char *line)
|
||||
{
|
||||
char *x, path[PATH_MAX];
|
||||
int ret;
|
||||
|
||||
x = path;
|
||||
char *ptr;
|
||||
|
||||
do {
|
||||
do { *x++ = *p++; } while (*p && *p != '/');
|
||||
*x = 0;
|
||||
ret = mkdir(path, 0777);
|
||||
} while (*p && (*p != '/' || *(p + 1))); /* ignore trailing slash */
|
||||
/* Trim leading whitespace */
|
||||
while (*line && isblank(*line))
|
||||
line++;
|
||||
|
||||
return ret;
|
||||
/* Strip any comment at end of line */
|
||||
ptr = line;
|
||||
while (*ptr && *ptr != '#')
|
||||
ptr++;
|
||||
*ptr = 0;
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
void ifconfig(char *name, char *inet, char *mask, int up)
|
||||
void runlevel_set(int pre, int now)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
struct sockaddr_in *a = (struct sockaddr_in *)&ifr.ifr_addr;
|
||||
int sock;
|
||||
|
||||
if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0)
|
||||
return;
|
||||
|
||||
memset(&ifr, 0, sizeof (ifr));
|
||||
strncpy(ifr.ifr_name, name, IFNAMSIZ);
|
||||
a->sin_family = AF_INET;
|
||||
|
||||
if (up) {
|
||||
inet_aton(inet, &a->sin_addr);
|
||||
ioctl(sock, SIOCSIFADDR, &ifr);
|
||||
inet_aton(mask, &a->sin_addr);
|
||||
ioctl(sock, SIOCSIFNETMASK, &ifr);
|
||||
}
|
||||
|
||||
ioctl(sock, SIOCGIFFLAGS, &ifr);
|
||||
|
||||
if (up)
|
||||
ifr.ifr_flags |= IFF_UP;
|
||||
else
|
||||
ifr.ifr_flags &= ~IFF_UP;
|
||||
|
||||
ioctl(sock, SIOCSIFFLAGS, &ifr);
|
||||
|
||||
close(sock);
|
||||
utmp_set_runlevel(pre, now);
|
||||
}
|
||||
|
||||
#define BUF_SIZE 4096
|
||||
|
||||
void copyfile(char *src, char *dst, int size)
|
||||
/**
|
||||
* runlevel_string - Convert a bit encoded runlevel to .conf syntax
|
||||
* @levels: Bit encoded runlevels
|
||||
*
|
||||
* Returns:
|
||||
* Pointer to string on the form [2345]
|
||||
*/
|
||||
char *runlevel_string(int levels)
|
||||
{
|
||||
char buffer[BUF_SIZE];
|
||||
int s, d, n;
|
||||
int i, pos = 1;
|
||||
static char lvl[20];
|
||||
|
||||
/* Size == 0 means copy entire file */
|
||||
if (size == 0)
|
||||
size = INT_MAX;
|
||||
memset(lvl, 0, sizeof(lvl));
|
||||
lvl[0] = '[';
|
||||
|
||||
if ((s = open(src, O_RDONLY)) >= 0) {
|
||||
if ((d = open(dst, O_WRONLY | O_CREAT, 0644)) >= 0) {
|
||||
do {
|
||||
int csize = size > BUF_SIZE ? BUF_SIZE : size;
|
||||
|
||||
if ((n = read(s, buffer, csize)) > 0)
|
||||
write(d, buffer, n);
|
||||
size -= csize;
|
||||
} while (size > 0 && n == BUF_SIZE);
|
||||
close(d);
|
||||
}
|
||||
close(s);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 10; i++) {
|
||||
if (ISSET(levels, i)) {
|
||||
if (runlevel == i)
|
||||
pos = strlcat(lvl, "\e[1m", sizeof(lvl));
|
||||
|
||||
#ifdef BUILTIN_RUNPARTS
|
||||
if (i == 0)
|
||||
lvl[pos++] = 'S';
|
||||
else
|
||||
lvl[pos++] = '0' + i;
|
||||
|
||||
#define NUM_SCRIPTS 128 /* ought to be enough for anyone */
|
||||
#define NUM_ARGS 16
|
||||
|
||||
static int cmp(const void *s1, const void *s2)
|
||||
{
|
||||
return strcmp(*(char **)s1, *(char **)s2);
|
||||
}
|
||||
|
||||
int run_parts(char *dir, ...)
|
||||
{
|
||||
DIR *d;
|
||||
struct dirent *e;
|
||||
struct stat st;
|
||||
char *ent[NUM_SCRIPTS];
|
||||
int i, num = 0, argnum = 1;
|
||||
char *args[NUM_ARGS];
|
||||
va_list ap;
|
||||
|
||||
if (chdir(dir))
|
||||
return -1;
|
||||
|
||||
if ((d = opendir(dir)) == NULL)
|
||||
return -1;
|
||||
|
||||
va_start(ap, dir);
|
||||
while (argnum < NUM_ARGS && (args[argnum++] = va_arg(ap, char *)));
|
||||
va_end(ap);
|
||||
|
||||
while ((e = readdir(d))) {
|
||||
if (e->d_type == DT_REG && stat(e->d_name, &st) == 0) {
|
||||
if (st.st_mode & S_IXUSR) {
|
||||
ent[num++] = strdup(e->d_name);
|
||||
if (num >= NUM_SCRIPTS)
|
||||
break;
|
||||
}
|
||||
if (runlevel == i)
|
||||
pos = strlcat(lvl, "\e[0m", sizeof(lvl));
|
||||
}
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
lvl[pos++] = ']';
|
||||
lvl[pos] = 0;
|
||||
|
||||
if (num == 0)
|
||||
return 0;
|
||||
return lvl;
|
||||
}
|
||||
|
||||
qsort(ent, num, sizeof(char *), cmp);
|
||||
static int print_timestamp(void)
|
||||
{
|
||||
#if defined(CONFIG_PRINTK_TIME)
|
||||
FILE * uptimefile;
|
||||
float num1, num2;
|
||||
char uptime_str[30];
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
args[0] = ent[i];
|
||||
if (!fork()) {
|
||||
execv(ent[i], args);
|
||||
exit(0);
|
||||
}
|
||||
wait(NULL);
|
||||
free(ent[i]);
|
||||
}
|
||||
if((uptimefile = fopen("/proc/uptime", "r")) == NULL)
|
||||
return 1;
|
||||
|
||||
fgets(uptime_str, 20, uptimefile);
|
||||
fclose(uptimefile);
|
||||
|
||||
sscanf(uptime_str, "%f %f", &num1, &num2);
|
||||
sprintf(uptime_str, "[ %.6f ]", num1);
|
||||
|
||||
write(STDERR_FILENO, uptime_str, strlen(uptime_str));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Other convenience functions
|
||||
*/
|
||||
|
||||
void chomp(char *s)
|
||||
void print(int action, const char *fmt, ...)
|
||||
{
|
||||
char *x;
|
||||
char buf[80];
|
||||
size_t len;
|
||||
va_list ap;
|
||||
const char success[] = " \e[1m[ OK ]\e[0m\n";
|
||||
const char failure[] = " \e[7m[FAIL]\e[0m\n";
|
||||
const char warning[] = " \e[7m[WARN]\e[0m\n";
|
||||
const char pending[] = " \e[1m[ \\/ ]\e[0m\n";
|
||||
const char dots[] = " .....................................................................";
|
||||
|
||||
if ((x = strchr((s), 0x0a)) != NULL)
|
||||
*x = 0;
|
||||
if (silent)
|
||||
return;
|
||||
|
||||
if (fmt) {
|
||||
va_start(ap, fmt);
|
||||
len = vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
delline();
|
||||
print_timestamp();
|
||||
|
||||
write(STDERR_FILENO, "\r", 1);
|
||||
write(STDERR_FILENO, buf, len);
|
||||
write(STDERR_FILENO, dots, 60 - len); /* pad with dots. */
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case -1:
|
||||
break;
|
||||
|
||||
case 0:
|
||||
write(STDERR_FILENO, success, sizeof(success));
|
||||
break;
|
||||
|
||||
case 1:
|
||||
write(STDERR_FILENO, failure, sizeof(failure));
|
||||
break;
|
||||
|
||||
case 2:
|
||||
write(STDERR_FILENO, warning, sizeof(warning));
|
||||
break;
|
||||
|
||||
default:
|
||||
write(STDERR_FILENO, pending, sizeof(pending));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void print_desc(char *action, char *desc)
|
||||
{
|
||||
print(-1, "%s%s", action ?: "", desc ?: "");
|
||||
}
|
||||
|
||||
int print_result(int fail)
|
||||
{
|
||||
print(!!fail, NULL);
|
||||
return fail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Log to /dev/kmsg until syslogd has started, then openlog()
|
||||
* and continue logging as a regular daemon.
|
||||
*/
|
||||
void logit(int prio, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
if (!_slup && !fexist("/dev/log")) {
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen("/dev/kmsg", "w");
|
||||
if (fp) {
|
||||
if (debug)
|
||||
prio = LOG_ERR;
|
||||
|
||||
fprintf(fp, "<%d>finit[1]:", LOG_DAEMON | prio);
|
||||
vfprintf(fp, fmt, ap);
|
||||
fclose(fp);
|
||||
} else {
|
||||
fprintf(stderr, "Failed opening /dev/kmsg for appending ...\n");
|
||||
if (debug || prio <= LOG_ERR)
|
||||
vfprintf(stderr, fmt, ap);
|
||||
}
|
||||
va_end(ap);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_slup) {
|
||||
openlog("finit", LOG_PID, LOG_DAEMON);
|
||||
_slup = 1;
|
||||
}
|
||||
|
||||
vsyslog(prio, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
int getuser(char *username, char **home)
|
||||
{
|
||||
#ifdef ENABLE_STATIC
|
||||
*home = "/"; /* XXX: Fixme */
|
||||
return fgetint("/etc/passwd", "x:\n", username);
|
||||
#else
|
||||
struct passwd *usr;
|
||||
|
||||
if (!username || (usr = getpwnam(username)) == NULL)
|
||||
return -1;
|
||||
|
||||
*home = usr->pw_dir;
|
||||
return usr->pw_uid;
|
||||
#endif
|
||||
}
|
||||
|
||||
int getgroup(char *group)
|
||||
{
|
||||
#ifdef ENABLE_STATIC
|
||||
return fgetint("/etc/group", "x:\n", group);
|
||||
#else
|
||||
struct group *grp;
|
||||
|
||||
if ((grp = getgrnam(group)) == NULL)
|
||||
return -1;
|
||||
|
||||
return grp->gr_gid;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Signal safe sleep ... we get a lot of SIGCHLD at reboot */
|
||||
void do_sleep(unsigned int sec)
|
||||
{
|
||||
while ((sec = sleep(sec)))
|
||||
;
|
||||
}
|
||||
|
||||
void set_hostname(char **hostname)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen("/etc/hostname", "r");
|
||||
if (fp) {
|
||||
struct stat st;
|
||||
|
||||
if (fstat(fileno(fp), &st)) {
|
||||
fclose(fp);
|
||||
return;
|
||||
}
|
||||
|
||||
*hostname = realloc(*hostname, st.st_size);
|
||||
if (!*hostname) {
|
||||
fclose(fp);
|
||||
return;
|
||||
}
|
||||
|
||||
fgets(*hostname, st.st_size, fp);
|
||||
chomp(*hostname);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
if (*hostname)
|
||||
sethostname(*hostname, strlen(*hostname));
|
||||
}
|
||||
|
||||
#ifndef HAVE_GETFSENT
|
||||
static lfile_t *fstab = NULL;
|
||||
|
||||
int setfsent(void)
|
||||
{
|
||||
if (fstab)
|
||||
lfclose(fstab);
|
||||
|
||||
fstab = lfopen("/etc/fstab", " \t\n");
|
||||
if (!fstab)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
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:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
|
||||
@@ -1,13 +1,100 @@
|
||||
#ifndef __FINIT_HELPERS_H
|
||||
#define __FINIT_HELPERS_H
|
||||
/* Misc. utility functions and C-library extensions for finit and its plugins
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2015 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
int makepath (char *);
|
||||
void ifconfig (char *, char *, char *, int);
|
||||
void copyfile (char *, char *, int);
|
||||
void chomp (char *);
|
||||
#ifndef FINIT_HELPERS_H_
|
||||
#define FINIT_HELPERS_H_
|
||||
|
||||
#ifdef BUILTIN_RUNPARTS
|
||||
int run_parts (char *, ...);
|
||||
#endif
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h> /* strerror() */
|
||||
#include <syslog.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Error and debug messages
|
||||
*
|
||||
* Use of logit() is preferred, but these are guaranteed to display on
|
||||
* /dev/console as well. Useful for critical errors and early debug.
|
||||
*/
|
||||
#define _l(prio, fmt, args...) do { if (_slup) warnx(fmt, ##args); logit(prio, fmt "\n", ##args); } while (0)
|
||||
#define _m(prio, fmt, args...) do { _l(prio, "%s() - " fmt, __func__, ##args); } while (0)
|
||||
#define _d(fmt, args...) do { if (debug) { _m(LOG_DEBUG, fmt, ##args); } } while (0)
|
||||
#define _w(fmt, args...) do { _m(LOG_WARNING, fmt, ##args); } while (0)
|
||||
#define _e(fmt, args...) do { _m(LOG_ERR, fmt, ##args); } while (0)
|
||||
#define _pe(fmt, args...) do { _m(LOG_ERR, fmt ". Error %d: %s", ##args, errno, strerror(errno)); } while (0)
|
||||
|
||||
extern int _slup; /* INTERNAL: Is syslog up yet? */
|
||||
|
||||
char *strip_line (char *line);
|
||||
|
||||
void runlevel_set (int pre, int now);
|
||||
char *runlevel_string (int levels);
|
||||
|
||||
int pid_alive (pid_t pid);
|
||||
char *pid_get_name (pid_t pid, char *name, size_t len);
|
||||
|
||||
void procname_set (char *name, char *args[]);
|
||||
|
||||
void print (int action, const char *fmt, ...);
|
||||
void print_desc (char *action, char *desc);
|
||||
int print_result (int fail);
|
||||
|
||||
void logit (int prio, const char *fmt, ...);
|
||||
|
||||
int start_process (char *cmd, char *args[], int console);
|
||||
void do_sleep (unsigned int sec);
|
||||
int getuser (char *username, char **home);
|
||||
int getgroup (char *group);
|
||||
void set_hostname (char **hostname);
|
||||
|
||||
int complete (char *cmd, int pid);
|
||||
int run (char *cmd);
|
||||
int run_interactive (char *cmd, char *fmt, ...);
|
||||
pid_t run_getty (char *tty, char *speed, char *term, int console);
|
||||
int run_parts (char *dir, char *cmd);
|
||||
|
||||
#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 */
|
||||
|
||||
#endif /* FINIT_HELPERS_H_ */
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 69 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
@@ -0,0 +1,7 @@
|
||||
_______ __ _____ ___ __ ___________ _______
|
||||
/" "||" \ (\" \|" \ |" \(" _ ")/" __ )
|
||||
(: ______)|| | |.\\ \ | || |)__/ \\__/(__/ _) ./
|
||||
\/ | |: | |: \. \\ | |: | \\_ / / //
|
||||
// ___) |. | |. \ \. | |. | |. | __ \_ \\
|
||||
(: ( /\ |\| \ \ | /\ |\ \: | (: \__) :\
|
||||
\__/ (__\_|_)\___|\____\)(__\_|_) \__| \_______)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 8.6 KiB |
@@ -0,0 +1,735 @@
|
||||
/* Classic inetd services launcher for Finit
|
||||
*
|
||||
* Copyright (c) 2015 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <uev/uev.h>
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "inetd.h"
|
||||
#include "helpers.h"
|
||||
#include "private.h"
|
||||
#include "service.h"
|
||||
|
||||
#define ENABLE_SOCKOPT(sd, level, opt) \
|
||||
do { \
|
||||
int val = 1; \
|
||||
if (setsockopt(sd, level, opt, &val, sizeof(val)) < 0) \
|
||||
logit(LOG_CRIT, "Failed enabling %s on %s service", \
|
||||
#opt, inetd->name); \
|
||||
} while (0);
|
||||
|
||||
/* Peek into SOCK_DGRAM socket to figure out where an inbound packet comes from. */
|
||||
static int inetd_dgram_peek(int sd, char *ifname)
|
||||
{
|
||||
char cmbuf[0x100];
|
||||
struct msghdr msgh;
|
||||
struct cmsghdr *cmsg;
|
||||
|
||||
memset(&msgh, 0, sizeof(msgh));
|
||||
msgh.msg_control = cmbuf;
|
||||
msgh.msg_controllen = sizeof(cmbuf);
|
||||
|
||||
if (recvmsg(sd, &msgh, MSG_PEEK) < 0)
|
||||
return -1;
|
||||
|
||||
for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg; cmsg = CMSG_NXTHDR(&msgh,cmsg)) {
|
||||
struct in_pktinfo *ipi = (struct in_pktinfo *)CMSG_DATA(cmsg);
|
||||
|
||||
if (cmsg->cmsg_level != SOL_IP || cmsg->cmsg_type != IP_PKTINFO)
|
||||
continue;
|
||||
|
||||
if_indextoname(ipi->ipi_ifindex, ifname);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Peek into SOCK_STREAM on accepted client socket to figure out inbound interface */
|
||||
static int inetd_stream_peek(int sd, char *ifname)
|
||||
{
|
||||
struct ifaddrs *ifaddr, *ifa;
|
||||
struct sockaddr_in sin;
|
||||
socklen_t len = sizeof(sin);
|
||||
|
||||
if (-1 == getsockname(sd, (struct sockaddr *)&sin, &len))
|
||||
return -1;
|
||||
|
||||
if (-1 == getifaddrs(&ifaddr))
|
||||
return -1;
|
||||
|
||||
for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
|
||||
size_t len = sizeof(struct in_addr);
|
||||
struct sockaddr_in *iin;
|
||||
|
||||
if (!ifa->ifa_addr)
|
||||
continue;
|
||||
|
||||
if (ifa->ifa_addr->sa_family != AF_INET)
|
||||
continue;
|
||||
|
||||
iin = (struct sockaddr_in *)ifa->ifa_addr;
|
||||
if (!memcmp(&sin.sin_addr, &iin->sin_addr, len)) {
|
||||
strncpy(ifname, ifa->ifa_name, IF_NAMESIZE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs(ifaddr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_stdin(svc_t *svc)
|
||||
{
|
||||
int stdin = svc->inetd.watcher.fd;
|
||||
char ifname[IF_NAMESIZE] = "UNKNOWN";
|
||||
|
||||
if (svc->inetd.type == SOCK_STREAM) {
|
||||
/* Open new client socket from server socket */
|
||||
stdin = accept(stdin, NULL, NULL);
|
||||
if (stdin < 0) {
|
||||
logit(LOG_CRIT, "Failed accepting inetd service %d/tcp", svc->inetd.port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
_d("New client socket %d accepted for inetd service %d/tcp", stdin, svc->inetd.port);
|
||||
|
||||
inetd_stream_peek(stdin, ifname);
|
||||
} else { /* SOCK_DGRAM */
|
||||
inetd_dgram_peek(stdin, ifname);
|
||||
}
|
||||
|
||||
if (!inetd_is_allowed(&svc->inetd, ifname)) {
|
||||
logit(LOG_INFO, "Service %s on %s:%d is not allowed", svc->inetd.name, ifname, svc->inetd.port);
|
||||
if (svc->inetd.type == SOCK_STREAM)
|
||||
close(stdin);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return stdin;
|
||||
}
|
||||
|
||||
/* Socket callback, looks up correct svc and starts it as an inetd service */
|
||||
static void socket_cb(uev_t *UNUSED(w), void *arg, int UNUSED(events))
|
||||
{
|
||||
svc_t *svc = (svc_t *)arg, *task;
|
||||
int stdin;
|
||||
|
||||
_d("Got event on %s socket ...", svc->cmd);
|
||||
stdin = get_stdin(svc);
|
||||
if (stdin < 0) {
|
||||
logit(LOG_CRIT, "%s: Unable to accept incoming connection", svc->cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure to disable O_NONBLOCK on the descriptor before
|
||||
* passing it to the inetd service, that's what is expected.
|
||||
*/
|
||||
if (fcntl(stdin, F_SETFL, fcntl(stdin, F_GETFL, 0) & ~O_NONBLOCK) < 0) {
|
||||
logit(LOG_CRIT, "Failed disabling non-blocking on %s socket", svc->cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
task = svc_new(svc->cmd, svc->inetd.next_id++, SVC_TYPE_INETD_CONN);
|
||||
if (!task) {
|
||||
logit(LOG_CRIT, "%s: Unable to allocate service for inetd client",
|
||||
svc->cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!svc->inetd.forking) {
|
||||
svc_busy(svc);
|
||||
service_step(svc);
|
||||
}
|
||||
|
||||
/* Copy inherited attributes from inetd service's svc */
|
||||
task->runlevels = svc->runlevels;
|
||||
|
||||
/* Only copy the most relevant parts of inetd, in particular we
|
||||
* must *not* copy the watcher data to the clone! */
|
||||
task->inetd.svc = svc;
|
||||
task->inetd.cmd = svc->inetd.cmd;
|
||||
task->inetd.type = svc->inetd.type;
|
||||
|
||||
memcpy(task->cond, svc->cond, sizeof(task->cond));
|
||||
memcpy(task->username, svc->username, sizeof(task->username));
|
||||
memcpy(task->group, svc->group, sizeof(task->group));
|
||||
memcpy(task->args, svc->args, sizeof(task->args));
|
||||
snprintf(task->desc, sizeof(task->desc), "%s connection", svc->desc);
|
||||
|
||||
task->stdin_fd = stdin;
|
||||
service_step(task);
|
||||
}
|
||||
|
||||
/*
|
||||
* Refuse service if the request specifies a reply port corresponding to any internal service.
|
||||
* This is done as a defense against looping attacks; the remote IP address is logged.
|
||||
* http://www.freebsd.org/cgi/man.cgi?inetd(8)
|
||||
* https://svnweb.freebsd.org/base/head/usr.sbin/inetd/inetd.c?revision=298909&view=markup#l2094
|
||||
*/
|
||||
int inetd_check_loop(struct sockaddr *sa, socklen_t len, char *name)
|
||||
{
|
||||
svc_t *svc;
|
||||
char pname[NI_MAXHOST];
|
||||
|
||||
for (svc = svc_inetd_iterator(1); svc; svc = svc_inetd_iterator(0)) {
|
||||
inetd_t *i = &svc->inetd;
|
||||
|
||||
if (!i->builtin || i->type != SOCK_DGRAM)
|
||||
continue;
|
||||
|
||||
if (((const struct sockaddr_in *)sa)->sin_port == i->port) {
|
||||
getnameinfo(sa, len, pname, sizeof(pname), NULL, 0, NI_NUMERICHOST);
|
||||
logit(LOG_WARNING, "%s/%s:%s/%s loop request REFUSED from %s", i->name, "UDP", name, "UDP", pname);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Launch Inet socket for service.
|
||||
* TODO: Add filtering ALLOW/DENY per interface.
|
||||
*/
|
||||
static int spawn_socket(inetd_t *inetd)
|
||||
{
|
||||
int sd;
|
||||
socklen_t len = sizeof(struct sockaddr);
|
||||
struct sockaddr_in s;
|
||||
|
||||
if (!inetd->type) {
|
||||
logit(LOG_CRIT, "Invalid inetd service %s, skipping ...", inetd->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
_d("Spawning server socket for inetd %s, type %s ...", inetd->name, inetd->type == SOCK_STREAM ? "stream" : "dgram");
|
||||
sd = socket(AF_INET, inetd->type | SOCK_NONBLOCK | SOCK_CLOEXEC, inetd->proto);
|
||||
if (-1 == sd) {
|
||||
logit(LOG_CRIT, "Failed opening inetd socket type %d proto %d", inetd->type, inetd->proto);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
ENABLE_SOCKOPT(sd, SOL_SOCKET, SO_REUSEADDR);
|
||||
#ifdef SO_REUSEPORT
|
||||
ENABLE_SOCKOPT(sd, SOL_SOCKET, SO_REUSEPORT);
|
||||
#endif
|
||||
|
||||
memset(&s, 0, sizeof(s));
|
||||
s.sin_family = AF_INET;
|
||||
s.sin_addr.s_addr = INADDR_ANY;
|
||||
s.sin_port = htons(inetd->port);
|
||||
if (bind(sd, (struct sockaddr *)&s, len) < 0) {
|
||||
logit(LOG_CRIT, "Failed binding to port %d, maybe another %s server is already running?",
|
||||
inetd->port, inetd->name);
|
||||
close(sd);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (inetd->port) {
|
||||
if (inetd->type == SOCK_STREAM) {
|
||||
if (-1 == listen(sd, 10)) {
|
||||
logit(LOG_CRIT, "Failed listening to inetd service %s", inetd->name);
|
||||
close(sd);
|
||||
return -errno;
|
||||
}
|
||||
} else { /* SOCK_DGRAM */
|
||||
/* Set extra sockopt to get ifindex from inbound packets */
|
||||
ENABLE_SOCKOPT(sd, SOL_IP, IP_PKTINFO);
|
||||
}
|
||||
}
|
||||
|
||||
if (uev_io_init(ctx, &inetd->watcher, socket_cb, inetd->svc, sd, UEV_READ)) {
|
||||
logit(LOG_CRIT, "Failed setting up inetd watcher for %s", inetd->name);
|
||||
close(sd);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int inetd_start(inetd_t *inetd)
|
||||
{
|
||||
int sd;
|
||||
char buf[BUFSIZ];
|
||||
ssize_t len;
|
||||
|
||||
sd = inetd->watcher.fd;
|
||||
if (sd == -1)
|
||||
return spawn_socket(inetd);
|
||||
|
||||
/* Read anything lingering, or clean up socket after failure */
|
||||
len = recv(sd, buf, sizeof(buf), MSG_DONTWAIT);
|
||||
if (len > 0)
|
||||
_d("Read %zd lingering bytes from socket before (re)starting %s ...", len, inetd->svc->cmd);
|
||||
|
||||
/* Restore O_NONBLOCK for socket */
|
||||
if (fcntl(sd, F_SETFL, fcntl(sd, F_GETFL, 0) | O_NONBLOCK)) {
|
||||
logit(LOG_CRIT, "Cannot safely (re)start %s inetd service", inetd->svc->cmd);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
_d("Re-starting %s socket watcher ...", inetd->svc->cmd);
|
||||
uev_io_start(&inetd->watcher);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void inetd_stop(inetd_t *inetd)
|
||||
{
|
||||
if (inetd->watcher.fd != -1) {
|
||||
_d("Stopping %s socket watcher ...", inetd->svc->cmd);
|
||||
uev_io_stop(&inetd->watcher);
|
||||
|
||||
/* For dgram inetd services we block the parent SVC
|
||||
* and halt the watcher, so don't close the socket! */
|
||||
if (!svc_is_busy(inetd->svc)) {
|
||||
_d("Shutting down inet socket %d ...", inetd->watcher.fd);
|
||||
if (inetd->type == SOCK_STREAM)
|
||||
shutdown(inetd->watcher.fd, SHUT_RDWR);
|
||||
close(inetd->watcher.fd);
|
||||
inetd->watcher.fd = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct servent *fallback_service(char *service, char *proto)
|
||||
{
|
||||
int service_num;
|
||||
static struct servent lfs;
|
||||
|
||||
service_num = fgetint("/etc/services", " \n\t", service);
|
||||
if (service_num > 0) {
|
||||
lfs.s_name = service;
|
||||
lfs.s_port = htons(service_num);
|
||||
lfs.s_proto = NULL;
|
||||
if (!strcmp("tcp", proto) || !strcmp("udp", proto))
|
||||
lfs.s_proto = proto;
|
||||
|
||||
return &lfs;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct servent *getent_service(char *service, char *proto)
|
||||
{
|
||||
struct servent *ent;
|
||||
|
||||
#ifdef ENABLE_STATIC
|
||||
ent = fallback_service(service, proto);
|
||||
#else
|
||||
ent = getservbyname(service, proto);
|
||||
if (!ent)
|
||||
ent = fallback_service(service, proto);
|
||||
#endif
|
||||
return ent;
|
||||
}
|
||||
|
||||
static struct protoent *fallback_proto(char *proto)
|
||||
{
|
||||
int proto_num;
|
||||
static struct protoent lfp;
|
||||
|
||||
proto_num = fgetint("/etc/protocols", " \n\t", proto);
|
||||
if (proto_num > 0) {
|
||||
lfp.p_name = proto;
|
||||
lfp.p_proto = proto_num;
|
||||
|
||||
return &lfp;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct protoent *getent_proto(char *proto)
|
||||
{
|
||||
struct protoent *ent;
|
||||
|
||||
#ifdef ENABLE_STATIC
|
||||
ent = fallback_proto(proto);
|
||||
#else
|
||||
ent = getprotobyname(proto);
|
||||
if (!ent)
|
||||
ent = fallback_proto(proto);
|
||||
#endif
|
||||
return ent;
|
||||
}
|
||||
|
||||
static int getent(char *service, char *proto, struct servent **sv, struct protoent **pv)
|
||||
{
|
||||
if (!fexist("/etc/services") || !fexist("/etc/protocols")) {
|
||||
_w("Cannot register inetd %s/%s, system missing /etc/services or /etc/protocols", service, proto);
|
||||
return errno = ECANCELED;
|
||||
}
|
||||
|
||||
*sv = getent_service(service, proto);
|
||||
if (!*sv) {
|
||||
const char *errstr;
|
||||
static struct servent s;
|
||||
|
||||
s.s_name = service;
|
||||
s.s_port = strtonum(service, 1, UINT16_MAX, &errstr);
|
||||
s.s_proto = NULL;
|
||||
if (!strcmp("tcp", proto) || !strcmp("udp", proto))
|
||||
s.s_proto = proto;
|
||||
|
||||
if (errstr || !s.s_proto) {
|
||||
_e("Invalid/unknown inetd service, cannot create custom entry");
|
||||
return errno = EINVAL;
|
||||
}
|
||||
|
||||
_d("Creating cutom inetd service %s/%s", service, proto);
|
||||
s.s_port = htons(s.s_port);
|
||||
*sv = &s;
|
||||
}
|
||||
|
||||
if (pv && (*sv)->s_proto) {
|
||||
*pv = getent_proto((*sv)->s_proto);
|
||||
if (!*pv) {
|
||||
_e("Cannot find proto %s, skipping ...", (*sv)->s_proto);
|
||||
return errno = EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find exact match.
|
||||
*/
|
||||
static inetd_filter_t *find_filter(inetd_t *inetd, char *ifname)
|
||||
{
|
||||
inetd_filter_t *filter;
|
||||
|
||||
if (!ifname)
|
||||
ifname = "*";
|
||||
|
||||
TAILQ_FOREACH(filter, &inetd->filters, link) {
|
||||
_d("Checking filters for %s: '%s' vs '%s' (exact match) ...",
|
||||
inetd->name, filter->ifname, ifname);
|
||||
|
||||
if (!strcmp(filter->ifname, ifname))
|
||||
return filter;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* First try exact match, then fall back to any match.
|
||||
*/
|
||||
inetd_filter_t *inetd_filter_match(inetd_t *inetd, char *ifname)
|
||||
{
|
||||
inetd_filter_t *filter = find_filter(inetd, ifname);
|
||||
|
||||
if (filter)
|
||||
return filter;
|
||||
|
||||
TAILQ_FOREACH(filter, &inetd->filters, link) {
|
||||
_d("Checking filters for %s: '%s' vs '%s' (any match) ...",
|
||||
inetd->name, filter->ifname, ifname);
|
||||
|
||||
if (!strcmp(filter->ifname, "*"))
|
||||
return filter;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int inetd_flush(inetd_t *inetd)
|
||||
{
|
||||
inetd_filter_t *filter, *next;
|
||||
|
||||
TAILQ_FOREACH_SAFE(filter, &inetd->filters, link, next) {
|
||||
TAILQ_REMOVE(&inetd->filters, filter, link);
|
||||
free(filter);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Poor man's tcpwrappers filtering */
|
||||
int inetd_allow(inetd_t *inetd, char *ifname)
|
||||
{
|
||||
inetd_filter_t *filter;
|
||||
|
||||
if (!inetd)
|
||||
return errno = EINVAL;
|
||||
|
||||
if (!ifname)
|
||||
ifname = "*";
|
||||
|
||||
filter = inetd_filter_match(inetd, ifname);
|
||||
if (filter) {
|
||||
_d("Filter %s for inetd %s already exists, skipping ...", ifname, inetd->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_d("Allow iface %s for service %s (port %d)", ifname, inetd->name, inetd->port);
|
||||
filter = calloc(1, sizeof(*filter));
|
||||
if (!filter) {
|
||||
_e("Out of memory, cannot add filter to service %s", inetd->name);
|
||||
return errno = ENOMEM;
|
||||
}
|
||||
|
||||
filter->deny = 0;
|
||||
strlcpy(filter->ifname, ifname, sizeof(filter->ifname));
|
||||
TAILQ_INSERT_TAIL(&inetd->filters, filter, link);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int inetd_deny(inetd_t *inetd, char *ifname)
|
||||
{
|
||||
inetd_filter_t *filter;
|
||||
|
||||
if (!inetd)
|
||||
return errno = EINVAL;
|
||||
|
||||
if (!ifname)
|
||||
ifname = "*";
|
||||
|
||||
filter = find_filter(inetd, ifname);
|
||||
if (filter) {
|
||||
_d("%s filter %s for inetd %s already exists, cannot set deny filter for same, skipping ...",
|
||||
filter->deny ? "Deny" : "Allow", ifname, inetd->name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
_d("Deny iface %s for service %s (port %d)", ifname, inetd->name, inetd->port);
|
||||
filter = calloc(1, sizeof(*filter));
|
||||
if (!filter) {
|
||||
_e("Out of memory, cannot add filter to service %s", inetd->name);
|
||||
return errno = ENOMEM;
|
||||
}
|
||||
|
||||
filter->deny = 1;
|
||||
strlcpy(filter->ifname, ifname, sizeof(filter->ifname));
|
||||
TAILQ_INSERT_TAIL(&inetd->filters, filter, link);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int inetd_is_allowed(inetd_t *inetd, char *ifname)
|
||||
{
|
||||
inetd_filter_t *filter;
|
||||
|
||||
if (!inetd) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
filter = inetd_filter_match(inetd, ifname);
|
||||
if (filter) {
|
||||
_d("Found matching filter for %s, deny: %d ... ", inetd->name, filter->deny);
|
||||
return !filter->deny;
|
||||
}
|
||||
|
||||
_d("No matching filter for %s ... ", inetd->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int inetd_match(inetd_t *inetd, char *service, char *proto)
|
||||
{
|
||||
struct servent *sv = NULL;
|
||||
struct protoent *pv = NULL;
|
||||
|
||||
if (!inetd || !service || !proto)
|
||||
return errno = EINVAL;
|
||||
|
||||
if (strncmp(inetd->name, service, sizeof(inetd->name)))
|
||||
return 0;
|
||||
|
||||
if (getent(service, proto, &sv, &pv))
|
||||
return 0;
|
||||
|
||||
if (inetd->proto == ntohs(pv->p_proto) &&
|
||||
inetd->port == ntohs(sv->s_port))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compose presentable string of inetd filters: !eth0,eth1,eth2,!eth3 */
|
||||
int inetd_filter_str(inetd_t *inetd, char *str, size_t len)
|
||||
{
|
||||
int prev = 0;
|
||||
char buf[42];
|
||||
inetd_filter_t *filter;
|
||||
|
||||
if (!inetd || !str || len <= 0) {
|
||||
_e("Dafuq?");
|
||||
return 1;
|
||||
}
|
||||
|
||||
snprintf(str, len, "%s allow %s ", inetd->name,
|
||||
inetd->type == SOCK_DGRAM ? "UDP" : "TCP");
|
||||
TAILQ_FOREACH(filter, &inetd->filters, link) {
|
||||
char ifname[IFNAMSIZ];
|
||||
|
||||
if (filter->deny)
|
||||
continue;
|
||||
|
||||
if (!strlen(filter->ifname))
|
||||
snprintf(ifname, sizeof(ifname), "*");
|
||||
else
|
||||
strlcpy(ifname, filter->ifname, sizeof(ifname));
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s%s:%d", prev ? "," : "",
|
||||
ifname, inetd->port);
|
||||
prev = 1;
|
||||
strlcat(str, buf, len);
|
||||
}
|
||||
|
||||
prev = 0;
|
||||
TAILQ_FOREACH(filter, &inetd->filters, link) {
|
||||
char ifname[IFNAMSIZ];
|
||||
|
||||
if (!filter->deny)
|
||||
continue;
|
||||
if (!prev) {
|
||||
snprintf(buf, sizeof(buf), " deny ");
|
||||
strlcat(str, buf, len);
|
||||
}
|
||||
|
||||
if (!strlen(filter->ifname))
|
||||
snprintf(ifname, sizeof(ifname), "*");
|
||||
else
|
||||
strlcpy(ifname, filter->ifname, sizeof(ifname));
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s%s", prev ? "," : "", ifname);
|
||||
prev = 1;
|
||||
strlcat(str, buf, len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
svc_t *inetd_find_svc(char *path, char *service, char *proto)
|
||||
{
|
||||
svc_t *svc;
|
||||
|
||||
for (svc = svc_inetd_iterator(1); svc; svc = svc_inetd_iterator(0)) {
|
||||
if (strncmp(path, svc->cmd, strlen(svc->cmd)))
|
||||
continue;
|
||||
|
||||
if (inetd_match(&svc->inetd, service, proto)) {
|
||||
_d("Found a matching inetd svc for %s %s %s", path, service, proto);
|
||||
return svc;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called to add a new, unique, inetd service. When an
|
||||
* ifname is given as argument this means *only* run service on this
|
||||
* interface. If a similar service runs on another port, this function
|
||||
* must add this ifname as "deny" to that other service.
|
||||
*
|
||||
* Example:
|
||||
* inetd ssh@eth0:222/tcp nowait [2345] /usr/sbin/sshd -i
|
||||
* inetd ssh/tcp nowait [2345] /usr/sbin/sshd -i
|
||||
*
|
||||
* In this example eth0:222 is very specific, so when ssh/tcp (default)
|
||||
* is added we must find the previous 'ssh' service and add its eth0 as
|
||||
* deny, so we don't accept port 22 session on eth0.
|
||||
*
|
||||
* In the reverse case, where the default (ssh/tcp) entry is listed
|
||||
* before the specific (eth0:222), the new inetd service must find the
|
||||
* (any!) previous rule and add its ifname to their deny list.
|
||||
*
|
||||
* If equivalent service exists already service_register() will instead call
|
||||
* inetd_allow().
|
||||
*/
|
||||
int inetd_new(inetd_t *inetd, char *name, char *service, char *proto, int forking, svc_t *svc)
|
||||
{
|
||||
int result;
|
||||
struct servent *sv = NULL;
|
||||
struct protoent *pv = NULL;
|
||||
|
||||
if (!inetd || !service || !proto)
|
||||
return errno = EINVAL;
|
||||
|
||||
result = getent(service, proto, &sv, &pv);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
/* Setup defaults */
|
||||
inetd->std = 1;
|
||||
inetd->port = ntohs(sv->s_port);
|
||||
inetd->proto = pv->p_proto;
|
||||
inetd->forking = !!forking;
|
||||
inetd->next_id = 2;
|
||||
if (!name)
|
||||
name = service;
|
||||
strlcpy(inetd->name, name, sizeof(inetd->name));
|
||||
TAILQ_INIT(&inetd->filters);
|
||||
|
||||
/* Naïve mapping tcp->stream, udp->dgram, other->dgram */
|
||||
if (!strcasecmp(sv->s_proto, "tcp"))
|
||||
inetd->type = SOCK_STREAM;
|
||||
else
|
||||
inetd->type = SOCK_DGRAM;
|
||||
|
||||
if (inetd->type == SOCK_DGRAM && inetd->forking) {
|
||||
logit(LOG_WARNING, "%s: 'nowait' is not applicable on UDP services, ignoring", svc->cmd);
|
||||
inetd->forking = 0;
|
||||
}
|
||||
|
||||
/* Reset descriptor, used internally */
|
||||
inetd->watcher.fd = -1;
|
||||
|
||||
/* Setup socket callback argument */
|
||||
inetd->svc = svc;
|
||||
|
||||
_d("New service %s (default port %d proto %s:%d)", name, inetd->port, sv->s_proto, pv->p_proto);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int inetd_del(inetd_t *inetd)
|
||||
{
|
||||
svc_unblock(inetd->svc);
|
||||
inetd_stop(inetd);
|
||||
|
||||
return inetd_flush(inetd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,82 @@
|
||||
/* Classic inetd services launcher for Finit
|
||||
*
|
||||
* Copyright (c) 2015 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef FINIT_INETD_H_
|
||||
#define FINIT_INETD_H_
|
||||
|
||||
#include <netdb.h>
|
||||
#include <net/if.h>
|
||||
#include <uev/uev.h>
|
||||
#include <lite/queue.h> /* BSD sys/queue.h API */
|
||||
|
||||
typedef struct svc svc_t;
|
||||
|
||||
typedef struct inetd_filter {
|
||||
TAILQ_ENTRY(inetd_filter) link;
|
||||
int deny; /* 0:allow, 1:deny */
|
||||
char ifname[IFNAMSIZ]; /* E.g., eth0 */
|
||||
} inetd_filter_t;
|
||||
|
||||
typedef struct {
|
||||
uev_t watcher;
|
||||
svc_t *svc; /* svc_t pointer for the socket callback */
|
||||
|
||||
int type; /* Socket type: SOCK_STREAM/SOCK_DGRAM */
|
||||
int std; /* Standard proto/port from /etc/services */
|
||||
int proto;
|
||||
int port;
|
||||
int forking;
|
||||
int builtin; /* Set by built-in inetd services only */
|
||||
int next_id; /* Next child job's id */
|
||||
char name[10];
|
||||
int (*cmd)(int type); /* internal inetd service, like 'time' */
|
||||
|
||||
TAILQ_HEAD(, inetd_filter) filters;
|
||||
} inetd_t;
|
||||
|
||||
int inetd_check_loop(struct sockaddr *sa, socklen_t len, char *name);
|
||||
|
||||
int inetd_start (inetd_t *inetd);
|
||||
void inetd_stop (inetd_t *inetd);
|
||||
|
||||
int inetd_new (inetd_t *inetd, char *name, char *service, char *proto, int forking, svc_t *svc);
|
||||
int inetd_del (inetd_t *inetd);
|
||||
|
||||
svc_t *inetd_find_svc (char *path, char *service, char *proto);
|
||||
|
||||
int inetd_match (inetd_t *inetd, char *service, char *proto);
|
||||
int inetd_filter_str(inetd_t *inetd, char *str, size_t len);
|
||||
|
||||
int inetd_flush (inetd_t *inetd);
|
||||
int inetd_allow (inetd_t *inetd, char *ifname);
|
||||
int inetd_deny (inetd_t *inetd, char *ifname);
|
||||
int inetd_is_allowed(inetd_t *inetd, char *ifname);
|
||||
|
||||
#endif /* FINIT_INETD_H_ */
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,516 @@
|
||||
/* New client tool, complements old /dev/initctl API and telinit tool
|
||||
*
|
||||
* Copyright (c) 2015-2016 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <ctype.h>
|
||||
#include <getopt.h>
|
||||
#include <glob.h>
|
||||
#include <paths.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "finit.h"
|
||||
#include "cond.h"
|
||||
#include "helpers.h"
|
||||
#include "service.h"
|
||||
#include "util.h"
|
||||
#include "utmp-api.h"
|
||||
|
||||
#define _PATH_COND _PATH_VARRUN "finit/cond/"
|
||||
|
||||
typedef struct {
|
||||
char *cmd;
|
||||
int (*cb)(char *arg);
|
||||
} command_t;
|
||||
|
||||
int debug = 0;
|
||||
int verbose = 0;
|
||||
int silent = 1; /* For helpers.c */
|
||||
int runlevel = 0;
|
||||
|
||||
static int do_send(struct init_request *rq, ssize_t len)
|
||||
{
|
||||
int sd, result = 255;
|
||||
struct sockaddr_un sun = {
|
||||
.sun_family = AF_UNIX,
|
||||
.sun_path = INIT_SOCKET,
|
||||
};
|
||||
|
||||
sd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (-1 == sd)
|
||||
return -1;
|
||||
|
||||
if (connect(sd, (struct sockaddr*)&sun, sizeof(sun)) == -1)
|
||||
goto error;
|
||||
|
||||
if (write(sd, rq, len) != len)
|
||||
goto error;
|
||||
|
||||
if (read(sd, rq, len) != len)
|
||||
goto error;
|
||||
|
||||
result = 0;
|
||||
goto exit;
|
||||
error:
|
||||
perror("Failed communicating with finit");
|
||||
exit:
|
||||
close(sd);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int runlevel_get(void)
|
||||
{
|
||||
int sd, result = 255;
|
||||
struct init_request rq;
|
||||
struct sockaddr_un sun = {
|
||||
.sun_family = AF_UNIX,
|
||||
.sun_path = INIT_SOCKET,
|
||||
};
|
||||
|
||||
memset(&rq, 0, sizeof(rq));
|
||||
rq.cmd = INIT_CMD_GET_RUNLEVEL;
|
||||
rq.magic = INIT_MAGIC;
|
||||
|
||||
sd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (-1 == sd)
|
||||
return -1;
|
||||
|
||||
if (connect(sd, (struct sockaddr*)&sun, sizeof(sun)) == -1)
|
||||
goto error;
|
||||
|
||||
if (write(sd, &rq, sizeof(rq)) != sizeof(rq))
|
||||
goto error;
|
||||
|
||||
if (read(sd, &rq, sizeof(rq)) != sizeof(rq))
|
||||
goto error;
|
||||
|
||||
result = rq.runlevel;
|
||||
goto exit;
|
||||
error:
|
||||
perror("Failed communicating with finit");
|
||||
result = -1;
|
||||
exit:
|
||||
close(sd);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int toggle_debug(char *UNUSED(arg))
|
||||
{
|
||||
struct init_request rq = {
|
||||
.magic = INIT_MAGIC,
|
||||
.cmd = INIT_CMD_DEBUG,
|
||||
};
|
||||
|
||||
return do_send(&rq, sizeof(rq));
|
||||
}
|
||||
|
||||
static int do_runlevel(char *arg)
|
||||
{
|
||||
struct init_request rq = {
|
||||
.magic = INIT_MAGIC,
|
||||
.cmd = INIT_CMD_RUNLVL,
|
||||
.runlevel = (int)arg[0],
|
||||
};
|
||||
|
||||
/* Not compatible with the SysV runlevel(8) command, it prints
|
||||
* "PREVLEVEL RUNLEVEL", we just print the current runlevel. */
|
||||
if (!rq.runlevel) {
|
||||
printf("%d\n", runlevel_get());
|
||||
return 0;
|
||||
}
|
||||
|
||||
return do_send(&rq, sizeof(rq));
|
||||
}
|
||||
|
||||
static int do_svc(int cmd, char *arg)
|
||||
{
|
||||
struct init_request rq = {
|
||||
.magic = INIT_MAGIC,
|
||||
.cmd = cmd,
|
||||
};
|
||||
|
||||
strlcpy(rq.data, arg, sizeof(rq.data));
|
||||
|
||||
return do_send(&rq, sizeof(rq));
|
||||
}
|
||||
|
||||
static int do_emit (char *arg) { return do_svc(INIT_CMD_EMIT, arg); }
|
||||
static int do_reload (char *arg) { return do_svc(INIT_CMD_RELOAD, arg); }
|
||||
static int do_start (char *arg) { return do_svc(INIT_CMD_START_SVC, arg); }
|
||||
static int do_stop (char *arg) { return do_svc(INIT_CMD_STOP_SVC, arg); }
|
||||
static int do_restart(char *arg) { return do_svc(INIT_CMD_RESTART_SVC, arg); }
|
||||
|
||||
static void show_cond_one(const char *_conds)
|
||||
{
|
||||
static char conds[MAX_ARG_LEN];
|
||||
char *cond;
|
||||
|
||||
strlcpy(conds, _conds, sizeof(conds));
|
||||
|
||||
putchar('<');
|
||||
|
||||
for (cond = strtok(conds, ","); cond; cond = strtok(NULL, ",")) {
|
||||
if (cond != conds)
|
||||
putchar(',');
|
||||
|
||||
switch (cond_get(cond)) {
|
||||
case COND_ON:
|
||||
printf("+%s", cond);
|
||||
break;
|
||||
|
||||
case COND_FLUX:
|
||||
printf("\e[1m~%s\e[0m", cond);
|
||||
break;
|
||||
|
||||
case COND_OFF:
|
||||
printf("\e[1m-%s\e[0m", cond);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
putchar('>');
|
||||
}
|
||||
|
||||
static int do_cond_magic(char op, char *cond)
|
||||
{
|
||||
cond[0] = op;
|
||||
return do_emit(cond);
|
||||
}
|
||||
|
||||
static int do_cond_set (char *cond) { return do_cond_magic('+', cond); }
|
||||
static int do_cond_clear(char *cond) { return do_cond_magic('-', cond); }
|
||||
|
||||
static int do_cond_show(char *UNUSED(arg))
|
||||
{
|
||||
svc_t *svc;
|
||||
enum cond_state cond;
|
||||
|
||||
if (verbose) {
|
||||
glob_t gl;
|
||||
|
||||
printf("Asserted conditions (taken from %s)\n", _PATH_COND);
|
||||
printf("===============================================================================\n");
|
||||
|
||||
if (!glob(_PATH_COND "*/*/*", 0, NULL, &gl)) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < gl.gl_pathc; i++) {
|
||||
char *cond, *name = gl.gl_pathv[i];
|
||||
struct stat st;
|
||||
|
||||
if (stat(name, &st) || S_ISDIR(st.st_mode))
|
||||
continue;
|
||||
|
||||
cond = name + strlen(_PATH_COND);
|
||||
printf("\t%s\n", cond);
|
||||
}
|
||||
globfree(&gl);
|
||||
}
|
||||
puts("");
|
||||
}
|
||||
|
||||
printf("PID Service Status Condition (+ on, ~ flux, - off)\n");
|
||||
printf("===============================================================================\n");
|
||||
|
||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
||||
if (!svc->cond[0])
|
||||
continue;
|
||||
|
||||
cond = cond_get_agg(svc->cond);
|
||||
|
||||
printf("%-6d %-20.20s ", svc->pid, svc->cmd);
|
||||
|
||||
if (cond == COND_ON)
|
||||
printf("%-6.6s ", condstr(cond));
|
||||
else
|
||||
printf("\e[1m%-6.6s\e[0m ", condstr(cond));
|
||||
|
||||
show_cond_one(svc->cond);
|
||||
puts("");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_cond(char *cmd)
|
||||
{
|
||||
int c;
|
||||
char *arg;
|
||||
command_t command[] = {
|
||||
{ "set", do_cond_set },
|
||||
{ "clear", do_cond_clear },
|
||||
{ "show", do_cond_show },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
arg = strpbrk(cmd, " ");
|
||||
if (arg) {
|
||||
*arg = 0;
|
||||
|
||||
for (c = 0; command[c].cmd; c++) {
|
||||
if (!strcmp(command[c].cmd, cmd))
|
||||
return command[c].cb(arg);
|
||||
}
|
||||
}
|
||||
|
||||
return do_cond_show(NULL);
|
||||
}
|
||||
|
||||
static int do_signal(int signo, const char *msg)
|
||||
{
|
||||
if (kill(1, signo))
|
||||
err(1, "Failed signalling init to %s", msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_halt (char *UNUSED(arg)) { return do_signal(SIGUSR1, "halt"); }
|
||||
static int do_poweroff(char *UNUSED(arg)) { return do_signal(SIGUSR2, "power off"); }
|
||||
static int do_reboot (char *UNUSED(arg)) { return do_signal(SIGTERM, "reboot"); }
|
||||
|
||||
static int do_utmp(char *UNUSED(cmd))
|
||||
{
|
||||
return utmp_show(_PATH_WTMP) ||
|
||||
utmp_show(_PATH_UTMP);
|
||||
}
|
||||
|
||||
static int show_version(char *UNUSED(arg))
|
||||
{
|
||||
puts("v" PACKAGE_VERSION);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* In verbose mode we skip the header and each service description.
|
||||
* This in favor of having all info on one line so a machine can more
|
||||
* easily parse it. */
|
||||
static int show_status(char *arg)
|
||||
{
|
||||
svc_t *svc;
|
||||
|
||||
/* Fetch UTMP runlevel, needed for svc_status() call below */
|
||||
runlevel = runlevel_get();
|
||||
|
||||
if (arg && arg[0]) {
|
||||
int id = 1;
|
||||
char *ptr, *next;
|
||||
|
||||
ptr = strchr(arg, ':');
|
||||
if (ptr) {
|
||||
*ptr++ = 0;
|
||||
next = strchr(ptr, ' ');
|
||||
if (next)
|
||||
*next = 0;
|
||||
id = atonum(ptr);
|
||||
}
|
||||
|
||||
if (isdigit(arg[0]))
|
||||
svc = svc_find_by_jobid(atonum(arg), id);
|
||||
else
|
||||
svc = svc_find_by_nameid(arg, id);
|
||||
|
||||
if (!svc)
|
||||
return 1;
|
||||
|
||||
printf("%s\n", svc_status(svc));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!verbose) {
|
||||
printf("# Status PID Runlevels Service Description\n");
|
||||
printf("===============================================================================\n");
|
||||
}
|
||||
|
||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
||||
char jobid[10], args[512] = "", *lvls;
|
||||
|
||||
if (svc_is_unique(svc))
|
||||
snprintf(jobid, sizeof(jobid), "%d", svc->job);
|
||||
else
|
||||
snprintf(jobid, sizeof(jobid), "%d:%d", svc->job, svc->id);
|
||||
|
||||
printf("%-5s %7s ", jobid, svc_status(svc));
|
||||
if (svc_is_inetd(svc))
|
||||
printf("inetd ");
|
||||
else
|
||||
printf("%-6d ", svc->pid);
|
||||
|
||||
lvls = runlevel_string(svc->runlevels);
|
||||
if (strchr(lvls, '\e'))
|
||||
printf("%-18.18s ", lvls);
|
||||
else
|
||||
printf("%-10.10s ", lvls);
|
||||
|
||||
if (!verbose) {
|
||||
char *name = strrchr(svc->cmd, '/');
|
||||
|
||||
if (!name)
|
||||
name = svc->cmd;
|
||||
else
|
||||
name++;
|
||||
|
||||
printf("%-20.20s %-21.21s\n", name, svc->desc);
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifndef INETD_DISABLED
|
||||
if (svc_is_inetd(svc)) {
|
||||
char *info;
|
||||
struct init_request rq = {
|
||||
.magic = INIT_MAGIC,
|
||||
.cmd = INIT_CMD_QUERY_INETD,
|
||||
};
|
||||
|
||||
snprintf(rq.data, sizeof(rq.data), "%s", jobid);
|
||||
if (do_send(&rq, sizeof(rq))) {
|
||||
snprintf(args, sizeof(args), "Unknown inetd");
|
||||
info = args;
|
||||
} else {
|
||||
info = rq.data;
|
||||
if (strcmp("internal", svc->cmd)) {
|
||||
char *ptr = strchr(info, ' ');
|
||||
if (ptr)
|
||||
info = ptr + 1;
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s %s\n", svc->cmd, info);
|
||||
}
|
||||
else
|
||||
#endif /* !INETD_DISABLED */
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 1; i < MAX_NUM_SVC_ARGS; i++) {
|
||||
strlcat(args, svc->args[i], sizeof(args));
|
||||
strlcat(args, " ", sizeof(args));
|
||||
}
|
||||
|
||||
printf("%s %s\n", svc->cmd, args);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usage(int rc)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [OPTIONS] <COMMAND>\n\n"
|
||||
"Options:\n"
|
||||
" -d, --debug Debug initctl (client)\n"
|
||||
" -v, --verbose Verbose output\n"
|
||||
" -h, --help This help text\n\n"
|
||||
"Commands:\n"
|
||||
" debug Toggle Finit (daemon) debug\n"
|
||||
" help This help text\n"
|
||||
" reload Reload *.conf in /etc/finit.d and activate changes\n"
|
||||
" runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot\n"
|
||||
" status | show Show status of services\n"
|
||||
" cond set <COND> Set (assert) condition => +COND\n"
|
||||
" cond clear <COND> Clear (deassert) condition => -COND\n"
|
||||
" cond show Show condition status\n"
|
||||
" start <JOB|NAME>[:ID] Start service by job# or name, with optional ID\n"
|
||||
" stop <JOB|NAME>[:ID] Stop/Pause a running service by job# or name\n"
|
||||
" restart <JOB|NAME>[:ID] Restart (stop/start) service by job# or name\n"
|
||||
" reboot Reboot system\n"
|
||||
" halt Halt system\n"
|
||||
" poweroff Halt and power off system\n"
|
||||
" utmp show Raw dump of UTMP/WTMP db\n"
|
||||
" version Show Finit version\n\n", prognm);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
command_t command[] = {
|
||||
{ "debug", toggle_debug },
|
||||
{ "reload", do_reload },
|
||||
{ "runlevel", do_runlevel },
|
||||
{ "status", show_status },
|
||||
{ "show", show_status }, /* Convenience alias */
|
||||
{ "cond", do_cond },
|
||||
{ "start", do_start },
|
||||
{ "stop", do_stop },
|
||||
{ "restart", do_restart },
|
||||
{ "reboot", do_reboot },
|
||||
{ "halt", do_halt },
|
||||
{ "poweroff", do_poweroff },
|
||||
{ "utmp", do_utmp },
|
||||
{ "version", show_version },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
struct option long_options[] = {
|
||||
{"help", 0, NULL, 'h'},
|
||||
{"debug", 0, NULL, 'd'},
|
||||
{"verbose", 0, NULL, 'v'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
progname(argv[0]);
|
||||
while ((c = getopt_long(argc, argv, "dh?v", long_options, NULL)) != EOF) {
|
||||
switch(c) {
|
||||
case 'h':
|
||||
case '?':
|
||||
return usage(0);
|
||||
|
||||
case 'd':
|
||||
debug = 1;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
silent = !verbose;
|
||||
|
||||
if (optind < argc) {
|
||||
char *cmd = argv[optind++];
|
||||
char arg[120] = "";
|
||||
|
||||
while (optind < argc) {
|
||||
strlcat(arg, argv[optind++], sizeof(arg));
|
||||
strlcat(arg, " ", sizeof(arg));
|
||||
}
|
||||
|
||||
for (c = 0; command[c].cmd; c++) {
|
||||
if (!strcmp(command[c].cmd, cmd))
|
||||
return command[c].cb(arg);
|
||||
}
|
||||
}
|
||||
|
||||
return usage(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,2 @@
|
||||
*.m4
|
||||
!plugin.m4
|
||||
@@ -0,0 +1,17 @@
|
||||
# From https://github.com/kakaroto/e17/blob/master/BINDINGS/javascript/elixir/m4/ac_expand_dir.m4
|
||||
# By Alexandre Oliva <oliva@dcc.unicamp.br>
|
||||
|
||||
# AC_EXPAND_DIR(VARNAME, DIR)
|
||||
# ------------------------------------------------------------
|
||||
# Expands occurrences of ${prefix} and ${exec_prefix} in the
|
||||
# given DIR, and assigns the resulting string to VARNAME
|
||||
#
|
||||
# Example: AC_DEFINE_DIR(DATADIR, "$datadir")
|
||||
AC_DEFUN([AC_EXPAND_DIR], [
|
||||
$1=$2
|
||||
$1=`(
|
||||
test "x$prefix" = xNONE && prefix="$ac_default_prefix"
|
||||
test "x$exec_prefix" = xNONE && exec_prefix="${prefix}"
|
||||
eval echo \""[$]$1"\"
|
||||
)`
|
||||
])
|
||||
@@ -0,0 +1,35 @@
|
||||
# From https://github.com/collectd/collectd/blob/master/configure.ac
|
||||
# Dependency handling currently unused
|
||||
|
||||
define([toupper], [translit([$1], [a-z], [A-Z])])
|
||||
define([sanitize], [translit([$1], [-], [_])])
|
||||
define([enadis], [ifelse([$1], [yes], [disable], [enable])])
|
||||
|
||||
# AC_PLUGIN(name, default, info)
|
||||
# ------------------------------------------------------------
|
||||
AC_DEFUN([AC_PLUGIN],[
|
||||
m4_divert_once([HELP_ENABLE], [
|
||||
Optional Plugins:])
|
||||
enable_plugin="no"
|
||||
define(pluggy, sanitize($1))
|
||||
define(PLUGGY, toupper(pluggy))
|
||||
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"
|
||||
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.])
|
||||
fi
|
||||
AM_CONDITIONAL([BUILD_]PLUGGY[_PLUGIN], test "x$enable_plugin" = "xyes")
|
||||
enable_pluggy="$enable_plugin"])
|
||||
@@ -0,0 +1,72 @@
|
||||
/* Handle MD arrays
|
||||
*
|
||||
* Copyright (c) 2016 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <glob.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
|
||||
static glob_t *get_arrays(void)
|
||||
{
|
||||
static glob_t arrays;
|
||||
|
||||
glob("/sys/block/md*", 0, NULL, &arrays);
|
||||
if (arrays.gl_pathc > 0)
|
||||
return &arrays;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If system has an MD raid, we must tell it to stop before continuing
|
||||
* with the shutdown. Some controller cards, in particular the Intel(R)
|
||||
* Matrix Storage Manager, must be properly notified.
|
||||
*/
|
||||
void mdadm_wait(void)
|
||||
{
|
||||
size_t i;
|
||||
glob_t *gl;
|
||||
char cmd[160];
|
||||
|
||||
/* Setup kernel specific settings, e.g. allow broadcast ping, etc. */
|
||||
gl = get_arrays();
|
||||
if (gl) {
|
||||
for (i = 0; i < gl->gl_pathc; i++) {
|
||||
char *array;
|
||||
|
||||
array = basename(gl->gl_pathv[i]);
|
||||
snprintf(cmd, sizeof(cmd), "mdadm --wait-clean /dev/%s >/dev/null", array);
|
||||
run_interactive(cmd, "Marking MD array %s as clean", array);
|
||||
}
|
||||
globfree(gl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,110 @@
|
||||
/* Mount and unmount helpers
|
||||
*
|
||||
* Copyright (c) 2016 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <mntent.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
/*
|
||||
* SysV init on Debian/Ubuntu skips these protected mount points
|
||||
*
|
||||
* It also skips anything below /proc, /sys and /run for good meausre so
|
||||
* we do the same here. What we want is a list of non-protected tmpfs
|
||||
* and regular filesystems that can be safely unmounted before we do
|
||||
* swapoff, and remount / as read-only, respectively.
|
||||
*/
|
||||
static int is_protected(char *dir)
|
||||
{
|
||||
size_t i;
|
||||
char *protected[] = {
|
||||
"/sys", "/proc",
|
||||
"/.dev", "/dev", "/dev/pts", "/dev/shm", "dev/.static/dev", "/dev/vcs",
|
||||
"/run", "/var/run",
|
||||
"/", NULL
|
||||
};
|
||||
char *any[] = {
|
||||
"/proc/", "/sys/", "/run/", NULL
|
||||
};
|
||||
|
||||
for (i = 0; protected[i]; i++) {
|
||||
if (!strcmp(dir, protected[i]))
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; any[i]; i++) {
|
||||
if (!strncmp(dir, any[i], strlen(any[i])))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mntent *iterator(char *fstab)
|
||||
{
|
||||
static FILE *fp = NULL;
|
||||
static struct mntent *mnt;
|
||||
|
||||
if (!fp && fstab) {
|
||||
fp = setmntent(fstab, "r");
|
||||
if (!fp)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while ((mnt = getmntent(fp))) {
|
||||
if (is_protected(mnt->mnt_dir))
|
||||
continue;
|
||||
|
||||
return mnt;
|
||||
}
|
||||
|
||||
endmntent(fp);
|
||||
fp = NULL;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void unmount_tmpfs(void)
|
||||
{
|
||||
struct mntent *mnt;
|
||||
|
||||
while ((mnt = iterator("/proc/mounts"))) {
|
||||
if (!strcmp("tmpfs", mnt->mnt_fsname))
|
||||
umount(mnt->mnt_dir);
|
||||
}
|
||||
}
|
||||
|
||||
void unmount_regular(void)
|
||||
{
|
||||
struct mntent *mnt;
|
||||
|
||||
while ((mnt = iterator("/proc/mounts"))) {
|
||||
umount(mnt->mnt_dir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,98 @@
|
||||
/* Misc. utility functions and C-library extensions for finit and its plugins
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2015 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
|
||||
/**
|
||||
* pid_alive - Check if a given process ID is running
|
||||
* @pid: Process ID to check for.
|
||||
*
|
||||
* Returns:
|
||||
* %TRUE(1) if pid is alive (/proc/pid exists), otherwise %FALSE(0)
|
||||
*/
|
||||
int pid_alive(pid_t pid)
|
||||
{
|
||||
char name[24]; /* Enough for max pid_t */
|
||||
|
||||
snprintf(name, sizeof(name), "/proc/%d", pid);
|
||||
|
||||
return fexist(name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* pid_get_name - Find name of a process
|
||||
* @pid: PID of process to find.
|
||||
* @name: Pointer to buffer where to return process name, may be %NULL
|
||||
* @len: Length in bytes of @name buffer.
|
||||
*
|
||||
* If @name is %NULL, or @len is zero the function will return
|
||||
* a static string. This may be useful to one-off calls.
|
||||
*
|
||||
* Returns:
|
||||
* %NULL on error, otherwise a va
|
||||
*/
|
||||
char *pid_get_name(pid_t pid, char *name, size_t len)
|
||||
{
|
||||
int ret = 1;
|
||||
FILE *fp;
|
||||
char *pname, path[32];
|
||||
static char line[64];
|
||||
|
||||
snprintf(path, sizeof(path), "/proc/%d/status", pid);
|
||||
fp = fopen(path, "r");
|
||||
if (fp) {
|
||||
if (fgets(line, sizeof (line), fp)) {
|
||||
pname = line + 6; /* Skip first part of line --> "Name:\t" */
|
||||
chomp(pname);
|
||||
if (name)
|
||||
strlcpy(name, pname, len);
|
||||
ret = 0; /* Found it! */
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return NULL;
|
||||
|
||||
if (name)
|
||||
return name;
|
||||
|
||||
return pname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,376 @@
|
||||
/* Plugin based services architecture for finit
|
||||
*
|
||||
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <dlfcn.h> /* dlopen() et al */
|
||||
#include <dirent.h> /* readdir() et al */
|
||||
#include <poll.h>
|
||||
#include <string.h>
|
||||
#include <lite/lite.h>
|
||||
#include <lite/queue.h> /* BSD sys/queue.h API */
|
||||
|
||||
#include "config.h"
|
||||
#include "finit.h"
|
||||
#include "private.h"
|
||||
#include "helpers.h"
|
||||
#include "plugin.h"
|
||||
|
||||
#define is_io_plugin(p) ((p)->io.cb && (p)->io.fd > 0)
|
||||
#define SEARCH_PLUGIN(str) \
|
||||
PLUGIN_ITERATOR(p, tmp) { \
|
||||
if (!strcmp(p->name, str)) \
|
||||
return p; \
|
||||
}
|
||||
|
||||
static char *plugpath = NULL; /* Set by first load. */
|
||||
static TAILQ_HEAD(plugin_head, plugin) plugins = TAILQ_HEAD_INITIALIZER(plugins);
|
||||
|
||||
#ifndef ENABLE_STATIC
|
||||
static void check_plugin_depends(plugin_t *plugin);
|
||||
#endif
|
||||
|
||||
|
||||
static char *trim_ext(char *name)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
if (name) {
|
||||
ptr = strstr(name, ".so");
|
||||
if (!ptr)
|
||||
ptr = strstr(name, ".c");
|
||||
if (ptr)
|
||||
*ptr = 0;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
int plugin_register(plugin_t *plugin)
|
||||
{
|
||||
if (!plugin) {
|
||||
errno = EINVAL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Setup default name if none is provided */
|
||||
if (!plugin->name) {
|
||||
#ifndef ENABLE_STATIC
|
||||
Dl_info info;
|
||||
|
||||
if (dladdr(plugin, &info) && info.dli_fname)
|
||||
plugin->name = basename(info.dli_fname);
|
||||
#endif
|
||||
if (!plugin->name)
|
||||
plugin->name = "unknown";
|
||||
}
|
||||
plugin->name = trim_ext(strdup(plugin->name));
|
||||
|
||||
/* Already registered? */
|
||||
if (plugin_find(plugin->name)) {
|
||||
_d("... %s already loaded", plugin->name);
|
||||
free(plugin->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef ENABLE_STATIC
|
||||
/* Resolve plugin dependencies */
|
||||
check_plugin_depends(plugin);
|
||||
#endif
|
||||
|
||||
TAILQ_INSERT_TAIL(&plugins, plugin, link);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Not called, at the moment plugins cannot be unloaded. */
|
||||
int plugin_unregister(plugin_t *plugin)
|
||||
{
|
||||
#ifndef ENABLE_STATIC
|
||||
TAILQ_REMOVE(&plugins, plugin, link);
|
||||
|
||||
_d("%s exiting ...", plugin->name);
|
||||
free(plugin->name);
|
||||
#else
|
||||
_d("Finit built statically, cannot unload %s ...", plugin->name);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* plugin_find - Find a plugin by name
|
||||
* @name: With or without path, or .so extension
|
||||
*
|
||||
* This function uses an opporunistic search for a suitable plugin and
|
||||
* returns the first match. Albeit with at least some measure of
|
||||
* heuristics.
|
||||
*
|
||||
* First it checks for an exact match. If no match is found and @name
|
||||
* starts with a slash the search ends. Otherwise a new search with the
|
||||
* plugin path prepended to @name is made. Also, if @name does not end
|
||||
* with .so it too is added to @name before searching.
|
||||
*
|
||||
* Returns:
|
||||
* On success the pointer to the matching &plugin_t is returned,
|
||||
* otherwise %NULL is returned.
|
||||
*/
|
||||
plugin_t *plugin_find(char *name)
|
||||
{
|
||||
plugin_t *p, *tmp;
|
||||
|
||||
if (!name) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SEARCH_PLUGIN(name);
|
||||
|
||||
if (plugpath && name[0] != '/') {
|
||||
int noext;
|
||||
char path[CMD_SIZE];
|
||||
|
||||
noext = strcmp(name + strlen(name) - 3, ".so");
|
||||
snprintf(path, sizeof(path), "%s%s%s%s", plugpath,
|
||||
fisslashdir(plugpath) ? "" : "/",
|
||||
name, noext ? ".so" : "");
|
||||
|
||||
SEARCH_PLUGIN(path);
|
||||
}
|
||||
|
||||
errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Private daemon API *******************************************************/
|
||||
|
||||
/* Some hooks are called with a fixed argument, like HOOK_SVC_LOST */
|
||||
void plugin_run_hook(hook_point_t no, void *arg)
|
||||
{
|
||||
plugin_t *p, *tmp;
|
||||
|
||||
PLUGIN_ITERATOR(p, tmp) {
|
||||
if (p->hook[no].cb) {
|
||||
_d("Calling %s hook n:o %d (arg: %p) ...", basename(p->name), no, arg);
|
||||
p->hook[no].cb(arg ? arg : p->hook[no].arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Regular hooks are called with the registered plugin's argument */
|
||||
void plugin_run_hooks(hook_point_t no)
|
||||
{
|
||||
plugin_run_hook(no, NULL);
|
||||
}
|
||||
|
||||
/* Generic libev I/O callback, looks up correct plugin and calls its callback */
|
||||
static void generic_io_cb(uev_t *w, void *arg, int events)
|
||||
{
|
||||
plugin_t *p = (plugin_t *)arg;
|
||||
|
||||
if (is_io_plugin(p) && p->io.fd == w->fd) {
|
||||
/* Stop watcher, callback may close descriptor on us ... */
|
||||
uev_io_stop(w);
|
||||
|
||||
_d("Calling I/O %s from runloop...", basename(p->name));
|
||||
p->io.cb(p->io.arg, w->fd, events);
|
||||
|
||||
/* Update fd, may be changed by plugin callback, e.g., if FIFO */
|
||||
uev_io_set(w, p->io.fd, p->io.flags);
|
||||
}
|
||||
}
|
||||
|
||||
int plugin_io_init(plugin_t *p)
|
||||
{
|
||||
if (!is_io_plugin(p))
|
||||
return 0;
|
||||
|
||||
_d("Initializing plugin %s for I/O", basename(p->name));
|
||||
if (uev_io_init(ctx, &p->watcher, generic_io_cb, p, p->io.fd, p->io.flags)) {
|
||||
_e("Failed setting up I/O plugin %s", basename(p->name));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Setup any I/O callbacks for plugins that use them */
|
||||
static int init_plugins(uev_ctx_t *UNUSED(ctx))
|
||||
{
|
||||
int fail = 0;
|
||||
plugin_t *p, *tmp;
|
||||
|
||||
PLUGIN_ITERATOR(p, tmp) {
|
||||
if (plugin_io_init(p))
|
||||
fail++;
|
||||
}
|
||||
|
||||
return fail;
|
||||
}
|
||||
|
||||
#ifndef ENABLE_STATIC
|
||||
/**
|
||||
* load_one - Load one plugin
|
||||
* @path: Path to finit plugins, usually %PLUGIN_PATH
|
||||
* @name: Name of plugin, optionally ending in ".so"
|
||||
*
|
||||
* Loads a plugin from @path/@name[.so]. Note, if ".so" is missing from
|
||||
* the plugin @name it is added before attempting to load.
|
||||
*
|
||||
* It is up to the plugin itself ot register itself as a "ctor" with the
|
||||
* %PLUGIN_INIT macro so that plugin_register() is called automatically.
|
||||
*
|
||||
* Returns:
|
||||
* POSIX OK(0) on success, non-zero otherwise.
|
||||
*/
|
||||
static int load_one(char *path, char *name)
|
||||
{
|
||||
int noext;
|
||||
char sofile[CMD_SIZE];
|
||||
void *handle;
|
||||
plugin_t *plugin;
|
||||
|
||||
if (!path || !fisdir(path) || !name) {
|
||||
errno = EINVAL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Compose full path, with optional .so extension, to plugin */
|
||||
noext = strcmp(name + strlen(name) - 3, ".so");
|
||||
snprintf(sofile, sizeof(sofile), "%s/%s%s", path, name, noext ? ".so" : "");
|
||||
|
||||
_d("Loading plugin %s ...", basename(sofile));
|
||||
handle = dlopen(sofile, RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!handle) {
|
||||
_e("Failed loading plugin %s: %s", sofile, dlerror());
|
||||
return 1;
|
||||
}
|
||||
|
||||
plugin = TAILQ_LAST(&plugins, plugin_head);
|
||||
if (!plugin) {
|
||||
_e("Plugin %s failed to register, unloading from memory", sofile);
|
||||
dlclose(handle);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Remember handle from dlopen() for plugin_unregister() */
|
||||
plugin->handle = handle;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* check_plugin_depends - Check and load any plugins this one depends on.
|
||||
* @plugin: Plugin with possible depends to check
|
||||
*
|
||||
* Very simple dependency resolver, should actually load the plugin of
|
||||
* the correct .name, but currently loads a matching filename.
|
||||
*
|
||||
* Works, but only for now. A better way might be to have a try_load()
|
||||
* that actually loads all plugins and checks their &plugin_t for the
|
||||
* correct .name.
|
||||
*/
|
||||
static void check_plugin_depends(plugin_t *plugin)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < PLUGIN_DEP_MAX && plugin->depends[i]; i++) {
|
||||
// _d("Plugin %s depends on %s ...", plugin->name, plugin->depends[i]);
|
||||
if (plugin_find(plugin->depends[i])) {
|
||||
// _d("OK plugin %s was already loaded.", plugin->depends[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
load_one(plugpath, plugin->depends[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static int load_plugins(char *path)
|
||||
{
|
||||
int fail = 0;
|
||||
DIR *dp;
|
||||
struct dirent *entry;
|
||||
|
||||
if (!silent)
|
||||
print_desc("Loading plugins", NULL);
|
||||
|
||||
dp = opendir(path);
|
||||
if (!dp) {
|
||||
_e("Failed, cannot open plugin directory %s: %s", path, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
plugpath = path;
|
||||
|
||||
while ((entry = readdir(dp))) {
|
||||
if (entry->d_name[0] == '.')
|
||||
continue; /* Skip . and .. directories */
|
||||
|
||||
if (load_one(path, entry->d_name))
|
||||
fail++;
|
||||
}
|
||||
|
||||
closedir(dp);
|
||||
|
||||
return fail;
|
||||
}
|
||||
#else
|
||||
static int load_plugins(char *UNUSED(path))
|
||||
{
|
||||
if (!silent)
|
||||
print_desc("Initializing plugins", NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* ENABLE_STATIC */
|
||||
|
||||
int plugin_init(uev_ctx_t *ctx, char *path)
|
||||
{
|
||||
int fail = 1;
|
||||
|
||||
if (!load_plugins(path))
|
||||
fail = init_plugins(ctx);
|
||||
|
||||
if (!silent)
|
||||
print_result(fail);
|
||||
|
||||
return fail;
|
||||
}
|
||||
|
||||
void plugin_exit(void)
|
||||
{
|
||||
#ifndef ENABLE_STATIC
|
||||
plugin_t *p, *tmp;
|
||||
|
||||
PLUGIN_ITERATOR(p, tmp) {
|
||||
if (dlclose(p->handle))
|
||||
_e("Failed: unloading plugin %s: %s", p->name, dlerror());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,145 @@
|
||||
/* Plugin based services architecture for finit
|
||||
*
|
||||
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef FINIT_PLUGIN_H_
|
||||
#define FINIT_PLUGIN_H_
|
||||
|
||||
#include <uev/uev.h>
|
||||
#include <lite/queue.h> /* BSD sys/queue.h API */
|
||||
|
||||
#include "svc.h"
|
||||
|
||||
#ifndef PLUGIN_PATH /* Fallback for --enable-static builds */
|
||||
#define PLUGIN_PATH "/dev/null"
|
||||
#endif
|
||||
|
||||
#define PLUGIN_DEP_MAX 10
|
||||
#define PLUGIN_IO_READ UEV_READ
|
||||
#define PLUGIN_IO_WRITE UEV_WRITE
|
||||
|
||||
#define PLUGIN_INIT(x) static void __attribute__ ((constructor)) x(void)
|
||||
#define PLUGIN_EXIT(x) static void __attribute__ ((destructor)) x(void)
|
||||
|
||||
#define PLUGIN_ITERATOR(x, tmp) TAILQ_FOREACH_SAFE(x, &plugins, link, tmp)
|
||||
|
||||
/*
|
||||
* Predefined hook points for easier plugin debugging
|
||||
*/
|
||||
typedef enum {
|
||||
/* Bootstrap hooks */
|
||||
HOOK_ROOTFS_UP = 0,
|
||||
HOOK_MOUNT_ERROR,
|
||||
HOOK_BASEFS_UP,
|
||||
HOOK_NETWORK_UP,
|
||||
HOOK_SVC_UP,
|
||||
HOOK_SYSTEM_UP,
|
||||
|
||||
/* Runtime hooks */
|
||||
HOOK_SVC_RECONF,
|
||||
HOOK_SVC_LOST,
|
||||
HOOK_SVC_START,
|
||||
HOOK_RUNLEVEL_CHANGE,
|
||||
|
||||
/* Shutdown hooks */
|
||||
HOOK_SHUTDOWN,
|
||||
HOOK_MAX_NUM
|
||||
} hook_point_t;
|
||||
|
||||
/**
|
||||
* plugin_t - Finit &plugin_t object
|
||||
* @link: BSD sys/queue.h linked list node
|
||||
* @name: Plugin name, or identifier to match against a &svc_t object
|
||||
* @svc: Service callback for a loaded &svc_t object
|
||||
* @hook: Hook callback definitions
|
||||
* @io: I/O hook callback
|
||||
*
|
||||
* To setup an &svc_t object callback for a service monitor the @name
|
||||
* must match the @svc_t @cmd exactly for them to "pair".
|
||||
*
|
||||
* A &plugin_t object may contain a service callback, several hooks
|
||||
* and/or an I/O callback as well. This way all critical extensions
|
||||
* to finit can fit in one single plugin, if needed.
|
||||
*
|
||||
* The "dynamic events" discussed in the svc callback is for external
|
||||
* service plugins to implement. However, it can be anything that
|
||||
* can cause a service to need to SIGHUP at runtime. E.g., acquiring
|
||||
* a DHCP lease, or an interface going UP/DOWN. The event itself can
|
||||
* be passed as an integer @event and any optional argument @event_arg
|
||||
*
|
||||
* It is up to the external service plugin to track these events and
|
||||
* relay them to each @dynamic service plugins' callback. I.e., to
|
||||
* all those with the dynamic flag set.
|
||||
*/
|
||||
typedef struct plugin {
|
||||
/* BSD sys/queue.h linked list node. */
|
||||
TAILQ_ENTRY(plugin) link;
|
||||
|
||||
/* Handle to be sent to dlclose() when plugins is unloaded. */
|
||||
void *handle;
|
||||
|
||||
/* Event loop handler, used internally by Finit */
|
||||
uev_t watcher;
|
||||
|
||||
/* Plugin name, defaults to basename of plugin path if unset.
|
||||
* NOTE: Must match cmd for services or inetd plugins! */
|
||||
char *name;
|
||||
|
||||
/* List of hook callbacks. */
|
||||
struct {
|
||||
void *arg; /* Optional argument to callback func. */
|
||||
void (*cb)(void *arg);
|
||||
} hook[HOOK_MAX_NUM];
|
||||
|
||||
/* I/O Plugin */
|
||||
struct {
|
||||
int fd, flags; /* 1:READ, 2:WRITE */
|
||||
void *arg;
|
||||
void (*cb)(void *arg, int fd, int events);
|
||||
} io;
|
||||
|
||||
/* Inetd Plugin, stdio used as client socket.
|
||||
* @type argument will be either SOCK_DGRAM or SOCK_STREAM */
|
||||
struct {
|
||||
int (*cmd)(int type);
|
||||
} inetd;
|
||||
|
||||
char *depends[PLUGIN_DEP_MAX]; /* List of other .name's this depends on. */
|
||||
} plugin_t;
|
||||
|
||||
/* Public plugin API */
|
||||
int plugin_io_init (plugin_t *plugin);
|
||||
|
||||
int plugin_register (plugin_t *plugin);
|
||||
int plugin_unregister (plugin_t *plugin);
|
||||
|
||||
/* Helper API */
|
||||
plugin_t *plugin_find (char *name);
|
||||
|
||||
#endif /* FINIT_PLUGIN_H_ */
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,4 @@
|
||||
/*.la
|
||||
/*.lo
|
||||
/.deps/*
|
||||
/.libs/*
|
||||
@@ -0,0 +1,108 @@
|
||||
AM_LDFLAGS = -module -avoid-version -shared
|
||||
AM_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||
AM_CPPFLAGS = -U_FORTIFY_SOURCE
|
||||
AM_CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
|
||||
AM_CPPFLAGS += $(lite_CFLAGS)
|
||||
|
||||
if STATIC
|
||||
noinst_LTLIBRARIES = libplug.la
|
||||
libplug_la_SOURCES = bootmisc.c hwclock.c initctl.c pidfile.c procps.c tty.c urandom.c
|
||||
|
||||
if BUILD_ALSA_UTILS_PLUGIN
|
||||
libplug_la_SOURCES += alsa-utils.c
|
||||
endif
|
||||
|
||||
if BUILD_DBUS_PLUGIN
|
||||
libplug_la_SOURCES += dbus.c
|
||||
endif
|
||||
|
||||
if INETD
|
||||
if BUILD_INETD_ECHO_PLUGIN
|
||||
libplug_la_SOURCES += echo.c
|
||||
endif
|
||||
|
||||
if BUILD_INETD_CHARGEN_PLUGIN
|
||||
libplug_la_SOURCES += chargen.c
|
||||
endif
|
||||
|
||||
if BUILD_INETD_DAYTIME_PLUGIN
|
||||
libplug_la_SOURCES += daytime.c
|
||||
endif
|
||||
|
||||
if BUILD_INETD_DISCARD_PLUGIN
|
||||
libplug_la_SOURCES += discard.c
|
||||
endif
|
||||
|
||||
if BUILD_INETD_TIME_PLUGIN
|
||||
libplug_la_SOURCES += time.c
|
||||
endif
|
||||
endif
|
||||
|
||||
if BUILD_LOST_PLUGIN
|
||||
libplug_la_SOURCES += lost.c
|
||||
endif
|
||||
|
||||
if BUILD_NETLINK_PLUGIN
|
||||
libplug_la_SOURCES += netlink.c
|
||||
endif
|
||||
|
||||
if BUILD_RESOLVCONF_PLUGIN
|
||||
libplug_la_SOURCES += resolvconf.c
|
||||
endif
|
||||
|
||||
else
|
||||
pkglib_LTLIBRARIES = bootmisc.la hwclock.la initctl.la pidfile.la procps.la tty.la urandom.la
|
||||
|
||||
if BUILD_ALSA_UTILS_PLUGIN
|
||||
pkglib_LTLIBRARIES += alsa-utils.la
|
||||
endif
|
||||
|
||||
if BUILD_DBUS_PLUGIN
|
||||
pkglib_LTLIBRARIES += dbus.la
|
||||
endif
|
||||
|
||||
if INETD
|
||||
if BUILD_INETD_ECHO_PLUGIN
|
||||
pkglib_LTLIBRARIES += echo.la
|
||||
endif
|
||||
|
||||
if BUILD_INETD_CHARGEN_PLUGIN
|
||||
pkglib_LTLIBRARIES += chargen.la
|
||||
endif
|
||||
|
||||
if BUILD_INETD_DAYTIME_PLUGIN
|
||||
pkglib_LTLIBRARIES += daytime.la
|
||||
endif
|
||||
|
||||
if BUILD_INETD_DISCARD_PLUGIN
|
||||
pkglib_LTLIBRARIES += discard.la
|
||||
endif
|
||||
|
||||
if BUILD_INETD_TIME_PLUGIN
|
||||
pkglib_LTLIBRARIES += time.la
|
||||
endif
|
||||
endif
|
||||
|
||||
if BUILD_LOST_PLUGIN
|
||||
pkglib_LTLIBRARIES += lost.la
|
||||
endif
|
||||
|
||||
if BUILD_NETLINK_PLUGIN
|
||||
pkglib_LTLIBRARIES += netlink.la
|
||||
endif
|
||||
|
||||
if BUILD_RESOLVCONF_PLUGIN
|
||||
pkglib_LTLIBRARIES += resolvconf.la
|
||||
endif
|
||||
|
||||
if BUILD_X11_COMMON_PLUGIN
|
||||
pkglib_LTLIBRARIES += x11-common.la
|
||||
endif
|
||||
|
||||
# Clean up .la files installed by libtool despite being in -module mode
|
||||
install-exec-hook:
|
||||
@(cd $(DESTDIR)$(pkglibdir) && $(RM) $(pkglib_LTLIBRARIES))
|
||||
|
||||
uninstall-hook:
|
||||
@(cd $(DESTDIR)$(pkglibdir) && for file in $(pkglib_LTLIBRARIES); do $(RM) `basename $$file .la`.so; done)
|
||||
endif
|
||||
@@ -0,0 +1,69 @@
|
||||
/* Save and restore ALSA sound settings using alsactl
|
||||
*
|
||||
* Copyright (c) 2012-2016 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <lite/lite.h>
|
||||
#include "../finit.h"
|
||||
#include "../helpers.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
#define ALSACTL "/usr/sbin/alsactl"
|
||||
|
||||
static void save(void *UNUSED(arg))
|
||||
{
|
||||
if (fexist(ALSACTL)) {
|
||||
_d("Saving sound settings ...");
|
||||
run_interactive(ALSACTL " -g store", "Saving sound settings");
|
||||
}
|
||||
}
|
||||
|
||||
static void restore(void *UNUSED(arg))
|
||||
{
|
||||
if (fexist(ALSACTL)) {
|
||||
_d("Restoring sound settings ...");
|
||||
run_interactive(ALSACTL " -g restore", "Restoring sound settings");
|
||||
}
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_BASEFS_UP] = { .cb = restore },
|
||||
.hook[HOOK_SHUTDOWN] = { .cb = save }
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,199 @@
|
||||
/* Setup necessary system files for, e.g. UTMP (tracking logins)
|
||||
*
|
||||
* Copyright (c) 2012-2016 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <ftw.h>
|
||||
#include <mntent.h>
|
||||
#include <string.h>
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "../config.h"
|
||||
#include "../finit.h"
|
||||
#include "../helpers.h"
|
||||
#include "../plugin.h"
|
||||
#include "../utmp-api.h"
|
||||
|
||||
static int is_tmpfs(char *path)
|
||||
{
|
||||
int tmpfs = 0;
|
||||
FILE *fp;
|
||||
char *dir;
|
||||
struct mntent *mnt;
|
||||
|
||||
/* If path is a symlink, check what it resolves to */
|
||||
dir = realpath(path, NULL);
|
||||
if (!dir)
|
||||
return 0; /* Outlook not so good */
|
||||
|
||||
fp = setmntent("/proc/mounts", "r");
|
||||
if (!fp) {
|
||||
free(dir);
|
||||
return 0; /* Dunno, maybe not */
|
||||
}
|
||||
|
||||
while ((mnt = getmntent(fp))) {
|
||||
if (!strcmp(dir, mnt->mnt_dir))
|
||||
break;
|
||||
}
|
||||
|
||||
if (mnt && !strcmp("tmpfs", mnt->mnt_type))
|
||||
tmpfs = 1;
|
||||
|
||||
endmntent(fp);
|
||||
free(dir);
|
||||
|
||||
return tmpfs;
|
||||
}
|
||||
|
||||
static void create(char *path, mode_t mode, uid_t uid, gid_t gid)
|
||||
{
|
||||
if (touch(path) || chmod(path, mode) || chown(path, uid, gid))
|
||||
_w("Failed creating %s properl.", path);
|
||||
}
|
||||
|
||||
static int do_clean(const char *fpath, const struct stat *UNUSED(sb), int UNUSED(tflag), struct FTW *ftwbuf)
|
||||
{
|
||||
if (ftwbuf->level == 0)
|
||||
return 1;
|
||||
|
||||
_d("Removing %s ...", fpath);
|
||||
(void)remove(fpath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We can safely skip tmpfs, nothing to clean from previous boot there */
|
||||
static void bootclean(void)
|
||||
{
|
||||
char *dir[] = {
|
||||
"/tmp/",
|
||||
"/var/run/",
|
||||
"/var/lock/",
|
||||
NULL
|
||||
};
|
||||
|
||||
for (int i = 0; dir[i]; i++) {
|
||||
if (is_tmpfs(dir[i]))
|
||||
continue;
|
||||
|
||||
nftw(dir[i], do_clean, 20, FTW_DEPTH);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup standard FHS 2.3 structure in /var, and write runlevel to UTMP
|
||||
*/
|
||||
static void setup(void *UNUSED(arg))
|
||||
{
|
||||
int gid;
|
||||
|
||||
/* Cleanup stale files, if any still linger on. */
|
||||
bootclean();
|
||||
|
||||
_d("Setting up FHS structure in /var ...");
|
||||
umask(0);
|
||||
makedir("/var/cache", 0755);
|
||||
makedir("/var/games", 0755);
|
||||
makedir("/var/lib", 0755);
|
||||
makedir("/var/lib/misc", 0755);
|
||||
makedir("/var/lib/alarm", 0755);
|
||||
makedir("/var/lib/urandom",0755);
|
||||
if (fisdir("/run")) {
|
||||
_d("System with new /run tmpfs ...");
|
||||
makedir("/run/lock", 1777);
|
||||
symlink("/run/lock", "/var/lock");
|
||||
symlink("/run", "/var/run");
|
||||
symlink("/dev/shm", "/run/shm");
|
||||
} 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);
|
||||
|
||||
/*
|
||||
* If /etc/group or "utmp" group is missing,
|
||||
* default to "root"/"wheel" group
|
||||
*/
|
||||
_d("Setting up necessary UTMP files ...");
|
||||
gid = getgroup("utmp");
|
||||
if (gid < 0)
|
||||
gid = 0;
|
||||
|
||||
/*
|
||||
* UTMP actually needs multiple db files
|
||||
*/
|
||||
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 */
|
||||
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 */
|
||||
makedir("/var/run/quagga", 0755); /* Needed by Quagga */
|
||||
makedir("/var/log/quagga", 0755); /* Needed by Quagga */
|
||||
makedir("/var/run/sshd", 01755); /* OpenSSH */
|
||||
makefifo("/dev/xconsole", 0640); /* sysklogd */
|
||||
chown("/dev/xconsole", 0, getgroup("tty"));
|
||||
|
||||
umask(022);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_BASEFS_UP] = {
|
||||
.cb = setup
|
||||
},
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,120 @@
|
||||
/* Optional inetd plugin for the Character Generator Protocol, RFC 864
|
||||
*
|
||||
* Copyright (c) 2016 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h> /* STDIN_FILENO */
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
#define NAME "chargen"
|
||||
#define PATTERN "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ "
|
||||
|
||||
static char *generator(char *buf, size_t buflen)
|
||||
{
|
||||
size_t num, len, width = 72;
|
||||
static size_t pos = 0;
|
||||
const char pattern[] = PATTERN;
|
||||
|
||||
if (buflen < width)
|
||||
width = buflen;
|
||||
|
||||
len = width;
|
||||
if (len + 3 > buflen)
|
||||
len = buflen - 3;
|
||||
if (pos + len > sizeof(pattern)) {
|
||||
num = sizeof(pattern) - pos;
|
||||
len -= num;
|
||||
} else {
|
||||
num = width;
|
||||
if (num + 3 > buflen)
|
||||
num = buflen - 3;
|
||||
len = 0;
|
||||
}
|
||||
|
||||
strncpy(buf, &pattern[pos], num--);
|
||||
if (len++)
|
||||
strncpy(&buf[num], pattern, len);
|
||||
strlcat(buf, "\r\n", width);
|
||||
|
||||
if (++pos >= sizeof(pattern) - 1)
|
||||
pos = 0;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int recv_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, socklen_t *sa_len)
|
||||
{
|
||||
len = recvfrom(sd, buf, len, MSG_DONTWAIT, sa, sa_len);
|
||||
if (-1 == len)
|
||||
return -1; /* On error, close connection. */
|
||||
|
||||
if (inetd_check_loop(sa, *sa_len, NAME))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, socklen_t sa_len)
|
||||
{
|
||||
char *pattern = generator(buf, len);
|
||||
|
||||
return sendto(sd, pattern, strlen(pattern), MSG_DONTWAIT, sa, sa_len);
|
||||
}
|
||||
|
||||
static int cb(int UNUSED(type))
|
||||
{
|
||||
int sd = STDIN_FILENO;
|
||||
char buf[BUFSIZ];
|
||||
struct sockaddr_storage sa;
|
||||
socklen_t sa_len = sizeof(sa);
|
||||
|
||||
if (recv_peer(sd, buf, sizeof(buf), (struct sockaddr *)&sa, &sa_len))
|
||||
return -1;
|
||||
|
||||
return send_peer(sd, buf, sizeof(buf), (struct sockaddr *)&sa, sa_len);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = NAME, /* Must match the inetd /etc/services entry */
|
||||
.inetd = {
|
||||
.cmd = cb
|
||||
},
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,102 @@
|
||||
/* Optional inetd plugin for Daytime Protocol, RFC 867
|
||||
*
|
||||
* Copyright (c) 2016 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h> /* STDIN_FILENO */
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
#define NAME "daytime"
|
||||
|
||||
|
||||
static char *daytime(char *buf, size_t len)
|
||||
{
|
||||
time_t t;
|
||||
struct tm *tmp;
|
||||
|
||||
t = time(NULL);
|
||||
tmp = localtime(&t);
|
||||
|
||||
memset(buf, 0, len);
|
||||
strftime(buf, len, "%a, %B %d, %Y %T-%Z", tmp);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int recv_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, socklen_t *sa_len)
|
||||
{
|
||||
len = recvfrom(sd, buf, sizeof(buf), MSG_DONTWAIT, sa, sa_len);
|
||||
if (-1 == len)
|
||||
return -1; /* On error, close connection. */
|
||||
|
||||
if (inetd_check_loop(sa, *sa_len, NAME))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, socklen_t sa_len)
|
||||
{
|
||||
char *now = daytime(buf, len);
|
||||
|
||||
return sendto(sd, now, strlen(now), MSG_DONTWAIT, sa, sa_len);
|
||||
}
|
||||
|
||||
static int cb(int UNUSED(type))
|
||||
{
|
||||
int sd = STDIN_FILENO;
|
||||
char buf[BUFSIZ];
|
||||
struct sockaddr_storage sa;
|
||||
socklen_t sa_len = sizeof(sa);
|
||||
|
||||
if (recv_peer(sd, buf, sizeof(buf), (struct sockaddr *)&sa, &sa_len))
|
||||
return -1;
|
||||
|
||||
return send_peer(sd, buf, sizeof(buf), (struct sockaddr *)&sa, sa_len);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = NAME, /* Must match the inetd /etc/services entry */
|
||||
.inetd = {
|
||||
.cmd = cb
|
||||
}
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,70 @@
|
||||
/* Setup and start system message bus, D-Bus
|
||||
*
|
||||
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "../finit.h"
|
||||
#include "../config.h"
|
||||
#include "../helpers.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
static void setup(void *UNUSED(arg))
|
||||
{
|
||||
umask(0);
|
||||
|
||||
_d("Starting D-Bus ...");
|
||||
makedir("/var/run/dbus", 0755);
|
||||
makedir("/var/lock/subsys", 0755);
|
||||
makedir("/var/lock/subsys/messagebus", 0755);
|
||||
run("dbus-uuidgen --ensure");
|
||||
erase("/var/run/dbus/pid");
|
||||
run_interactive("dbus-daemon --system", "Starting D-Bus");
|
||||
|
||||
umask(022);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_NETWORK_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:
|
||||
*/
|
||||
@@ -0,0 +1,67 @@
|
||||
/* Optional inetd plugin for the Discard Protocol, RFC 863
|
||||
*
|
||||
* Copyright (c) 2016 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h> /* STDIN_FILENO */
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
static int cb(int UNUSED(type))
|
||||
{
|
||||
int sd = STDIN_FILENO;
|
||||
char buf[BUFSIZ];
|
||||
ssize_t len;
|
||||
struct sockaddr_storage sa;
|
||||
socklen_t sa_len = sizeof(sa);
|
||||
|
||||
len = recvfrom(sd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr *)&sa, &sa_len);
|
||||
if (-1 == len)
|
||||
return -1; /* On error, close connection. */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = "discard", /* Must match the inetd /etc/services entry */
|
||||
.inetd = {
|
||||
.cmd = cb
|
||||
},
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,81 @@
|
||||
/* Optional inetd plugin for the Echo Protocol, RFC 862
|
||||
*
|
||||
* Copyright (c) 2016 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h> /* STDIN_FILENO */
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
#define NAME "echo"
|
||||
|
||||
static int recv_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, socklen_t *sa_len)
|
||||
{
|
||||
len = recvfrom(sd, buf, sizeof(buf), MSG_DONTWAIT, sa, sa_len);
|
||||
if (-1 == len)
|
||||
return -1; /* On error, close connection. */
|
||||
|
||||
if (inetd_check_loop(sa, *sa_len, NAME))
|
||||
return -1;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int cb(int UNUSED(type))
|
||||
{
|
||||
int sd = STDIN_FILENO;
|
||||
char buf[BUFSIZ];
|
||||
ssize_t len;
|
||||
struct sockaddr_storage sa;
|
||||
socklen_t sa_len = sizeof(sa);
|
||||
|
||||
len = recv_peer(sd, buf, sizeof(buf), (struct sockaddr *)&sa, &sa_len);
|
||||
if (-1 == len)
|
||||
return -1; /* On error, close connection. */
|
||||
|
||||
return sendto(sd, buf, len, MSG_DONTWAIT, (struct sockaddr *)&sa, sa_len);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = NAME, /* Must match the inetd /etc/services entry */
|
||||
.inetd = {
|
||||
.cmd = cb
|
||||
},
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,69 @@
|
||||
/* Save and restore RTC using hwclock
|
||||
*
|
||||
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "../finit.h"
|
||||
#include "../helpers.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
static void save(void *UNUSED(arg))
|
||||
{
|
||||
_d("Saving system clock to RTC ...");
|
||||
/* -w,--systohc, -u,--utc */
|
||||
run_interactive("/sbin/hwclock -w -u", "Saving system time (UTC) to RTC");
|
||||
}
|
||||
|
||||
static void restore(void *UNUSED(arg))
|
||||
{
|
||||
_d("Restoring system clock from RTC ...");
|
||||
/* -s,--hctosys, -u,--utc */
|
||||
run_interactive("/sbin/hwclock -s -u", "Restoring system clock (UTC) from RTC");
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_BASEFS_UP] = {
|
||||
.cb = restore
|
||||
},
|
||||
.hook[HOOK_SHUTDOWN] = {
|
||||
.cb = save
|
||||
}
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,194 @@
|
||||
/* Optional /dev/initctl FIFO monitor, for receiving commands from telinit
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2015 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "../config.h" /* Generated by configure script */
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h> /* O_RDONLY et al */
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h> /* read() */
|
||||
#include <sys/stat.h>
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "../finit.h"
|
||||
#include "../conf.h"
|
||||
#include "../helpers.h"
|
||||
#include "../plugin.h"
|
||||
#include "../sig.h"
|
||||
#include "../service.h"
|
||||
|
||||
static void parse(void *arg, int fd, int events);
|
||||
static void setup(void *arg);
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.io = {
|
||||
.cb = parse,
|
||||
.flags = PLUGIN_IO_READ,
|
||||
},
|
||||
.hook[HOOK_BASEFS_UP] = {
|
||||
.cb = setup
|
||||
},
|
||||
.depends = { "bootmisc", },
|
||||
};
|
||||
|
||||
static void fifo_open(void)
|
||||
{
|
||||
plugin.io.fd = open(FINIT_FIFO, O_RDWR | O_NONBLOCK | O_CLOEXEC);
|
||||
if (-1 == plugin.io.fd) {
|
||||
_e("Failed opening %s FIFO, error %d: %s", FINIT_FIFO, errno, strerror(errno));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We only handle INIT_HALT for differentiating between halt/poweroff
|
||||
*/
|
||||
static void set_env(char *data)
|
||||
{
|
||||
const char *var = "INIT_HALT";
|
||||
|
||||
if (strncmp(data, var, strlen(var)))
|
||||
return;
|
||||
data += strlen(var);
|
||||
|
||||
/*
|
||||
* No value means unset env, in this case cancel shutdown.
|
||||
*/
|
||||
if (data[0] == 0) {
|
||||
halt = SHUT_DEFAULT;
|
||||
/* XXX: Cancel timer here, when we get support for timed shutdown */
|
||||
return;
|
||||
}
|
||||
|
||||
if (string_match(data, "=POWERDOWN"))
|
||||
halt = SHUT_OFF;
|
||||
if (string_match(data, "=HALT"))
|
||||
halt = SHUT_HALT;
|
||||
|
||||
/* Now we wait for runlevel change, or cancelled shutdown */
|
||||
}
|
||||
|
||||
/*
|
||||
* Standard reboot/shutdown utilities talk to init using /run/initctl.
|
||||
* We should check if the fifo was recreated and reopen it.
|
||||
*
|
||||
* For SysV compatibility the default is to halt the system when issuing
|
||||
* `init 0`, unless INIT_HALT=POWERDOWN, as performed by the SysV utils.
|
||||
*/
|
||||
static void parse(void *UNUSED(arg), int fd, int UNUSED(events))
|
||||
{
|
||||
int lvl;
|
||||
struct init_request rq;
|
||||
|
||||
while (1) {
|
||||
ssize_t len = read(fd, &rq, sizeof(rq));
|
||||
|
||||
if (len <= 0) {
|
||||
if (-1 == len) {
|
||||
if (EINTR == errno)
|
||||
continue;
|
||||
|
||||
if (EAGAIN == errno)
|
||||
break;
|
||||
|
||||
_e("Failed reading initctl request, error %d: %s", errno, strerror(errno));
|
||||
}
|
||||
|
||||
_d("Nothing to do, bailing out.");
|
||||
break;
|
||||
}
|
||||
|
||||
if (rq.magic != INIT_MAGIC || len != sizeof(rq)) {
|
||||
_e("Invalid initctl request.");
|
||||
break;
|
||||
}
|
||||
|
||||
switch (rq.cmd) {
|
||||
case INIT_CMD_RUNLVL:
|
||||
switch (rq.runlevel) {
|
||||
case 's':
|
||||
case 'S':
|
||||
rq.runlevel = '1';
|
||||
/* Fall through to regular processing */
|
||||
|
||||
case '0'...'9':
|
||||
_d("Setting new runlevel %c", rq.runlevel);
|
||||
lvl = rq.runlevel - '0';
|
||||
if (lvl == 6)
|
||||
halt = SHUT_REBOOT;
|
||||
service_runlevel(lvl);
|
||||
break;
|
||||
|
||||
default:
|
||||
_d("Unsupported runlevel: %d", rq.runlevel);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case INIT_CMD_RELOAD:
|
||||
service_reload_dynamic();
|
||||
break;
|
||||
|
||||
case INIT_CMD_SETENV:
|
||||
set_env(rq.data);
|
||||
break;
|
||||
|
||||
default:
|
||||
_d("Unsupported cmd: %d", rq.cmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
fifo_open();
|
||||
}
|
||||
|
||||
/* Must run after the base FS is up, needs /run, or /var/run */
|
||||
static void setup(void *UNUSED(arg))
|
||||
{
|
||||
_d("Setting up %s", FINIT_FIFO);
|
||||
makefifo(FINIT_FIFO, 0600);
|
||||
|
||||
fifo_open();
|
||||
plugin_io_init(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,60 @@
|
||||
/* Example HOOK_SVC_LOST plugin, very noisy do not use as-is!
|
||||
*
|
||||
* Copyright (c) 2016 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "../finit.h"
|
||||
#include "../svc.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
static void lost_pid(void *arg)
|
||||
{
|
||||
pid_t pid = (uintptr_t)arg;
|
||||
svc_t *svc;
|
||||
|
||||
svc = svc_find_by_pid(pid);
|
||||
if (!svc)
|
||||
return;
|
||||
|
||||
logit(LOG_INFO, "Lost PID %u, svc %s", pid, svc->cmd);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_SVC_LOST] = { .cb = lost_pid },
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,233 @@
|
||||
/* Netlink plugin for IFUP/IFDN and GW events
|
||||
*
|
||||
* Copyright (C) 2009-2011 Mårten Wikström <marten.wikstrom@keystream.se>
|
||||
* Copyright (C) 2009-2015 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <net/if.h> /* IFNAMSIZ */
|
||||
#include <sys/socket.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../finit.h"
|
||||
#include "../cond.h"
|
||||
#include "../helpers.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
static int nlmsg_validate(struct nlmsghdr *nh, size_t len)
|
||||
{
|
||||
if (!NLMSG_OK(nh, len))
|
||||
return 1;
|
||||
|
||||
if (nh->nlmsg_type == NLMSG_DONE) {
|
||||
_d("Done with netlink messages.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (nh->nlmsg_type == NLMSG_ERROR) {
|
||||
_d("Netlink reports error.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nl_route(struct nlmsghdr *nlmsg)
|
||||
{
|
||||
struct rtmsg *r;
|
||||
struct rtattr *a;
|
||||
int la;
|
||||
int gw = 0, dst = 0, mask = 0, idx = 0;
|
||||
|
||||
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg))) {
|
||||
_e("Packet too small or truncated!");
|
||||
return;
|
||||
}
|
||||
|
||||
r = NLMSG_DATA(nlmsg);
|
||||
a = RTM_RTA(r);
|
||||
la = RTM_PAYLOAD(nlmsg);
|
||||
while (RTA_OK(a, la)) {
|
||||
void *data = RTA_DATA(a);
|
||||
switch (a->rta_type) {
|
||||
case RTA_GATEWAY:
|
||||
gw = *((int *)data);
|
||||
//_d("GW: 0x%04x", gw);
|
||||
break;
|
||||
|
||||
case RTA_DST:
|
||||
dst = *((int *)data);
|
||||
mask = r->rtm_dst_len;
|
||||
//_d("MASK: 0x%04x", mask);
|
||||
break;
|
||||
|
||||
case RTA_OIF:
|
||||
idx = *((int *)data);
|
||||
//_d("IDX: 0x%04x", idx);
|
||||
break;
|
||||
}
|
||||
|
||||
a = RTA_NEXT(a, la);
|
||||
}
|
||||
|
||||
if ((!dst && !mask) && (gw || idx)) {
|
||||
if (nlmsg->nlmsg_type == RTM_DELROUTE)
|
||||
cond_clear("net/route/default");
|
||||
else
|
||||
cond_set("net/route/default");
|
||||
}
|
||||
}
|
||||
|
||||
static void nl_link(struct nlmsghdr *nlmsg)
|
||||
{
|
||||
int la;
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
struct rtattr *a;
|
||||
struct ifinfomsg *i;
|
||||
|
||||
if (nlmsg->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) {
|
||||
_e("Packet too small or truncated!");
|
||||
return;
|
||||
}
|
||||
|
||||
i = NLMSG_DATA(nlmsg);
|
||||
a = (struct rtattr *)((char *)i + NLMSG_ALIGN(sizeof(struct ifinfomsg)));
|
||||
la = NLMSG_PAYLOAD(nlmsg, sizeof(struct ifinfomsg));
|
||||
|
||||
while (RTA_OK(a, la)) {
|
||||
if (a->rta_type == IFLA_IFNAME) {
|
||||
char msg[MAX_ARG_LEN];
|
||||
|
||||
strlcpy(ifname, RTA_DATA(a), sizeof(ifname));
|
||||
switch (nlmsg->nlmsg_type) {
|
||||
case RTM_NEWLINK:
|
||||
/*
|
||||
* New interface has appearad, or interface flags has changed.
|
||||
* Check ifi_flags here to see if the interface is UP/DOWN
|
||||
*/
|
||||
if (i->ifi_change & IFF_UP) {
|
||||
snprintf(msg, sizeof(msg), "net/%s/up", ifname);
|
||||
|
||||
if (i->ifi_flags & IFF_UP)
|
||||
cond_set(msg);
|
||||
else
|
||||
cond_clear(msg);
|
||||
|
||||
if (string_compare("lo", ifname)) {
|
||||
snprintf(msg, sizeof(msg), "net/%s/exist", ifname);
|
||||
cond_set(msg);
|
||||
}
|
||||
} else {
|
||||
snprintf(msg, sizeof(msg), "net/%s/exist", ifname);
|
||||
cond_set(msg);
|
||||
}
|
||||
break;
|
||||
|
||||
case RTM_DELLINK:
|
||||
/* NOTE: Interface has dissapeared, not link down ... */
|
||||
snprintf(msg, sizeof(msg), "net/%s/exist", ifname);
|
||||
cond_clear(msg);
|
||||
break;
|
||||
|
||||
case RTM_NEWADDR:
|
||||
_d("%s: New Address", ifname);
|
||||
break;
|
||||
|
||||
case RTM_DELADDR:
|
||||
_d("%s: Deconfig Address", ifname);
|
||||
break;
|
||||
|
||||
default:
|
||||
_d("%s: Msg 0x%x", ifname, nlmsg->nlmsg_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
a = RTA_NEXT(a, la);
|
||||
}
|
||||
}
|
||||
|
||||
static void nl_callback(void *UNUSED(arg), int sd, int UNUSED(events))
|
||||
{
|
||||
ssize_t len;
|
||||
static char buf[4096];
|
||||
struct nlmsghdr *nh;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
len = recv(sd, buf, sizeof(buf), 0);
|
||||
if (len < 0) {
|
||||
if (errno != EINTR) /* Signal */
|
||||
_pe("recv()");
|
||||
return;
|
||||
}
|
||||
|
||||
for (nh = (struct nlmsghdr *)buf; !nlmsg_validate(nh, len); nh = NLMSG_NEXT(nh, len)) {
|
||||
//_d("Well formed netlink message received. type %d ...", nh->nlmsg_type);
|
||||
if (nh->nlmsg_type == RTM_NEWROUTE || nh->nlmsg_type == RTM_DELROUTE)
|
||||
nl_route(nh);
|
||||
else
|
||||
nl_link(nh);
|
||||
}
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.io = {
|
||||
.cb = nl_callback,
|
||||
.flags = PLUGIN_IO_READ,
|
||||
},
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
int sd;
|
||||
struct sockaddr_nl sa;
|
||||
|
||||
sd = socket(AF_NETLINK, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, NETLINK_ROUTE);
|
||||
if (sd < 0) {
|
||||
_pe("socket()");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.nl_family = AF_NETLINK;
|
||||
sa.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_LINK; // | RTMGRP_NOTIFY | RTMGRP_IPV4_IFADDR;
|
||||
sa.nl_pid = getpid();
|
||||
|
||||
if (bind(sd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
||||
_pe("bind()");
|
||||
close(sd);
|
||||
return;
|
||||
}
|
||||
|
||||
plugin.io.fd = sd;
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,159 @@
|
||||
/* Simple pidfile event monitor for the Finit condition engine
|
||||
*
|
||||
* Copyright (c) 2015-2016 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 <limits.h>
|
||||
#include <paths.h>
|
||||
|
||||
#include <sys/inotify.h>
|
||||
|
||||
#include "../finit.h"
|
||||
#include "../cond.h"
|
||||
#include "../helpers.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
struct context {
|
||||
int fd;
|
||||
int wd;
|
||||
};
|
||||
|
||||
static void pidfile_callback(void *UNUSED(arg), int fd, int UNUSED(events))
|
||||
{
|
||||
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
||||
static char cond[MAX_ARG_LEN];
|
||||
|
||||
struct inotify_event *ev;
|
||||
ssize_t sz, len;
|
||||
char *basename;
|
||||
svc_t *svc;
|
||||
|
||||
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
||||
if (sz <= 0) {
|
||||
_pe("invalid inotify event");
|
||||
return;
|
||||
}
|
||||
ev_buf[sz] = 0;
|
||||
|
||||
for (ev = (void *)ev_buf; sz > (ssize_t)sizeof(*ev);
|
||||
len = sizeof(*ev) + ev->len, ev = (void *)ev + len, sz -= len) {
|
||||
/* ev = (void *)(ev + 1) + ev->len, sz -= sizeof(*ev) + ev->len) { */
|
||||
if (!ev->mask || !strstr(ev->name, ".pid"))
|
||||
continue;
|
||||
|
||||
basename = strtok(ev->name, ".");
|
||||
if (!basename)
|
||||
continue;
|
||||
|
||||
svc = svc_find_by_nameid(basename, 1);
|
||||
if (!svc)
|
||||
continue;
|
||||
|
||||
/* TODO FIXME XXX WKZ check that pid is controlled by finit */
|
||||
|
||||
_d("%s: match %s", basename, svc->cmd);
|
||||
snprintf(cond, sizeof(cond), "svc%s", svc->cmd);
|
||||
if (ev->mask & (IN_CREATE | IN_ATTRIB | IN_MODIFY)) {
|
||||
svc_started(svc);
|
||||
cond_set(cond);
|
||||
} else if (ev->mask & IN_DELETE)
|
||||
cond_clear(cond);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Assert condition only if the service is running, but not if it's
|
||||
* recently been changed or while it's starting up.
|
||||
*
|
||||
* We must wait for the service to create/touch its pidfile.
|
||||
*/
|
||||
static void pidfile_reconf(void *_null)
|
||||
{
|
||||
static char name[MAX_ARG_LEN];
|
||||
|
||||
svc_t *svc;
|
||||
(void)(_null);
|
||||
|
||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
||||
if (svc->state == SVC_RUNNING_STATE && !svc_is_changed(svc) && !svc_is_starting(svc)) {
|
||||
snprintf(name, MAX_ARG_LEN, "svc%s", svc->cmd);
|
||||
cond_set_path(cond_path(name), COND_ON);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void pidfile_init(void *arg)
|
||||
{
|
||||
struct context *ctx = arg;
|
||||
|
||||
ctx->wd = inotify_add_watch(ctx->fd, _PATH_VARRUN,
|
||||
IN_CREATE | IN_ATTRIB | IN_DELETE | IN_MODIFY);
|
||||
if (ctx->wd < 0) {
|
||||
_pe("inotify_add_watch()");
|
||||
close(ctx->fd);
|
||||
return;
|
||||
}
|
||||
|
||||
_d("pidfile monitor active");
|
||||
}
|
||||
|
||||
static struct context pidfile_ctx;
|
||||
|
||||
/*
|
||||
* We require /var/run to be set up before calling pidfile_init(),
|
||||
* so the bootmisc plugin must run first.
|
||||
*/
|
||||
static plugin_t plugin = {
|
||||
.hook[HOOK_BASEFS_UP] = { .arg = &pidfile_ctx, .cb = pidfile_init },
|
||||
.hook[HOOK_SVC_RECONF] = { .cb = pidfile_reconf },
|
||||
.io = {
|
||||
.cb = pidfile_callback,
|
||||
.flags = PLUGIN_IO_READ,
|
||||
},
|
||||
.depends = { "bootmisc", },
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
pidfile_ctx.fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
||||
if (pidfile_ctx.fd < 0) {
|
||||
_pe("inotify_init()");
|
||||
return;
|
||||
}
|
||||
|
||||
plugin.io.fd = pidfile_ctx.fd;
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
inotify_rm_watch(pidfile_ctx.fd, pidfile_ctx.wd);
|
||||
close(pidfile_ctx.fd);
|
||||
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,74 @@
|
||||
/* Set kernel variables from /etc/sysctl.conf et al
|
||||
*
|
||||
* Copyright (c) 2016 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <glob.h>
|
||||
#include <lite/lite.h>
|
||||
#include "../plugin.h"
|
||||
|
||||
static void setup(void *UNUSED(arg))
|
||||
{
|
||||
size_t i;
|
||||
glob_t gl;
|
||||
char buf[160];
|
||||
|
||||
glob("/run/sysctl.d/*.conf", 0, NULL, &gl);
|
||||
glob("/etc/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||
glob("/usr/local/lib/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||
glob("/usr/lib/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||
glob("/lib/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||
glob("/mnt/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||
glob("/etc/sysctl.conf", GLOB_APPEND, NULL, &gl);
|
||||
if (gl.gl_pathc > 0) {
|
||||
for (i = 0; i < gl.gl_pathc; i++) {
|
||||
snprintf(buf, sizeof(buf), "/sbin/sysctl -e -p %s >/dev/null", gl.gl_pathv[i]);
|
||||
run(buf);
|
||||
}
|
||||
globfree(&gl);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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:
|
||||
*/
|
||||
@@ -0,0 +1,71 @@
|
||||
/* Setup necessary files for resolvconf
|
||||
*
|
||||
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "../finit.h"
|
||||
#include "../helpers.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
/*
|
||||
* No need to clean up files in /etc/resolvconf/run/interface/
|
||||
* this is already taken care of by bootclean
|
||||
*/
|
||||
static void setup(void *UNUSED(arg))
|
||||
{
|
||||
_d("Setting up the resolver ...");
|
||||
mkpath("/etc/resolvconf", 0755);
|
||||
mkpath("/etc/resolvconf/run", 0755);
|
||||
mkpath("/var/run/resolvconf", 0755);
|
||||
mkpath("/var/run/resolvconf/interface", 0755);
|
||||
|
||||
touch("/etc/resolvconf/run/enable-updates");
|
||||
chdir("/etc/resolvconf/run/interface");
|
||||
run_parts("/etc/resolvconf/update.d", "-i");
|
||||
chdir("/");
|
||||
}
|
||||
|
||||
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:
|
||||
*/
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
/* Optional inetd plugin for Time Protocol (rdate), RFC 868
|
||||
*
|
||||
* Copyright (c) 2015 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h> /* STDIN_FILENO */
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
#define NAME "time"
|
||||
|
||||
/* UNIX epoch starts midnight, 1st Jan, 1970 */
|
||||
#define EPOCH_OFFSET 2208988800ULL
|
||||
|
||||
/* Return number of seconds since midnight, 1st Jan, 1900 */
|
||||
static char *rfctime(char *buf, size_t *len)
|
||||
{
|
||||
time_t now;
|
||||
|
||||
now = time(NULL);
|
||||
if ((time_t)-1 == now)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Account for UNIX epoch offset, and
|
||||
* convert to network byte order
|
||||
*/
|
||||
now += EPOCH_OFFSET;
|
||||
now = htonl(now);
|
||||
|
||||
*len = sizeof(now);
|
||||
memcpy(buf, &now, *len);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int recv_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, socklen_t *sa_len)
|
||||
{
|
||||
len = recvfrom(sd, buf, sizeof(buf), MSG_DONTWAIT, sa, sa_len);
|
||||
if (-1 == len)
|
||||
return -1; /* On error, close connection. */
|
||||
|
||||
if (inetd_check_loop(sa, *sa_len, NAME))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, socklen_t sa_len)
|
||||
{
|
||||
char *now;
|
||||
|
||||
now = rfctime(buf, (size_t *)&len);
|
||||
if (!now)
|
||||
return -1; /* On error, close connection. */
|
||||
|
||||
return sendto(sd, now, len, MSG_DONTWAIT, sa, sa_len);
|
||||
}
|
||||
|
||||
static int cb(int UNUSED(type))
|
||||
{
|
||||
int sd = STDIN_FILENO;
|
||||
char buf[BUFSIZ];
|
||||
struct sockaddr_storage sa;
|
||||
socklen_t sa_len = sizeof(sa);
|
||||
|
||||
if (recv_peer(sd, buf, sizeof(buf), (struct sockaddr *)&sa, &sa_len))
|
||||
return -1; /* On error, close connection. */
|
||||
|
||||
return send_peer(sd, buf, sizeof(buf), (struct sockaddr *)&sa, sa_len);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = NAME, /* Must match the inetd /etc/services entry */
|
||||
.inetd = {
|
||||
.cmd = cb
|
||||
}
|
||||
};
|
||||
|
||||
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:
|
||||
*/
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
/* 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 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h> /* O_RDONLY et al */
|
||||
#include <unistd.h> /* read() */
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/stat.h>
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "../finit.h"
|
||||
#include "../helpers.h"
|
||||
#include "../plugin.h"
|
||||
#include "../tty.h"
|
||||
|
||||
static void watcher(void *arg, int fd, int events);
|
||||
|
||||
static plugin_t plugin = {
|
||||
.io = {
|
||||
.cb = watcher,
|
||||
.flags = PLUGIN_IO_READ,
|
||||
},
|
||||
};
|
||||
|
||||
static void setup(void)
|
||||
{
|
||||
if (plugin.io.fd)
|
||||
close(plugin.io.fd);
|
||||
|
||||
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)
|
||||
_pe("Failed starting TTY watcher");
|
||||
}
|
||||
|
||||
static void watcher(void *UNUSED(arg), int fd, int UNUSED(events))
|
||||
{
|
||||
int len = 0;
|
||||
char buf[EVENT_SIZE], name[42];
|
||||
tty_node_t *entry;
|
||||
struct inotify_event *notified = (struct inotify_event *)buf;
|
||||
|
||||
while ((len = read(fd, buf, sizeof(buf)))) {
|
||||
if (-1 == len) {
|
||||
if (errno == EINVAL)
|
||||
setup();
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
break; /* Likely EAGAIN */
|
||||
}
|
||||
|
||||
snprintf(name, sizeof(name), "/dev/%s", notified->name);
|
||||
entry = tty_find(name);
|
||||
if (entry && tty_enabled(&entry->data, runlevel)) {
|
||||
if (notified->mask & IN_CREATE)
|
||||
tty_start(&entry->data);
|
||||
else if (entry->data.pid)
|
||||
tty_stop(&entry->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
setup();
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
if (plugin.io.fd)
|
||||
close(plugin.io.fd);
|
||||
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,100 @@
|
||||
/* Setup random seed
|
||||
*
|
||||
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h> /* gettimeofday() */
|
||||
#include <sys/types.h>
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "../config.h"
|
||||
#include "../finit.h"
|
||||
#include "../helpers.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
static void setup(void *UNUSED(arg))
|
||||
{
|
||||
#ifdef RANDOMSEED
|
||||
if (!fexist(RANDOMSEED)) {
|
||||
int ret = 1;
|
||||
FILE *fp;
|
||||
|
||||
print_desc("Bootstrapping random seed", NULL);
|
||||
umask(077);
|
||||
fp = fopen(RANDOMSEED, "w");
|
||||
if (fp) {
|
||||
int iter = 128;
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
srandom(tv.tv_sec % 3600);
|
||||
while (iter--) {
|
||||
uint32_t i, prng = random();
|
||||
|
||||
for (i = 0; i < sizeof(prng); i++)
|
||||
fputc((prng >> (i * CHAR_BIT)) & UCHAR_MAX, fp);
|
||||
}
|
||||
ret = fclose(fp);
|
||||
}
|
||||
print_result(ret);
|
||||
umask(0);
|
||||
}
|
||||
|
||||
print_desc("Initializing random number generator", NULL);
|
||||
print_result(512 != copyfile(RANDOMSEED, "/dev/urandom", 0, 0));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void save(void *UNUSED(arg))
|
||||
{
|
||||
#ifdef RANDOMSEED
|
||||
umask(077);
|
||||
print_desc("Saving random seed", NULL);
|
||||
print_result(512 != copyfile("/dev/urandom", RANDOMSEED, 512, 0));
|
||||
umask(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_BASEFS_UP] = { .cb = setup },
|
||||
.hook[HOOK_SHUTDOWN] = { .cb = save },
|
||||
.depends = { "bootmisc", }
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,86 @@
|
||||
/* Console setup (for X)
|
||||
*
|
||||
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "../finit.h"
|
||||
#include "../helpers.h"
|
||||
#include "../plugin.h"
|
||||
|
||||
static void setup(void *UNUSED(arg))
|
||||
{
|
||||
#ifdef PAM_CONSOLE
|
||||
int fd;
|
||||
#endif
|
||||
char line[LINE_SIZE];
|
||||
|
||||
umask(0);
|
||||
|
||||
makedir("/var/run/console", 01777);
|
||||
snprintf(line, sizeof(line), "/var/run/console/%s", username);
|
||||
touch(line);
|
||||
|
||||
#ifdef PAM_CONSOLE
|
||||
if ((fd = open("/var/run/console/console.lock", O_CREAT|O_WRONLY|O_TRUNC, 0644)) >= 0) {
|
||||
write(fd, username, strlen(username));
|
||||
close(fd);
|
||||
run("/sbin/pam_console_apply");
|
||||
}
|
||||
#endif
|
||||
|
||||
makedir("/tmp/.X11-unix", 01777);
|
||||
makedir("/tmp/.ICE-unix", 01777);
|
||||
|
||||
if (fexist("/sbin/restorecon"))
|
||||
run("/sbin/restorecon /tmp/.ICE-unix /tmp/.X11-unix");
|
||||
|
||||
umask(022);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = __FILE__,
|
||||
.hook[HOOK_NETWORK_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:
|
||||
*/
|
||||
@@ -0,0 +1,56 @@
|
||||
/* Private header file for main finit daemon, not for plugins
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2013 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef FINIT_PRIVATE_H_
|
||||
#define FINIT_PRIVATE_H_
|
||||
|
||||
#include "svc.h"
|
||||
#include "plugin.h"
|
||||
|
||||
/*
|
||||
* Main loop context
|
||||
*/
|
||||
uev_ctx_t *ctx;
|
||||
|
||||
int api_init (uev_ctx_t *ctx);
|
||||
int api_exit (void);
|
||||
|
||||
int client (int argc, char *argv[]);
|
||||
|
||||
void service_monitor (pid_t lost);
|
||||
|
||||
void plugin_run_hook (hook_point_t no, void *arg);
|
||||
void plugin_run_hooks (hook_point_t no);
|
||||
|
||||
int plugin_init (uev_ctx_t *ctx, char *path);
|
||||
void plugin_exit (void);
|
||||
|
||||
#endif /* FINIT_PRIVATE_H_ */
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,206 @@
|
||||
/* reboot, halt, poweroff, shutdown, suspend for finit
|
||||
*
|
||||
* Copyright (c) 2009-2016 Joachim Nilsson <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/reboot.h>
|
||||
#include "util.h"
|
||||
|
||||
#ifndef RB_SW_SUSPEND /* Since Linux 2.5.18, but not in GLIBC until 2.19 */
|
||||
#define RB_SW_SUSPEND 0xd000fce2
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
CMD_UNKNOWN = -1,
|
||||
CMD_REBOOT = 0,
|
||||
CMD_HALT,
|
||||
CMD_POWEROFF,
|
||||
CMD_SUSPEND,
|
||||
} cmd_t;
|
||||
|
||||
static cmd_t cmd = CMD_UNKNOWN;
|
||||
static char *msg = NULL;
|
||||
|
||||
static void translate(void)
|
||||
{
|
||||
if (cmd == CMD_UNKNOWN) {
|
||||
if (!strcmp(prognm, "halt") || !strcmp(prognm, "shutdown"))
|
||||
cmd = CMD_HALT;
|
||||
else if (!strcmp(prognm, "poweroff"))
|
||||
cmd = CMD_POWEROFF;
|
||||
else if (!strcmp(prognm, "suspend"))
|
||||
cmd = CMD_SUSPEND;
|
||||
else
|
||||
cmd = CMD_REBOOT;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case CMD_REBOOT:
|
||||
msg = "reboot";
|
||||
break;
|
||||
|
||||
case CMD_HALT:
|
||||
msg = "halt";
|
||||
break;
|
||||
|
||||
case CMD_POWEROFF:
|
||||
msg = "power-off";
|
||||
break;
|
||||
|
||||
case CMD_SUSPEND:
|
||||
msg = "suspend";
|
||||
break;
|
||||
|
||||
case CMD_UNKNOWN:
|
||||
cmd = CMD_REBOOT;
|
||||
msg = "reboot";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int usage(int rc)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [OPTIONS]\n\n"
|
||||
"Options:\n"
|
||||
" -h, --help This help text\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"
|
||||
" -p, --poweroff Power-off system, regardless of how the command is called.\n"
|
||||
" --reboot Reboot system, regardless of how the command is called.\n"
|
||||
"\n", prognm, msg);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int c, force = 0;
|
||||
struct option long_options[] = {
|
||||
{"help", 0, NULL, 'h'},
|
||||
{"force", 0, NULL, 'f'},
|
||||
{"halt", 0, NULL, 'H'},
|
||||
{"poweroff", 0, NULL, 'p'},
|
||||
{"reboot", 0, NULL, 'r'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
/* Initial command taken from program name */
|
||||
progname(argv[0]);
|
||||
translate();
|
||||
|
||||
while ((c = getopt_long(argc, argv, "h?fHpr", long_options, NULL)) != EOF) {
|
||||
switch(c) {
|
||||
case 'h':
|
||||
case '?':
|
||||
return usage(0);
|
||||
|
||||
case 'f':
|
||||
force = 1;
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
cmd = CMD_HALT;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
cmd = CMD_POWEROFF;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
cmd = CMD_REBOOT;
|
||||
break;
|
||||
|
||||
default:
|
||||
return usage(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for any overrides */
|
||||
translate();
|
||||
|
||||
if (force) {
|
||||
switch (cmd) {
|
||||
case CMD_REBOOT:
|
||||
c = reboot(RB_AUTOBOOT);
|
||||
break;
|
||||
|
||||
case CMD_HALT:
|
||||
c = reboot(RB_HALT_SYSTEM);
|
||||
break;
|
||||
|
||||
case CMD_POWEROFF:
|
||||
c = reboot(RB_POWER_OFF);
|
||||
break;
|
||||
|
||||
case CMD_SUSPEND:
|
||||
c = reboot(RB_SW_SUSPEND);
|
||||
break;
|
||||
|
||||
case CMD_UNKNOWN:
|
||||
errx(1, "Invalid command");
|
||||
break;
|
||||
}
|
||||
|
||||
if (c)
|
||||
warn("Failed forced %s", msg);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case CMD_REBOOT:
|
||||
c = kill(1, SIGTERM);
|
||||
break;
|
||||
|
||||
case CMD_HALT:
|
||||
c = kill(1, SIGUSR1);
|
||||
break;
|
||||
|
||||
case CMD_POWEROFF:
|
||||
c = kill(1, SIGUSR2);
|
||||
break;
|
||||
|
||||
case CMD_SUSPEND:
|
||||
case CMD_UNKNOWN:
|
||||
errx(1, "Invalid command");
|
||||
break;
|
||||
}
|
||||
|
||||
if (c)
|
||||
err(1, "Failed signalling init to %s", msg);
|
||||
else
|
||||
sleep(2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
initctl show
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ $# -lt 2 -o $# -gt 2 ]; then
|
||||
echo "Usage: service [job# | name] <stop | start | restart | reload>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
initctl $2 $1
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user