mirror of
https://github.com/troglobit/finit.git
synced 2026-10-12 10:12:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
+22
-2
@@ -1,8 +1,13 @@
|
|||||||
|
*~
|
||||||
*.o
|
*.o
|
||||||
*.d
|
|
||||||
*.so
|
*.so
|
||||||
*.gz
|
*.gz
|
||||||
*.map
|
*.map
|
||||||
|
configure
|
||||||
|
Makefile
|
||||||
|
Makefile.in
|
||||||
|
/.deps/*
|
||||||
|
/.libs/*
|
||||||
/finit
|
/finit
|
||||||
/initctl
|
/initctl
|
||||||
/reboot
|
/reboot
|
||||||
@@ -12,4 +17,19 @@
|
|||||||
/GRTAGS
|
/GRTAGS
|
||||||
/GSYMS
|
/GSYMS
|
||||||
/GTAGS
|
/GTAGS
|
||||||
/contrib/*
|
/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
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
[submodule "libuev"]
|
|
||||||
path = libuev
|
|
||||||
url = https://github.com/troglobit/libuev.git
|
|
||||||
[submodule "libite"]
|
|
||||||
path = libite
|
|
||||||
url = https://github.com/troglobit/libite.git
|
|
||||||
|
|||||||
+35
-7
@@ -2,9 +2,17 @@
|
|||||||
# Defaults to GNU GCC and autotools: ./configure && make && make test
|
# Defaults to GNU GCC and autotools: ./configure && make && make test
|
||||||
language: c
|
language: c
|
||||||
|
|
||||||
# We don't need to install packages, use dockerized build, quicker
|
# Use docker for quicker builds, it now allows https://docs.travis-ci.com/user/apt/
|
||||||
sudo: false
|
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:
|
env:
|
||||||
global:
|
global:
|
||||||
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||||
@@ -12,17 +20,37 @@ env:
|
|||||||
- secure: "eOiuHs02lG2Uv146K9dMqucGTWUJFEhpz1oAtwe+kPrRXsXWc20hYMO+DSpMgD05vSvNeQA6p7h7LdRFQ+/g/Obj27TsOE+RKkUvRAtdwzxnKVyii9C/nmML8cFw7rIA0VS8O9mAkVYeyDxNDupBp3e9DPCibhKPvqCvioTnyy4="
|
- secure: "eOiuHs02lG2Uv146K9dMqucGTWUJFEhpz1oAtwe+kPrRXsXWc20hYMO+DSpMgD05vSvNeQA6p7h7LdRFQ+/g/Obj27TsOE+RKkUvRAtdwzxnKVyii9C/nmML8cFw7rIA0VS8O9mAkVYeyDxNDupBp3e9DPCibhKPvqCvioTnyy4="
|
||||||
|
|
||||||
addons:
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- tree
|
||||||
coverity_scan:
|
coverity_scan:
|
||||||
project:
|
project:
|
||||||
name: "troglobit/finit"
|
name: "troglobit/finit"
|
||||||
description: "finit | Fast & Extensible init for Linux"
|
description: "finit | Fast & Extensible init for Linux"
|
||||||
notification_email: troglobit@gmail.com
|
notification_email: troglobit@gmail.com
|
||||||
build_command_prepend: "./configure"
|
build_command_prepend: "./autogen.sh && PKG_CONFIG_PATH=/tmp/lib/pkgconfig ./configure --prefix=/tmp"
|
||||||
build_command: "make"
|
build_command: "make"
|
||||||
branch_pattern: dev
|
branch_pattern: dev
|
||||||
|
|
||||||
|
install:
|
||||||
|
- wget https://github.com/troglobit/libuev/releases/download/v1.4.2/libuev-1.4.2.tar.xz
|
||||||
|
- wget https://github.com/troglobit/libite/releases/download/v1.8.2/libite-1.8.2.tar.xz
|
||||||
|
- tar xf libuev-1.4.2.tar.xz
|
||||||
|
- tar xf libite-1.8.2.tar.xz
|
||||||
|
- (cd libuev-1.4.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
|
# Custom build script for the time being, no "make test" yet
|
||||||
script:
|
script:
|
||||||
- make distclean
|
- ./autogen.sh
|
||||||
- ./configure
|
- PKG_CONFIG_PATH=/tmp/lib/pkgconfig ./configure --prefix=/tmp
|
||||||
- make
|
- 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
|
||||||
|
|||||||
+36
-4
@@ -3,6 +3,38 @@ Change Log
|
|||||||
|
|
||||||
All relevant changes are documented in this file.
|
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
|
[2.4][] - 2015-12-04
|
||||||
--------------------
|
--------------------
|
||||||
@@ -17,10 +49,10 @@ Bug fix release.
|
|||||||
* Update section mentioning BusyBox getty
|
* Update section mentioning BusyBox getty
|
||||||
* Update debugging documentation
|
* Update debugging documentation
|
||||||
* Allow debug to override terse mode
|
* Allow debug to override terse mode
|
||||||
* Revert confusing change in service state introduced in [v2.3][].
|
* Revert confusing change in service state introduced in [v2.3][2.3].
|
||||||
As of v2.4 services are listed as "halted" and "stopped", when
|
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
|
they have been halted due to a runlevel changed or stopped by the
|
||||||
the user, respectively.
|
user, respectively.
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
|
||||||
|
|||||||
@@ -1,185 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
.PHONY: all install clean distclean dist \
|
|
||||||
install-exec install-data install-dev \
|
|
||||||
uninstall-exec uninstall-data uninstall-dev
|
|
||||||
|
|
||||||
#VERSION = $(shell git tag -l | tail -1)
|
|
||||||
VERSION = 2.4
|
|
||||||
NAME = finit
|
|
||||||
PKG = $(NAME)-$(VERSION)
|
|
||||||
DEV = $(NAME)-dev
|
|
||||||
ARCHTOOL = `which git-archive-all`
|
|
||||||
ARCHIVE = $(PKG).tar
|
|
||||||
ARCHIVEZ = ../$(ARCHIVE).xz
|
|
||||||
EXEC = finit initctl reboot
|
|
||||||
HEADERS = finit.h plugin.h svc.h inetd.h helpers.h queue.h
|
|
||||||
DISTFILES = LICENSE README ChangeLog finit.conf services
|
|
||||||
OBJS = finit.o api.o client.o conf.o exec.o helpers.o pid.o sig.o \
|
|
||||||
svc.o service.o plugin.o tty.o inetd.o event.o
|
|
||||||
DEPLIBS =
|
|
||||||
TOPDIR = $(shell pwd)
|
|
||||||
-include config.mk
|
|
||||||
|
|
||||||
# Figure out source and dependency files
|
|
||||||
SRCS = $(OBJS:.o=.c)
|
|
||||||
DEPS = $(SRCS:.c=.d)
|
|
||||||
|
|
||||||
CFLAGS += -W -Wall
|
|
||||||
# Disable annoying gcc warning for "warn_unused_result", see GIT 37af997
|
|
||||||
CPPFLAGS += -U_FORTIFY_SOURCE
|
|
||||||
CPPFLAGS += -I$(TOPDIR)
|
|
||||||
CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
|
|
||||||
CPPFLAGS += -DVERSION=\"$(VERSION)\" -DWHOAMI=\"`whoami`@`hostname`\"
|
|
||||||
|
|
||||||
include common.mk
|
|
||||||
|
|
||||||
|
|
||||||
all: config.h $(EXEC)
|
|
||||||
+$(MAKE) -C plugins $@
|
|
||||||
|
|
||||||
$(DEPLIBS): Makefile
|
|
||||||
+$(MAKE) -C `dirname $@` all
|
|
||||||
|
|
||||||
$(OBJS): Makefile
|
|
||||||
|
|
||||||
config.h: configure
|
|
||||||
@echo "Please run configure script first."
|
|
||||||
@exit 1
|
|
||||||
|
|
||||||
finit: $(OBJS) $(DEPLIBS)
|
|
||||||
|
|
||||||
initctl: initctl.o svc.o helpers.o $(DEPLIBS)
|
|
||||||
|
|
||||||
reboot: reboot.o $(DEPLIBS)
|
|
||||||
|
|
||||||
install-exec: all
|
|
||||||
@$(INSTALL) -d $(DESTDIR)$(FINIT_RCSD)
|
|
||||||
@$(INSTALL) -d $(DESTDIR)$(sbindir)
|
|
||||||
@for file in $(EXEC); do \
|
|
||||||
printf " INSTALL $(DESTDIR)$(sbindir)/$$file\n"; \
|
|
||||||
$(STRIPINST) $$file $(DESTDIR)$(sbindir)/$$file; \
|
|
||||||
done
|
|
||||||
@printf " INSTALL $(DESTDIR)$(sbindir)/service\n"
|
|
||||||
@$(INSTALL) -m 0755 service $(DESTDIR)$(sbindir)/service
|
|
||||||
printf " INSTALL $(DESTDIR)$(sbindir)/telinit\n"
|
|
||||||
@ln -sf finit $(DESTDIR)$(sbindir)/telinit
|
|
||||||
$(MAKE) -C plugins install
|
|
||||||
ifndef LIBITE
|
|
||||||
$(MAKE) -C libite install-exec
|
|
||||||
endif
|
|
||||||
|
|
||||||
install-data:
|
|
||||||
@$(INSTALL) -d $(DESTDIR)$(datadir)
|
|
||||||
@$(INSTALL) -d $(DESTDIR)$(mandir)
|
|
||||||
@for file in $(DISTFILES); do \
|
|
||||||
printf " INSTALL $(DESTDIR)$(datadir)/$$file\n"; \
|
|
||||||
$(INSTALL) -m 0644 $$file $(DESTDIR)$(datadir)/$$file; \
|
|
||||||
done
|
|
||||||
|
|
||||||
install-dev:
|
|
||||||
@$(INSTALL) -d $(DESTDIR)$(incdir)
|
|
||||||
@for file in $(HEADERS); do \
|
|
||||||
printf " INSTALL $(DESTDIR)$(incdir)/$$file\n"; \
|
|
||||||
$(INSTALL) -m 0644 $$file $(DESTDIR)$(incdir)/$$file; \
|
|
||||||
done
|
|
||||||
ifndef LIBITE
|
|
||||||
$(MAKE) -C libite install-dev
|
|
||||||
endif
|
|
||||||
ifndef LIBUEV
|
|
||||||
$(MAKE) -C libuev install-dev
|
|
||||||
endif
|
|
||||||
|
|
||||||
install: install-exec install-data install-dev
|
|
||||||
|
|
||||||
uninstall-exec:
|
|
||||||
-@for file in $(EXEC); do \
|
|
||||||
printf " REMOVE $(DESTDIR)$(sbindir)/$$file\n"; \
|
|
||||||
rm $(DESTDIR)$(sbindir)/$$file 2>/dev/null; \
|
|
||||||
done
|
|
||||||
-@for file in service telinit; do \
|
|
||||||
printf " REMOVE $(DESTDIR)$(sbindir)/$$file\n"; \
|
|
||||||
rm $(DESTDIR)$(sbindir)/$$file 2>/dev/null; \
|
|
||||||
done
|
|
||||||
-@rmdir $(DESTDIR)$(sbindir) 2>/dev/null
|
|
||||||
-@rmdir $(DESTDIR)$(FINIT_RCSD) 2>/dev/null
|
|
||||||
$(MAKE) -C plugins uninstall
|
|
||||||
ifndef LIBITE
|
|
||||||
$(MAKE) -C libite uninstall
|
|
||||||
endif
|
|
||||||
|
|
||||||
uninstall-data:
|
|
||||||
-@for file in $(DISTFILES); do \
|
|
||||||
printf " REMOVE $(DESTDIR)$(datadir)/$$file\n"; \
|
|
||||||
rm $(DESTDIR)$(datadir)/$$file 2>/dev/null; \
|
|
||||||
done
|
|
||||||
-@rmdir $(DESTDIR)$(mandir) 2>/dev/null
|
|
||||||
-@rmdir $(DESTDIR)$(datadir) 2>/dev/null
|
|
||||||
|
|
||||||
uninstall-dev:
|
|
||||||
-@$(RM) -rf $(DESTDIR)$(incdir) 2>/dev/null
|
|
||||||
|
|
||||||
uninstall: uninstall-exec uninstall-data uninstall-dev
|
|
||||||
|
|
||||||
clean:
|
|
||||||
+$(MAKE) -C plugins $@
|
|
||||||
+$(MAKE) -C libite $@
|
|
||||||
+$(MAKE) -C libuev $@
|
|
||||||
-@$(RM) $(OBJS) $(DEPS) $(EXEC) 2>/dev/null
|
|
||||||
|
|
||||||
distclean: clean
|
|
||||||
+$(MAKE) -C plugins $@
|
|
||||||
+$(MAKE) -C libite $@
|
|
||||||
+$(MAKE) -C libuev $@
|
|
||||||
-@$(RM) $(JUNK) config.mk config.h unittest *.o *.html 2>/dev/null
|
|
||||||
|
|
||||||
check:
|
|
||||||
$(CHECK) *.c plugins/*.c
|
|
||||||
|
|
||||||
dist:
|
|
||||||
@if [ x"$(ARCHTOOL)" = x"" ]; then \
|
|
||||||
echo "Missing git-archive-all from https://github.com/Kentzo/git-archive-all"; \
|
|
||||||
exit 1; \
|
|
||||||
fi
|
|
||||||
@if [ -e $(ARCHIVEZ) ]; then \
|
|
||||||
echo "Distribution already exists."; \
|
|
||||||
exit 1; \
|
|
||||||
fi
|
|
||||||
@echo "Building xz tarball of $(PKG) in parent dir..."
|
|
||||||
@$(ARCHTOOL) ../$(ARCHIVE)
|
|
||||||
@xz ../$(ARCHIVE)
|
|
||||||
@md5sum $(ARCHIVEZ) | tee $(ARCHIVEZ).md5
|
|
||||||
|
|
||||||
dev: distclean
|
|
||||||
@echo "Building unstable xz $(DEV) in parent dir..."
|
|
||||||
-@$(RM) -f ../$(DEV).tar.xz*
|
|
||||||
@(dir=`mktemp -d`; mkdir $$dir/$(DEV); cp -a . $$dir/$(DEV); \
|
|
||||||
cd $$dir; tar --exclude=.git --exclude=contrib \
|
|
||||||
-c -J -f $(DEV).tar.xz $(DEV); \
|
|
||||||
cd - >/dev/null; mv $$dir/$(DEV).tar.xz ../; cd ..; \
|
|
||||||
rm -rf $$dir; md5sum $(DEV).tar.xz | tee $(DEV).tar.xz.md5)
|
|
||||||
|
|
||||||
ifneq ($(MAKECMDGOALS),distclean)
|
|
||||||
-include $(DEPS)
|
|
||||||
endif
|
|
||||||
+112
@@ -0,0 +1,112 @@
|
|||||||
|
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 \
|
||||||
|
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
|
||||||
|
|
||||||
|
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 \
|
||||||
|
utmp-api.c utmp-api.h
|
||||||
|
initctl_CFLAGS = $(lite_CFLAGS)
|
||||||
|
initctl_LDADD = $(lite_LIBS)
|
||||||
|
|
||||||
|
reboot_SOURCES = reboot.c
|
||||||
|
|
||||||
|
INIT_LNKS = telinit init
|
||||||
|
REBOOT_LNKS = shutdown halt 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."; \
|
||||||
|
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,25 +1,32 @@
|
|||||||
Finit ][ Fast & Extensible init for Linux
|
```
|
||||||
=========================================
|
_______ __ _____ ___ __ ___________ _______
|
||||||
|
/" "||" \ (\" \|" \ |" \(" _ ")/" __ )
|
||||||
|
(: ______)|| | |.\\ \ | || |)__/ \\__/(__/ _) ./
|
||||||
|
\/ | |: | |: \. \\ | |: | \\_ / / //
|
||||||
|
// ___) |. | |. \ \. | |. | |. | __ \_ \\
|
||||||
|
(: ( /\ |\| \ \ | /\ |\ \: | (: \__) :\
|
||||||
|
\__/ (__\_|_)\___|\____\)(__\_|_) \__| \_______) ... Yes, we need a new logo!
|
||||||
|
```
|
||||||
|
|
||||||
|
Fast init for Linux
|
||||||
|
===================
|
||||||
[![Travis Status]][Travis] [![Coverity Status]][Coverity Scan]
|
[![Travis Status]][Travis] [![Coverity Status]][Coverity Scan]
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
Table of Contents
|
Table of Contents
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
* [Introduction](#introduction)
|
* [Introduction](#introduction)
|
||||||
* [Features](#features)
|
* [Features](#features)
|
||||||
* [/etc/finit.conf](#etcfinitconf)
|
* [/etc/finit.conf](doc/config.md#etcfinitconf)
|
||||||
* [/etc/finit.d](#etcfinitd)
|
* [/etc/finit.d](doc/config.md#etcfinitd)
|
||||||
* [Runparts](#runparts)
|
* [Runparts & /etc/rc.local](#runparts--etcrclocal)
|
||||||
* [Bootstrap](#bootstrap)
|
* [Bootstrap](doc/bootstrap.md#bootstrap)
|
||||||
* [Runlevels](#runlevels)
|
* [Runlevels](#runlevels)
|
||||||
* [Inetd](#inetd)
|
* [Inetd](doc/inetd.md#inetd)
|
||||||
* [Hooks, Callbacks & Plugins](#hooks-callbacks--plugins)
|
* [Hooks, Callbacks & Plugins](doc/plugins.md#hooks-callbacks--plugins)
|
||||||
* [Rebooting & Halting](#rebooting--halting)
|
* [Rebooting & Halting](#rebooting--halting)
|
||||||
* [Commands & Status](#commands--status)
|
* [Commands & Status](#commands--status)
|
||||||
* [Building](#building)
|
* [Building](doc/build.md#building)
|
||||||
* [Running](#running)
|
* [Running](#running)
|
||||||
* [Debugging](#debugging)
|
* [Debugging](#debugging)
|
||||||
* [Origin & References](#origin--references)
|
* [Origin & References](#origin--references)
|
||||||
@@ -28,29 +35,71 @@ Table of Contents
|
|||||||
Introduction
|
Introduction
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Init is the first userland process started by the UNIX kernel, therefore
|
Finit is an EeePC inspired Fastinit clone with [process supervision][1]
|
||||||
it always has PID 1 and is responsible for starting up the rest of the
|
similar to that of D.J. Bernstein's [daemontools][2] and Gerrit Pape's
|
||||||
system.
|
[runit][3]. The focus of Finit is on small and embedded Linux systems,
|
||||||
|
although it is fully usable on server and desktop installations as well.
|
||||||
Finit is a plugin-based init with [process supervision][1] similar to
|
See the [contrib section](contrib/) for Debian and Alpine examples.
|
||||||
that of D.J. Bernstein's [daemontools][2] and Gerrit Pape's [runit][3].
|
|
||||||
The main focus of Finit is on small and embedded GNU/Linux systems, yet
|
|
||||||
fully functional on standard server and desktop installations as well.
|
|
||||||
|
|
||||||
Traditional [SysV init][4] style systems are scripted. For low-resource
|
Traditional [SysV init][4] style systems are scripted. For low-resource
|
||||||
embedded systems this can be quite resource intensive and cause longer
|
embedded systems this is quite resource intensive and often leads to
|
||||||
boot times. Finit is optimized to reduce context switches and forking
|
long boot times. Finit reduces context switches and forking of shell
|
||||||
of processes to provide a very basic bootstrap written entirely in C.
|
scripts to provide a swift [system bootstrap](doc/bootstrap.md) written
|
||||||
|
entirely in C.
|
||||||
|
|
||||||
> Finit basically does everything you need from its `main()` function!
|
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.
|
||||||
|
|
||||||
Hence, there is no `/etc/init.d/rcS` script, or similar, instead Finit
|
**Example /etc/finit.conf:**
|
||||||
reads its configuration from [/etc/finit.conf](#etcfinitconf). This
|
|
||||||
file details what kernel modules to load, programs to run, daemons to
|
|
||||||
supervise, and inetd services to launch on demand.
|
|
||||||
|
|
||||||
See [TroglOS][9] for an example of how to boot a small embedded system
|
```
|
||||||
with Finit.
|
# 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
|
Features
|
||||||
@@ -58,17 +107,36 @@ Features
|
|||||||
|
|
||||||
**Process Supervision**
|
**Process Supervision**
|
||||||
|
|
||||||
Start, monitor and restart processes (daemons) if they fail.
|
Start, monitor and restart services should they fail.
|
||||||
|
|
||||||
|
|
||||||
**Inetd**
|
**Inetd**
|
||||||
|
|
||||||
Finit comes with a built-in `inetd` server. No need to maintain a
|
Finit comes with a built-in [inetd server](doc/inetd.md). No need to
|
||||||
separate config file for services that you want to start on demand.
|
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
|
All inetd services started can be filtered per port and inbound
|
||||||
interface, reducing the need for a full blown firewall.
|
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**
|
**Runlevels**
|
||||||
|
|
||||||
@@ -104,222 +172,25 @@ Extensions and functionality not purely related to what an `/sbin/init`
|
|||||||
needs to start a system are available as a set of plugins that either
|
needs to start a system are available as a set of plugins that either
|
||||||
hook into the boot process or respond to various I/O.
|
hook into the boot process or respond to various I/O.
|
||||||
|
|
||||||
|
For more information, see [doc/plugins.md](doc/plugins.md).
|
||||||
/etc/finit.conf
|
|
||||||
---------------
|
|
||||||
|
|
||||||
Contrary to most other script based init alternatives ([SysV init][4],
|
|
||||||
[upstart][6], [systemd][7], [OpenRC][8], etc.) Finit reads its entire
|
|
||||||
configuration from `/etc/finit.conf`.
|
|
||||||
|
|
||||||
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 before mounting it
|
|
||||||
|
|
||||||
* `module <MODULE>`
|
|
||||||
Load a kernel module, with optional arguments
|
|
||||||
|
|
||||||
* `network <PATH>`
|
|
||||||
Script or program to bring up networking, with optional arguments
|
|
||||||
|
|
||||||
* `runlevel <N>`
|
|
||||||
N is the runlevel number 1-9, where 6 is reserved for reboot.
|
|
||||||
Default is 2.
|
|
||||||
|
|
||||||
* `run [LVLS] /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] /path/to/cmd ARGS -- Optional description`
|
|
||||||
One-shot like 'run', but starts in parallel with the next command
|
|
||||||
|
|
||||||
* `service [LVLS] /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.
|
|
||||||
|
|
||||||
* `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 a directory to run start scripts. All executable
|
|
||||||
files, or scripts, in the directory are called, in alphabetic order.
|
|
||||||
|
|
||||||
* `include <CONF>`
|
|
||||||
Include another configuration file. Absolute path required.
|
|
||||||
|
|
||||||
* `tty [LVLS] <DEV | /path/to/cmd [args]>`
|
|
||||||
Start a getty on the given TTY device DEV, in the given runlevels. If
|
|
||||||
no tty setting is given in `finit.conf`, or if `/bin/sh` is given as
|
|
||||||
argument instead of a device path, a single shell is started on the
|
|
||||||
default console. Useful for really bare-bones systems.
|
|
||||||
|
|
||||||
It is also possible to supply the full command line, with arguments,
|
|
||||||
to your getty. In this case finit will simply use that command.
|
|
||||||
|
|
||||||
See `finit.h` for the `#define GETTY` that is called, along with the
|
|
||||||
default baud rate.
|
|
||||||
|
|
||||||
**Note:** BusyBox getty, used when Finit is built for embedded
|
|
||||||
systems, can take a `DEV` with *or* without `/dev/` prefix. Make
|
|
||||||
sure to call the configure script with `--enable-embedded` if this
|
|
||||||
is what you want.
|
|
||||||
|
|
||||||
* `console <DEV | /path/to/cmd [args]>`
|
|
||||||
Some embedded systems have a dedicated serial console/service port.
|
|
||||||
This command tells finit to not start getty directly, since there may
|
|
||||||
not be anyone there. To save RAM and CPU finit instead displays a
|
|
||||||
friendly message and waits for the user to activate the console with a
|
|
||||||
key press before starting getty. Finit also does some other magic and
|
|
||||||
changes the process name to "console".
|
|
||||||
|
|
||||||
Like the `tty` command, the `console` command can also be used to
|
|
||||||
simply start a UNIX shell, e.g. `/bin/sh`.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
|
|
||||||
/etc/finit.d
|
Runparts & /etc/rc.local
|
||||||
------------
|
------------------------
|
||||||
|
|
||||||
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
|
|
||||||
send `SIGHUP` to PID 1, or call `finit q`. Any service read from this
|
|
||||||
directory is flagged as a dynamic service, so changes to their `.conf`
|
|
||||||
files, or even removal of the files, is detected at `SIGHUP`.
|
|
||||||
|
|
||||||
- If a service's `.conf` file has been removed, the service is stopped.
|
|
||||||
- If the file is modified, the service is reloaded, stopped and started.
|
|
||||||
- If a new service is detected, it is started — respecting runlevels
|
|
||||||
and return values from any callbacks.
|
|
||||||
|
|
||||||
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`!
|
|
||||||
|
|
||||||
|
|
||||||
Runparts
|
|
||||||
--------
|
|
||||||
|
|
||||||
At the end of the boot, when networking and all services are up, finit
|
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,
|
calls its built-in [run-parts(8)][] on the `runparts <DIR>` directory,
|
||||||
if it exists. Similar to how the `/ec/rc.local` file works in most
|
and `/etc/rc.local`, in that order if they exist.
|
||||||
other init daemons, only finit runs a directory of scripts. This
|
|
||||||
replaces the earlier support for a `/usr/sbin/services.sh` script in the
|
|
||||||
original finit.
|
|
||||||
|
|
||||||
|
```shell
|
||||||
|
runparts /etc/rc.d/
|
||||||
|
```
|
||||||
|
|
||||||
Bootstrap
|
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
|
||||||
1. Populate `/dev`
|
hooks in [doc/plugins.md](doc/plugins.md#hooks), and about the system
|
||||||
2. Parse `/etc/finit.conf`
|
bootstrap in [doc/bootstrap.md](doc/bootstrap.md).
|
||||||
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 parameters from `/etc/sysctl.conf`
|
|
||||||
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. Load all `*.conf` files in `/etc/finit.d/` and switch to the active
|
|
||||||
active runlevel, as set in `/etc/finit.conf`, default is 2. Here is
|
|
||||||
where the rest of all tasks and inetd services are started.
|
|
||||||
16. Call 4th level hooks, `HOOK_SVC_UP`
|
|
||||||
17. If `runparts <DIR>` is set, [run-parts(8)][] is called on `<DIR>`
|
|
||||||
18. Call 5th level (last) hooks, `HOOK_SYSTEM_UP`
|
|
||||||
19. Start TTYs defined in `/etc/finit.conf`, or rescue on `/dev/console`
|
|
||||||
20. Enter main monitor loop
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
|
|
||||||
Runlevels
|
Runlevels
|
||||||
@@ -373,197 +244,48 @@ previous runlevel again — that way Finit can both stop old services and
|
|||||||
start any new ones for you, without rebooting the system.
|
start any new ones for you, without rebooting the system.
|
||||||
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
> 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`!
|
|
||||||
|
|
||||||
|
|
||||||
**Internal Services**
|
|
||||||
|
|
||||||
The original `inetd` had a few standard services built-in:
|
|
||||||
|
|
||||||
- time
|
|
||||||
- echo
|
|
||||||
- chargen
|
|
||||||
- discard
|
|
||||||
|
|
||||||
Finit only supports the `time` service. This is realized as a plugin to
|
|
||||||
provide a simple means of testing the inetd functionality stand-alone,
|
|
||||||
but also as a very rudimentary time server for rdate clients.
|
|
||||||
|
|
||||||
The `time.so` inetd plugin is set up as follows. Notice the keyword
|
|
||||||
`internal` which applies to all built-in inetd services:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
inetd time/tcp nowait [2345] internal
|
|
||||||
```
|
|
||||||
|
|
||||||
Then call `rdate` from a remote machine (or use localhost):
|
|
||||||
|
|
||||||
```shell
|
|
||||||
rdate -p <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` …
|
|
||||||
|
|
||||||
|
|
||||||
Hooks, Callbacks & Plugins
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
Finit provides only the bare necessities for starting and supervising
|
|
||||||
processes, with an emphasis on *bare* — for your convenience it does
|
|
||||||
however come with support for hooks, service callbacks and plugins that
|
|
||||||
can used to extend finit with.
|
|
||||||
|
|
||||||
### Plugins
|
|
||||||
|
|
||||||
For your convenience a set of *optional* plugins are available:
|
|
||||||
|
|
||||||
* *alsa-utils.so*: Restore and save ALSA sound settings on
|
|
||||||
startup/shutdown.
|
|
||||||
|
|
||||||
* *bootmisc.so*: Setup necessary files for UTMP, tracks logins at boot.
|
|
||||||
|
|
||||||
* *dbus.so*: Setup and start system message bus, D-Bus, at boot.
|
|
||||||
|
|
||||||
* *hwclock.so*: Restore and save system clock from/to RTC on
|
|
||||||
startup/shutdown.
|
|
||||||
|
|
||||||
* *initctl.so*: Extends finit with a traditional `initctl` functionality.
|
|
||||||
|
|
||||||
* *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.
|
|
||||||
|
|
||||||
* *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.
|
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
### 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_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.
|
|
||||||
|
|
||||||
### Callbacks
|
|
||||||
|
|
||||||
Callback plugins are called by finit right before a process is started,
|
|
||||||
or restarted if it exits. The callback runs as a separate process and
|
|
||||||
receives a pointer to the `svc_t` of the service, with all command line
|
|
||||||
parameters free to modify as needed.
|
|
||||||
|
|
||||||
All the callback needs to do is respond with one of: `SVC_STOP (0)`
|
|
||||||
tells Finit to *not* start the service, `SVC_START (1)` to start the
|
|
||||||
service, or `SVC_RELOAD (2)` to have finit signal the process with
|
|
||||||
`SIGHUP`.
|
|
||||||
|
|
||||||
|
|
||||||
Rebooting & Halting
|
Rebooting & Halting
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
Finit handles `SIGUSR1` and `SIGUSR2` for reboot and halt, and listens
|
Finit is often used on embedded and small Linux systems with BusyBox.
|
||||||
to `/dev/initctl` so system reboot and halt commands also work. The
|
For compatibility with its existing toolset (halt, poweroff, reboot),
|
||||||
latter is implemented in the optional `initctl.so` plugin and can be
|
the following signals have been adopted:
|
||||||
accessed with the traditional `telinit` command line tool, symlinked to
|
|
||||||
`finit`. Hence, if finit is your system init, then `init q` will work
|
* `SIGUSR1`
|
||||||
as the UNIX beards intended.
|
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`.
|
||||||
|
|
||||||
|
Finit also listens to the classic SysV init FIFO, which used to be
|
||||||
|
located in `/dev` but these days default to `/run/initctl`. So existing
|
||||||
|
tools like, `poweroff`, `halt`, `reboot`, and `shutdown` work as
|
||||||
|
expected. Support for this old-style handling is implemented in the
|
||||||
|
optional `initctl.so` plugin and can be accessed with the traditional
|
||||||
|
`telinit` command line tool, symlinked to `finit`. Hence, if finit is
|
||||||
|
your system init, then `init q` will work as the UNIX beards intended.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
~ $ telinit
|
~ $ telinit
|
||||||
@@ -598,13 +320,13 @@ not return until the given command has fully completed.
|
|||||||
Commands:
|
Commands:
|
||||||
debug Toggle Finit (daemon) debug
|
debug Toggle Finit (daemon) debug
|
||||||
help This help text
|
help This help text
|
||||||
emit <EV> Emit event; a predefined event: RELOAD, STOP, START
|
|
||||||
or a custom string matching an event in a service
|
|
||||||
stanza, e.g: GW:UP, IFUP:IFNAME, IFDN:IFNAME. Where
|
|
||||||
IFNAME is the interface name, e.g. eth0
|
|
||||||
reload Reload *.conf in /etc/finit.d/ and activate changes
|
reload Reload *.conf in /etc/finit.d/ and activate changes
|
||||||
runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot
|
runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot
|
||||||
status | show Show status of services
|
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
|
start <JOB|NAME>[:ID] Start service by job# or name, with optional ID
|
||||||
stop <JOB|NAME>[:ID] Stop/Pause a running service by job# or name
|
stop <JOB|NAME>[:ID] Stop/Pause a running service by job# or name
|
||||||
restart <JOB|NAME>[:ID] Restart (stop/start) service by job# or name
|
restart <JOB|NAME>[:ID] Restart (stop/start) service by job# or name
|
||||||
@@ -612,55 +334,6 @@ not return until the given command has fully completed.
|
|||||||
version Show Finit version
|
version Show Finit version
|
||||||
```
|
```
|
||||||
|
|
||||||
The `emit <EV>` command can be used to send events to Finit. Built-in
|
|
||||||
events are: RELOAD, STOP, START. These events act on a lower level than
|
|
||||||
their command counterparts. The `reload` command reloads all `*.conf`
|
|
||||||
files in `/etc/finit.d/` *and* activates the changes, with `emit RELOAD`
|
|
||||||
only the `*.conf` files are reloaded.
|
|
||||||
|
|
||||||
**Note:** The `emit STOP` event is more like "prepare" than "stop".
|
|
||||||
Depending on how the service is declared, `<!>` or not, the service
|
|
||||||
may be stopped, or skipped to be be sent `SIGHUP` later when `emit
|
|
||||||
START` is issued.
|
|
||||||
|
|
||||||
To achieve the same result as `initctl reload` emit all three events:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
~ $ initctl emit "RELOAD,STOP,START"
|
|
||||||
```
|
|
||||||
|
|
||||||
On an embedded system this can be used when changing complete system
|
|
||||||
configuration. Between `STOP` and `START` reset/change any hardware
|
|
||||||
or kernel settings required to be in effect before new services are
|
|
||||||
started.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# 1. Update/Change/Generate all daemon configuration files
|
|
||||||
~ $ …
|
|
||||||
|
|
||||||
# 2. Update /etc/finit.d/*.conf
|
|
||||||
~ $ …
|
|
||||||
|
|
||||||
# 3. Prepare finit, stop all old/previous services
|
|
||||||
~ $ initctl emit "RELOAD,STOP"
|
|
||||||
|
|
||||||
# 4. Reconfigure hardware, interfaces/bridges/VLANs, etc.
|
|
||||||
~ $ brctl …
|
|
||||||
~ $ vconfig …
|
|
||||||
~ $ ifconfig …
|
|
||||||
|
|
||||||
# 5. Complete finit reload by starting all new services and
|
|
||||||
# SIGHUP any changed services
|
|
||||||
~ $ initctl emit "START"
|
|
||||||
```
|
|
||||||
|
|
||||||
The `emit <EV>` command can also be used to emit custom events. In
|
|
||||||
fact, the event is a simple string. Declare a list of events in a
|
|
||||||
service stanza: `service … <GW:UP,IFUP:eth0>` to reload (`SIGHUP`) a
|
|
||||||
service when recieving the `"GW:UP"` or `"IFUP:eth0"` strings. If a
|
|
||||||
service cannot handle reload and must be stopped-started, simply add an
|
|
||||||
exclamation mark first: `service … <!GW:UP,IFUP:eth0>`.
|
|
||||||
|
|
||||||
The `<!>` notation to a service stanza can be used empty, then it will
|
The `<!>` notation to a service stanza can be used empty, then it will
|
||||||
apply to `reload` and `runlevel` commands. I.e., when a service's
|
apply to `reload` and `runlevel` commands. I.e., when a service's
|
||||||
`.conf` file has been changed Finit will stop and start it instead. If
|
`.conf` file has been changed Finit will stop and start it instead. If
|
||||||
@@ -671,8 +344,7 @@ behaviour, but not all daemons support this, unfortunately.
|
|||||||
**Note:** even though it is possible to start services not belonging to
|
**Note:** even though it is possible to start services not belonging to
|
||||||
the current runlevel these services will not be respawned automatically
|
the current runlevel these services will not be respawned automatically
|
||||||
by Finit if they exit (crash). Hence, if the runlevel is 2, the below
|
by Finit if they exit (crash). Hence, if the runlevel is 2, the below
|
||||||
Dropbear SSH service will not be restarted if it, for some reason,
|
Dropbear SSH service will not be restarted if it is killed or exits.
|
||||||
exits.
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
~ $ initctl status -v
|
~ $ initctl status -v
|
||||||
@@ -688,140 +360,24 @@ exits.
|
|||||||
6:2 inetd 0 [345] /sbin/dropbear allow *:22 deny eth0
|
6:2 inetd 0 [345] /sbin/dropbear allow *:22 deny eth0
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
Building
|
|
||||||
--------
|
|
||||||
|
|
||||||
Finit comes with a lightweight configure script to control which
|
|
||||||
features to enable an plugins to build. Below are a few of the main
|
|
||||||
switches to configure:
|
|
||||||
|
|
||||||
* `--prefix=`: Base prefix path for all files, except `--sbindir` and
|
|
||||||
`--sysconfdir`. Used in concert with the `DESTDIR` variable.
|
|
||||||
|
|
||||||
Defaults to `/usr`.
|
|
||||||
|
|
||||||
* `--sbindir=`: Path to where resulting binaries should install to. Used
|
|
||||||
in concert with the `DESTDIR` variable.
|
|
||||||
|
|
||||||
Defaults to `/sbin`.
|
|
||||||
|
|
||||||
* `--sysconfdir=`: Path to where finit configuration files should
|
|
||||||
install to. Used in concert with the `DESTDIR` variable.
|
|
||||||
|
|
||||||
Defaults to `/etc`, but is currently unused.
|
|
||||||
|
|
||||||
* `--plugindir=`: Absolute path to where finit should search for
|
|
||||||
dynamically loadable plugins at runtime. Can also be controlled
|
|
||||||
with the `--libdir` switch.
|
|
||||||
|
|
||||||
Defaults to `/lib/finit/plugins`.
|
|
||||||
|
|
||||||
* `--with-plugins=`: List of stock finit plugins to build and install.
|
|
||||||
The build system adds `.o` or `.so` extension to the listed plugins
|
|
||||||
depending on the `--enable-static` switch. Hence, list the plugins
|
|
||||||
*without* their extension.
|
|
||||||
|
|
||||||
* `--enable-embedded`: Target finit for BusyBox getty and mdev instead
|
|
||||||
of a standard Linux distribution with GNU tools and udev.
|
|
||||||
|
|
||||||
* `--enable-debug`: Add GDB symbols and disable code optimization.
|
|
||||||
|
|
||||||
* `--enable-static`: Build Finit statically. The plugins will be
|
|
||||||
built-in (.o files) instead. Note: very untested and not all plugins
|
|
||||||
can be built static. It is recommended to use `--with-plugins` and
|
|
||||||
select only the plugins really needed.
|
|
||||||
|
|
||||||
* `--disable-inetd`: Disables the built-in inetd server.
|
|
||||||
|
|
||||||
The following environment variables are checked by the makefiles and
|
|
||||||
control what is built and where resulting binaries are installed.
|
|
||||||
|
|
||||||
* `ROOTDIR=`: Top directory for building complete system, used in pretty
|
|
||||||
printing at build time.
|
|
||||||
|
|
||||||
* `VERSION=`: Defaults to the currently released version of finit,
|
|
||||||
e.g., 1.3 but can be overridden by packagers using this variable to
|
|
||||||
add a suffix or completely alter the version.
|
|
||||||
|
|
||||||
* `CFLAGS=`: Default `CFLAGS` are inherited from the environment.
|
|
||||||
|
|
||||||
* `CPPFLAGS=`: Default `CPPFLAGS` are inherited from the environment.
|
|
||||||
|
|
||||||
* `LDFLAGS=`: Default `LDFLAGS` are inherited from the environment.
|
|
||||||
|
|
||||||
* `LDLIBS=`: Default `LIBLIBS` are inherited from the environment.
|
|
||||||
|
|
||||||
* `DESTDIR=`: Used by packagers and distributions when building a
|
|
||||||
relocatable bundle of files. Always prepended to the `prefix`
|
|
||||||
destination directory.
|
|
||||||
|
|
||||||
**Example**
|
|
||||||
|
|
||||||
First, unpack the archive:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ tar xfJ finit-1.13.tar.xz
|
|
||||||
$ cd finit-1.13/
|
|
||||||
```
|
|
||||||
|
|
||||||
Then configure, build and install:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ ./configure --with-plugins="initctl hwclock"
|
|
||||||
$ make
|
|
||||||
CC finit.o
|
|
||||||
CC conf.o
|
|
||||||
CC helpers.o
|
|
||||||
CC sig.o
|
|
||||||
CC svc.o
|
|
||||||
CC plugin.o
|
|
||||||
CC strlcpy.o
|
|
||||||
LINK finit
|
|
||||||
CC plugins/initctl.o
|
|
||||||
PLUGIN plugins/initctl.so
|
|
||||||
CC plugins/hwclock.o
|
|
||||||
PLUGIN plugins/hwclock.so
|
|
||||||
$
|
|
||||||
$ DESTDIR=/tmp/finit make install
|
|
||||||
INSTALL /tmp/finit/sbin/finit
|
|
||||||
INSTALL /tmp/finit/lib/finit/plugins/initctl.so
|
|
||||||
INSTALL /tmp/finit/lib/finit/plugins/hwclock.so
|
|
||||||
```
|
|
||||||
|
|
||||||
In this example the [finit-1.13.tar.xz][10] 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.
|
|
||||||
|
|
||||||
For more configure flags, see <kbd>./configure --help</kbd>
|
|
||||||
|
|
||||||
**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`.
|
|
||||||
|
|
||||||
|
|
||||||
Running
|
Running
|
||||||
-------
|
-------
|
||||||
|
|
||||||
The default install does not setup finit as the system default
|
Having successfully [built Finit](doc/build.md) it may now be time to
|
||||||
`/sbin/init`, neither does it setup an initial `/etc/finit.conf`.
|
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.
|
||||||
|
|
||||||
It is assumed that users of finit are competent enough to either setup
|
So either change the symlink, or change your boot loader (GRUB, LOADLIN,
|
||||||
finit as their default `/sbin/init` or alter their respective Grub,
|
LILO, U-Boot/Barebox or RedBoot) configuration to append the following
|
||||||
LOADLIN, LILO, U-Boot/Barebox or RedBoot boot loader configuration to
|
to the kernel command line:
|
||||||
give the kernel the following extra command line:
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
init=/sbin/finit
|
init=/sbin/finit
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Remember to also set up an initial `/etc/finit.conf` before rebooting!
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
@@ -848,17 +404,13 @@ Finit is developed and maintained by [Joachim Nilsson][] at [GitHub][].
|
|||||||
Please file bug reports, clone it, or send pull requests for bug fixes
|
Please file bug reports, clone it, or send pull requests for bug fixes
|
||||||
and proposed extensions.
|
and proposed extensions.
|
||||||
|
|
||||||
|
|
||||||
[1]: https://en.wikipedia.org/wiki/Process_supervision
|
[1]: https://en.wikipedia.org/wiki/Process_supervision
|
||||||
[2]: http://cr.yp.to/daemontools.html
|
[2]: http://cr.yp.to/daemontools.html
|
||||||
[3]: http://smarden.org/runit/
|
[3]: http://smarden.org/runit/
|
||||||
[4]: http://en.wikipedia.org/wiki/Init
|
[4]: http://en.wikipedia.org/wiki/Init
|
||||||
[5]: http://en.wikipedia.org/wiki/Runlevel
|
[5]: http://en.wikipedia.org/wiki/Runlevel
|
||||||
[6]: http://upstart.ubuntu.com/
|
|
||||||
[7]: http://www.freedesktop.org/wiki/Software/systemd/
|
|
||||||
[8]: http://www.gentoo.org/proj/en/base/openrc/
|
|
||||||
[9]: https://github.com/troglobit/troglos
|
[9]: https://github.com/troglobit/troglos
|
||||||
[10]: ftp://troglobit.com/finit/finit-1.13.tar.xz
|
|
||||||
[TCP Wrappers]: https://en.wikipedia.org/wiki/TCP_Wrapper
|
|
||||||
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
||||||
[original finit]: http://helllabs.org/finit/
|
[original finit]: http://helllabs.org/finit/
|
||||||
[EeePC fastinit]: http://wiki.eeeuser.com/boot_process:the_boot_process
|
[EeePC fastinit]: http://wiki.eeeuser.com/boot_process:the_boot_process
|
||||||
|
|||||||
@@ -18,29 +18,29 @@ very low dependency on external packages.
|
|||||||
General
|
General
|
||||||
-------
|
-------
|
||||||
|
|
||||||
* Add compile-time support for running `/bin/sh` instead of `getty`
|
* Add halt/poweroff/shutdown symlinks to finit and convert reboot, but
|
||||||
* Add `!` or `[wait <pidfile>]` to service directive to let finit pause
|
only install symlinks if these tools don't already exist.
|
||||||
and wait for a pidfile before starting processes -- both at boot and
|
* Step state machine at shutdown instead of killing, same as shifting to
|
||||||
when starting processes in a runlevel.
|
runlevel 0 or 6, then call external (newly installed?) tool to reboot.
|
||||||
* Allow custom reload for processes like libreSwan's pluto
|
* Add support for timed shutdown in Finit, including cancelled shutdown.
|
||||||
|
* SysV init and systemd use SIGUSR1 to restart their FIFO/D-Bus. Add
|
||||||
service [2345] <!gw,if:eth0,reload:'starter reload'> /sbin/pluto
|
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.
|
* Allow process callbacks to be scripts.
|
||||||
* Add support for a pipe/popen where we can listen for `STOP`, `START`
|
* Add support for a pipe/popen where we can listen for `STOP`, `START`
|
||||||
and `RELOAD` on `STDOUT` from a script ... call it for example
|
and `RELOAD` on `STDOUT` from a script ... call it for example
|
||||||
`.monitor=` in `svc_t` ... the script named as the basename of the
|
`.monitor=` in `svc_t` ... the script named as the basename of the
|
||||||
service it monitors + `.sh`.
|
service it monitors + `.sh`.
|
||||||
* Add support for `/etc/sysctl.d`
|
|
||||||
* Implement `initctl stop|start|restart|reload|status <SVC>` and
|
* Implement `initctl stop|start|restart|reload|status <SVC>` and
|
||||||
`service <SVC> stop|start|restart|reload|status` on top
|
`service <SVC> stop|start|restart|reload|status` on top
|
||||||
|
* Add support for JSON output, or similar, from `initctl show`, e.g.
|
||||||
|
`initctl show --json`
|
||||||
* Add PRE and POST hooks for when switching between runlevels
|
* Add PRE and POST hooks for when switching between runlevels
|
||||||
* Make sure to install `queue.h` to `$(PREFIX)/include/finit/queue.h`
|
|
||||||
* Move `finit.conf` "check" command to plugin which checks `/etc/fstab`
|
|
||||||
instead. This is the de-facto practice. But keep the check command
|
|
||||||
for really low-end systems w/o `/etc/fstab`.
|
|
||||||
* Add support for generic events (strings or ubus events) that are passed
|
|
||||||
verbatim (?) to the service stanza definitions.
|
|
||||||
|
|
||||||
|
|
||||||
Init
|
Init
|
||||||
@@ -55,6 +55,8 @@ to achieve compatibility would be to add a plugin to finit which reads
|
|||||||
Inetd
|
Inetd
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
Add support for throttling connections.
|
||||||
|
|
||||||
Optimize interface filtering by using socket filter. The functions
|
Optimize interface filtering by using socket filter. The functions
|
||||||
`inet_*_peek()` and `inetd_is_allowed()` used for interace filtering
|
`inet_*_peek()` and `inetd_is_allowed()` used for interace filtering
|
||||||
should be possible to rewrite as socket filters.
|
should be possible to rewrite as socket filters.
|
||||||
@@ -109,7 +111,7 @@ Support for monitoring the health of the system and its processes.
|
|||||||
- If a process is not heard from within its subscribed period time
|
- If a process is not heard from within its subscribed period time
|
||||||
reboot system or restart process.
|
reboot system or restart process.
|
||||||
- Add client libwdt library, inspired by old Westermo API and the
|
- Add client libwdt library, inspired by old Westermo API and the
|
||||||
[libwdt] API published in the [Fritz!Box source dump], take for
|
[libwdt][] API published in the [Fritz!Box source dump][], take for
|
||||||
instance the `fritzbox7170-source-files-04.87-tar.gz` drop and see
|
instance the `fritzbox7170-source-files-04.87-tar.gz` drop and see
|
||||||
the `GPL-release_kernel.tgz` in `drivers/char/avm_new/` for the
|
the `GPL-release_kernel.tgz` in `drivers/char/avm_new/` for the
|
||||||
kernel driver, and the `LGPL-GPL-release_target_tools.tgz` in `wdt/`
|
kernel driver, and the `LGPL-GPL-release_target_tools.tgz` in `wdt/`
|
||||||
@@ -134,16 +136,10 @@ Documentation
|
|||||||
|
|
||||||
* Write man pages for finit and `finit.conf`, steal from the excellent
|
* Write man pages for finit and `finit.conf`, steal from the excellent
|
||||||
`pimd` man pages ...
|
`pimd` man pages ...
|
||||||
* Update Debian `finit.conf` example with runlevels, `tty/console` and
|
* Add simple, *very* simple, `finit-simple.conf` example. To illustrate
|
||||||
dependency handling for Debian 8 (the dreaded systemd release).
|
how close Finit3 still is to the original easy-to-use Finit0 :)
|
||||||
|
|
||||||
|
|
||||||
Investigation
|
|
||||||
-------------
|
|
||||||
|
|
||||||
* [FHS changes](http://askubuntu.com/questions/57297/why-has-var-run-been-migrated-to-run)
|
|
||||||
affecting runtime status, plugins, etc.
|
|
||||||
|
|
||||||
[libwdt]: http://www.wehavemorefun.de/fritzbox/Libwdt.so
|
[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/
|
[Fritz!Box source dump]: ftp://ftp.avm.de/fritz.box/fritzbox.fon_wlan_7170/x_misc/opensrc/
|
||||||
|
|
||||||
|
|||||||
@@ -29,24 +29,24 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
#include <lite/lite.h>
|
||||||
|
#include <uev/uev.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
|
#include "cond.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
#include "sig.h"
|
#include "sig.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
|
|
||||||
#include "libite/lite.h"
|
|
||||||
#include "libuev/uev.h"
|
|
||||||
|
|
||||||
uev_t api_watcher;
|
uev_t api_watcher;
|
||||||
|
|
||||||
/* Allowed characters in job/id/name */
|
/* Allowed characters in job/id/name */
|
||||||
static int isallowed(int ch)
|
static int isallowed(int ch)
|
||||||
{
|
{
|
||||||
return isalnum(ch) || isspace(ch) || ch == ':';
|
return isprint(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sanitize user input, make sure to NUL terminate. */
|
/* Sanitize user input, make sure to NUL terminate. */
|
||||||
@@ -113,14 +113,31 @@ static int call(int (*action)(svc_t *), char *buf, size_t len)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int service_pause(svc_t *svc)
|
static int service_block(svc_t *svc)
|
||||||
{
|
{
|
||||||
return service_stop(svc, SVC_PAUSED_STATE);
|
svc_block(svc);
|
||||||
|
service_step(svc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_start (char *buf, size_t len) { return call(service_start, buf, len); }
|
static int service_unblock(svc_t *svc)
|
||||||
static int do_pause (char *buf, size_t len) { return call(service_pause, buf, len); }
|
{
|
||||||
static int do_reload (char *buf, size_t len) { return call(service_reload, buf, len); }
|
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); }
|
static int do_restart(char *buf, size_t len) { return call(service_restart, buf, len); }
|
||||||
|
|
||||||
#ifndef INETD_DISABLED
|
#ifndef INETD_DISABLED
|
||||||
@@ -155,9 +172,7 @@ typedef struct {
|
|||||||
} ev_t;
|
} ev_t;
|
||||||
|
|
||||||
ev_t ev_list[] = {
|
ev_t ev_list[] = {
|
||||||
{ "RELOAD", conf_reload_dynamic },
|
{ "RELOAD", service_reload_dynamic },
|
||||||
{ "STOP", service_stop_dynamic },
|
|
||||||
{ "START", service_start_dynamic },
|
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -175,9 +190,13 @@ static int do_handle_event(char *event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: iterate over all services' events before failing. */
|
if (event[0] == '-')
|
||||||
|
cond_clear(&event[1]);
|
||||||
return -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)
|
static int do_handle_emit(char *buf, size_t len)
|
||||||
@@ -229,7 +248,7 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rq.magic != INIT_MAGIC || len != sizeof(rq)) {
|
if (rq.magic != INIT_MAGIC || len != sizeof(rq)) {
|
||||||
_e("Invalid initctl request.");
|
_e("Invalid initctl request");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,7 +257,7 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
|
|||||||
switch (rq.runlevel) {
|
switch (rq.runlevel) {
|
||||||
case '0':
|
case '0':
|
||||||
_d("Halting system (SIGUSR2)");
|
_d("Halting system (SIGUSR2)");
|
||||||
do_shutdown(SIGUSR2);
|
do_shutdown(SHUT_OFF);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
@@ -255,7 +274,7 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
|
|||||||
|
|
||||||
case '6':
|
case '6':
|
||||||
_d("Rebooting system (SIGUSR1)");
|
_d("Rebooting system (SIGUSR1)");
|
||||||
do_shutdown(SIGUSR1);
|
do_shutdown(SHUT_REBOOT);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -267,9 +286,9 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
|
|||||||
case INIT_CMD_DEBUG:
|
case INIT_CMD_DEBUG:
|
||||||
debug = !debug;
|
debug = !debug;
|
||||||
if (debug)
|
if (debug)
|
||||||
verbose = 1;
|
silent = 0;
|
||||||
else
|
else
|
||||||
verbose = quiet ? 0 : VERBOSE_MODE;
|
silent = quiet ? 1 : SILENT_MODE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_RELOAD: /* 'init q' and 'initctl reload' */
|
case INIT_CMD_RELOAD: /* 'init q' and 'initctl reload' */
|
||||||
@@ -284,10 +303,6 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
|
|||||||
result = do_pause(rq.data, sizeof(rq.data));
|
result = do_pause(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_RELOAD_SVC:
|
|
||||||
result = do_reload(rq.data, sizeof(rq.data));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case INIT_CMD_RESTART_SVC:
|
case INIT_CMD_RESTART_SVC:
|
||||||
result = do_restart(rq.data, sizeof(rq.data));
|
result = do_restart(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
@@ -302,8 +317,13 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
|
|||||||
result = do_handle_emit(rq.data, sizeof(rq.data));
|
result = do_handle_emit(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case INIT_CMD_GET_RUNLEVEL:
|
||||||
|
rq.runlevel = runlevel;
|
||||||
|
result = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
case INIT_CMD_ACK:
|
case INIT_CMD_ACK:
|
||||||
_d("Client failed reading ACK.");
|
_d("Client failed reading ACK");
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -317,7 +337,7 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
|
|||||||
rq.cmd = INIT_CMD_ACK;
|
rq.cmd = INIT_CMD_ACK;
|
||||||
len = write(sd, &rq, sizeof(rq));
|
len = write(sd, &rq, sizeof(rq));
|
||||||
if (len != sizeof(rq))
|
if (len != sizeof(rq))
|
||||||
_d("Failed sending ACK/NACK back to client.");
|
_d("Failed sending ACK/NACK back to client");
|
||||||
}
|
}
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
@@ -332,7 +352,7 @@ int api_init(uev_ctx_t *ctx)
|
|||||||
.sun_path = INIT_SOCKET,
|
.sun_path = INIT_SOCKET,
|
||||||
};
|
};
|
||||||
|
|
||||||
sd = socket(AF_UNIX, SOCK_STREAM, 0);
|
sd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||||
if (-1 == sd) {
|
if (-1 == sd) {
|
||||||
_pe("Failed starting external API socket");
|
_pe("Failed starting external API socket");
|
||||||
return 1;
|
return 1;
|
||||||
@@ -345,7 +365,8 @@ int api_init(uev_ctx_t *ctx)
|
|||||||
if (-1 == listen(sd, 10))
|
if (-1 == listen(sd, 10))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
return uev_io_init(ctx, &api_watcher, cb, NULL, sd, UEV_READ);
|
if (!uev_io_init(ctx, &api_watcher, cb, NULL, sd, UEV_READ))
|
||||||
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
_pe("Failed intializing API socket");
|
_pe("Failed intializing API socket");
|
||||||
@@ -353,10 +374,14 @@ error:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int api_exit(void)
|
||||||
|
{
|
||||||
|
return shutdown(api_watcher.fd, SHUT_RDWR) ||
|
||||||
|
close(api_watcher.fd);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
autoreconf -W portability -vifm
|
||||||
@@ -27,38 +27,70 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <lite/lite.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "libite/lite.h"
|
|
||||||
|
|
||||||
static int do_send(int cmd, int runlevel)
|
static int do_send(struct init_request *rq)
|
||||||
{
|
{
|
||||||
int fd;
|
static int fd = -1;
|
||||||
int result = 255;
|
int result = 255;
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
|
|
||||||
|
if (fd == -1) {
|
||||||
|
if (!fexist(FINIT_FIFO)) {
|
||||||
|
fprintf(stderr, "%s does not support %s!\n", __progname, 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 = {
|
struct init_request rq = {
|
||||||
.magic = INIT_MAGIC,
|
.magic = INIT_MAGIC,
|
||||||
.cmd = cmd,
|
.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,
|
.runlevel = runlevel,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!fexist(FINIT_FIFO)) {
|
return set_env(runlevel) || do_send(&rq);
|
||||||
fprintf(stderr, "%s does not support %s!\n", __progname, 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;
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* telinit q | telinit <0-9> */
|
/* telinit q | telinit <0-9> */
|
||||||
@@ -66,11 +98,17 @@ static int usage(int rc)
|
|||||||
{
|
{
|
||||||
fprintf(stderr, "Usage: %s [OPTIONS] [q | Q | 0-9]\n\n"
|
fprintf(stderr, "Usage: %s [OPTIONS] [q | Q | 0-9]\n\n"
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
" -h, --help This help text\n\n"
|
" -h, --help This help text\n"
|
||||||
" -V, --version Show Finit version\n\n"
|
" -V, --version Show Finit version\n\n"
|
||||||
"Commands:\n"
|
"Commands:\n"
|
||||||
" q | Q Reload *.conf in /etc/finit.d/, like SIGHUP\n"
|
" 0 Power-off the system, same as initctl poweroff\n"
|
||||||
" 0 - 9 Change runlevel: 0 halt, 6 reboot\n\n", __progname);
|
" 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", __progname);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -84,7 +122,7 @@ int client(int argc, char *argv[])
|
|||||||
{NULL, 0, NULL, 0}
|
{NULL, 0, NULL, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
verbose = 0;
|
silent = 1;
|
||||||
while ((c = getopt_long(argc, argv, "h?v", long_options, NULL)) != EOF) {
|
while ((c = getopt_long(argc, argv, "h?v", long_options, NULL)) != EOF) {
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case 'v':
|
case 'v':
|
||||||
@@ -99,12 +137,14 @@ int client(int argc, char *argv[])
|
|||||||
if (optind < argc) {
|
if (optind < argc) {
|
||||||
int req = (int)argv[optind][0];
|
int req = (int)argv[optind][0];
|
||||||
|
|
||||||
/* Compat: 'init <0-9>' */
|
|
||||||
if (isdigit(req))
|
if (isdigit(req))
|
||||||
return do_send(INIT_CMD_RUNLVL, req);
|
return set_runlevel(req);
|
||||||
|
|
||||||
if (req == 'q' || req == 'Q')
|
if (req == 'q' || req == 'Q')
|
||||||
return do_send(INIT_CMD_RELOAD, 0);
|
return do_reload();
|
||||||
|
|
||||||
|
if (req == 's' || req == 'S')
|
||||||
|
return set_runlevel(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return usage(1);
|
return usage(1);
|
||||||
@@ -112,7 +152,6 @@ int client(int argc, char *argv[])
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
# Top directory for building complete system, fall back to this directory
|
# Top directory for building complete system, fall back to this directory
|
||||||
ROOTDIR ?= $(TOPDIR)
|
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.
|
# 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.*
|
JUNK = *~ *.bak *.map .*.d *.d DEADJOE semantic.cache *.gdb *.elf core core.*
|
||||||
MAKE := @$(MAKE)
|
MAKE := @$(MAKE)
|
||||||
MAKEFLAGS = --no-print-directory --silent
|
MAKEFLAGS = --no-print-directory --silent
|
||||||
CHECK := cppcheck $(CPPFLAGS) --quiet --enable=all
|
CHECK := cppcheck $(CPPFLAGS) --quiet --enable=all
|
||||||
INSTALL := install --backup=off
|
INSTALL := install --backup=off
|
||||||
STRIPINST := $(INSTALL) -s --strip-program=$(CROSS)strip -m 0755
|
STRIPINST := $(INSTALL) $(STRIPARGS)
|
||||||
ARFLAGS := crus
|
ARFLAGS := crus
|
||||||
|
|
||||||
export libdir plugindir incdir ROOTDIR CPPFLAGS LDFLAGS LDLIBS STATIC
|
export libdir plugindir incdir ROOTDIR CPPFLAGS LDFLAGS LDLIBS STATIC
|
||||||
@@ -15,13 +18,13 @@ export libdir plugindir incdir ROOTDIR CPPFLAGS LDFLAGS LDLIBS STATIC
|
|||||||
|
|
||||||
# Override default implicit rules
|
# Override default implicit rules
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
@printf " CC $(subst $(ROOTDIR)/,,$(shell pwd)/$@)\n"
|
@printf " CC $(subst $(ROOTDIR)/,,$(shell pwd)/$@)\n"
|
||||||
@$(CC) $(CFLAGS) $(CPPFLAGS) -c -MMD -MP -o $@ $<
|
@$(CC) $(CFLAGS) $(CPPFLAGS) -c -MMD -MP -o $@ $<
|
||||||
|
|
||||||
%: %.o
|
%: %.o
|
||||||
@printf " LINK $(subst $(ROOTDIR)/,,$(shell pwd)/$@)\n"
|
@printf " LINK $(subst $(ROOTDIR)/,,$(shell pwd)/$@)\n"
|
||||||
@$(CC) $(CFLAGS) $(LDFLAGS) -Wl,-Map,$@.map -o $@ $^ $(LDLIBS$(LDLIBS-$(@)))
|
@$(CC) $(CFLAGS) $(LDFLAGS) -Wl,-Map,$@.map -o $@ $^ $(LDLIBS$(LDLIBS-$(@)))
|
||||||
|
|
||||||
%.so: %.o
|
%.so: %.o
|
||||||
@printf " PLUGIN $(subst $(ROOTDIR)/,,$(shell pwd)/$@)\n"
|
@printf " PLUGIN $(subst $(ROOTDIR)/,,$(shell pwd)/$@)\n"
|
||||||
@$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
|
@$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
|
||||||
|
|||||||
@@ -0,0 +1,135 @@
|
|||||||
|
/* 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);
|
||||||
|
if (!name)
|
||||||
|
return;
|
||||||
|
|
||||||
|
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, 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:
|
||||||
|
*/
|
||||||
@@ -23,14 +23,15 @@
|
|||||||
|
|
||||||
#include "config.h" /* Generated by configure script */
|
#include "config.h" /* Generated by configure script */
|
||||||
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#include <lite/lite.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
|
#include "cond.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
#include "libite/lite.h"
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
#define MATCH_CMD(l, c, x) \
|
#define MATCH_CMD(l, c, x) \
|
||||||
@@ -39,40 +40,22 @@
|
|||||||
static int parse_conf(char *file);
|
static int parse_conf(char *file);
|
||||||
|
|
||||||
|
|
||||||
static char *strip_line(char *line)
|
|
||||||
{
|
|
||||||
char *ptr;
|
|
||||||
|
|
||||||
/* Trim leading whitespace */
|
|
||||||
while (*line && isblank(*line))
|
|
||||||
line++;
|
|
||||||
|
|
||||||
/* Strip any comment at end of line */
|
|
||||||
ptr = line;
|
|
||||||
while (*ptr && *ptr != '#')
|
|
||||||
ptr++;
|
|
||||||
*ptr = 0;
|
|
||||||
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
|
|
||||||
void conf_parse_cmdline(void)
|
void conf_parse_cmdline(void)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
char line[LINE_SIZE];
|
char line[LINE_SIZE];
|
||||||
|
|
||||||
if ((fp = fopen("/proc/cmdline", "r")) != NULL) {
|
fp = fopen("/proc/cmdline", "r");
|
||||||
|
if (fp) {
|
||||||
fgets(line, sizeof(line), fp);
|
fgets(line, sizeof(line), fp);
|
||||||
_d("Kernel command line: %s", line);
|
_d("Kernel command line: %s", line);
|
||||||
|
|
||||||
if (strstr(line, "finit_debug") || strstr(line, "--debug"))
|
if (strstr(line, "finit_debug") || strstr(line, "--debug"))
|
||||||
debug = 1;
|
debug = 1;
|
||||||
#ifdef KERNEL_QUIET
|
|
||||||
if (!debug && strstr(line, "quiet"))
|
if (!debug && strstr(line, "quiet"))
|
||||||
quiet = 1;
|
quiet = 1;
|
||||||
else
|
|
||||||
quiet = 0;
|
|
||||||
#endif
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,7 +96,7 @@ int conf_parse_runlevels(char *runlevels)
|
|||||||
return bitmask;
|
return bitmask;
|
||||||
}
|
}
|
||||||
|
|
||||||
void conf_parse_events(svc_t *svc, char *events)
|
void conf_parse_cond(svc_t *svc, char *cond)
|
||||||
{
|
{
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
char *ptr;
|
char *ptr;
|
||||||
@@ -124,13 +107,14 @@ void conf_parse_events(svc_t *svc, char *events)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* By default we assume UNIX daemons support SIGHUP */
|
/* By default we assume UNIX daemons support SIGHUP */
|
||||||
svc->sighup = 1;
|
if (svc_is_daemon(svc))
|
||||||
|
svc->sighup = 1;
|
||||||
|
|
||||||
if (!events)
|
if (!cond)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* First character must be '!' if SIGHUP is not supported. */
|
/* First character must be '!' if SIGHUP is not supported. */
|
||||||
ptr = events;
|
ptr = cond;
|
||||||
if (ptr[i] == '!') {
|
if (ptr[i] == '!') {
|
||||||
svc->sighup = 0;
|
svc->sighup = 0;
|
||||||
ptr++;
|
ptr++;
|
||||||
@@ -140,13 +124,98 @@ void conf_parse_events(svc_t *svc, char *events)
|
|||||||
i++;
|
i++;
|
||||||
ptr[i] = 0;
|
ptr[i] = 0;
|
||||||
|
|
||||||
if (i >= sizeof(svc->events)) {
|
if (i >= sizeof(svc->cond)) {
|
||||||
FLOG_WARN("Too long event list in declaration of %s: %s", svc->cmd, ptr);
|
logit(LOG_WARNING, "Too long event list in declaration of %s: %s", svc->cmd, ptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
svc->state = SVC_CONDHALT_STATE;
|
strlcpy(svc->cond, ptr, sizeof(svc->cond));
|
||||||
strlcpy(svc->events, ptr, sizeof(svc->events));
|
}
|
||||||
|
|
||||||
|
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, 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)
|
static void parse_static(char *line)
|
||||||
@@ -301,6 +370,22 @@ static void parse_dynamic(char *line, time_t mtime)
|
|||||||
#endif
|
#endif
|
||||||
return;
|
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)
|
static int parse_conf_dynamic(char *file, time_t mtime)
|
||||||
@@ -319,6 +404,7 @@ static int parse_conf_dynamic(char *file, time_t mtime)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
chomp(line);
|
chomp(line);
|
||||||
|
tabstospaces(line);
|
||||||
_d("dyn conf: %s", line);
|
_d("dyn conf: %s", line);
|
||||||
|
|
||||||
parse_dynamic(line, mtime);
|
parse_dynamic(line, mtime);
|
||||||
@@ -359,14 +445,16 @@ static int parse_conf(char *file)
|
|||||||
strcat(line, " ");
|
strcat(line, " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose)
|
if (!silent)
|
||||||
print(0, "Loading %sconfiguration", line);
|
print(0, "Loading %sconfiguration", line);
|
||||||
while (!feof(fp)) {
|
while (!feof(fp)) {
|
||||||
if (!fgets(line, sizeof(line), fp))
|
if (!fgets(line, sizeof(line), fp))
|
||||||
continue;
|
continue;
|
||||||
chomp(line);
|
|
||||||
|
|
||||||
|
chomp(line);
|
||||||
|
tabstospaces(line);
|
||||||
_d("conf: %s", line);
|
_d("conf: %s", line);
|
||||||
|
|
||||||
parse_static(line);
|
parse_static(line);
|
||||||
parse_dynamic(line, 0);
|
parse_dynamic(line, 0);
|
||||||
}
|
}
|
||||||
@@ -425,28 +513,14 @@ void conf_reload_dynamic(void)
|
|||||||
|
|
||||||
int conf_parse_config(void)
|
int conf_parse_config(void)
|
||||||
{
|
{
|
||||||
int result;
|
|
||||||
|
|
||||||
username = strdup(DEFUSER);
|
username = strdup(DEFUSER);
|
||||||
hostname = strdup(DEFHOST);
|
hostname = strdup(DEFHOST);
|
||||||
|
|
||||||
result = parse_conf(FINIT_CONF);
|
return parse_conf(FINIT_CONF);
|
||||||
if (!tty_num()) {
|
|
||||||
char *fallback = FALLBACK_SHELL;
|
|
||||||
|
|
||||||
if (console)
|
|
||||||
fallback = console;
|
|
||||||
|
|
||||||
tty_register(fallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
void conf_parse_cmdline (void);
|
void conf_parse_cmdline (void);
|
||||||
int conf_parse_runlevels (char *runlevels);
|
int conf_parse_runlevels (char *runlevels);
|
||||||
void conf_parse_events (svc_t *svc, char *events);
|
void conf_parse_cond (svc_t *svc, char *cond);
|
||||||
int conf_parse_config (void);
|
int conf_parse_config (void);
|
||||||
void conf_reload_dynamic (void);
|
void conf_reload_dynamic (void);
|
||||||
|
|
||||||
@@ -36,7 +36,6 @@ void conf_reload_dynamic (void);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
@@ -1,451 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
# Simple home brew configure script, not as fancy as GNU Autotools
|
|
||||||
#
|
|
||||||
# --with-plugins="time initctl"
|
|
||||||
# --enable-static
|
|
||||||
# --disable-inetd
|
|
||||||
# --disable-plugins
|
|
||||||
#
|
|
||||||
# This creates a configuration where Finit is built statically, with the
|
|
||||||
# time and initctl plugins built-in, and no inetd support.
|
|
||||||
#
|
|
||||||
|
|
||||||
# Setup defaults if undefined
|
|
||||||
defaults()
|
|
||||||
{
|
|
||||||
heading=${heading:='"Finit v" VERSION'}
|
|
||||||
prefix=${prefix:="/usr"}
|
|
||||||
sysconfdir=${sysconfdir:="/etc"}
|
|
||||||
sbindir=${sbindir:="/sbin"}
|
|
||||||
libdir=${libdir:="/lib"}
|
|
||||||
pdir="finit/plugins"
|
|
||||||
plugindir=${plugindir:="$libdir/$pdir"}
|
|
||||||
# The initctl FIFO, should probably be in /run, not /dev
|
|
||||||
fifo=${fifo:="/dev/initctl"}
|
|
||||||
random=${random:="/var/lib/urandom/random-seed"}
|
|
||||||
conf="finit.conf"
|
|
||||||
config=${config:="$sysconfdir/$conf"}
|
|
||||||
confdir=${confdir:="finit.d"}
|
|
||||||
rcsd=${rcsd:="$sysconfdir/$confdir"}
|
|
||||||
console=${console:='_PATH_CONSOLE'}
|
|
||||||
shell=${shell:='_PATH_BSHELL'}
|
|
||||||
defuser=${defuser:="root"}
|
|
||||||
defhost=${defhost:="noname"}
|
|
||||||
runlevel=${runlevel:=2}
|
|
||||||
debug=${debug:=0}
|
|
||||||
embedded=${embedded:=0}
|
|
||||||
dbus=${dbus:=0}
|
|
||||||
remount=${remount:=0}
|
|
||||||
inetd=${inetd:=1}
|
|
||||||
verbose=${verbose:=1}
|
|
||||||
kernel_quiet=${kernel_quiet:=1}
|
|
||||||
static=${static:=0}
|
|
||||||
disable_plugins=${disable_plugins:=0}
|
|
||||||
}
|
|
||||||
|
|
||||||
result()
|
|
||||||
{
|
|
||||||
echo
|
|
||||||
echo "Finit configuration"
|
|
||||||
echo "========================================================================"
|
|
||||||
echo "Heading : $heading"
|
|
||||||
echo "Install prefix : $prefix"
|
|
||||||
echo "System config dir : $sysconfdir"
|
|
||||||
echo "Super user bindir : $sbindir"
|
|
||||||
echo "Shared libs dir : $libdir"
|
|
||||||
echo "Plugins dir : $plugindir"
|
|
||||||
echo "FIFO : $fifo"
|
|
||||||
echo "Config file : $config"
|
|
||||||
echo "rcs.d/ directory : $rcsd"
|
|
||||||
echo "Default console : $console"
|
|
||||||
# echo "Fallback shell : $shell"
|
|
||||||
if [ x"$sysroot" != x"" ]; then
|
|
||||||
echo "Swap rootfs to : $sysroot"
|
|
||||||
fi
|
|
||||||
echo "Default username : $defuser"
|
|
||||||
echo "Default hostname : $defhost"
|
|
||||||
echo "Default runlevel : $runlevel"
|
|
||||||
|
|
||||||
if [ $debug -ne 0 ]; then
|
|
||||||
echo "Debug : ENABLED"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $embedded -ne 0 ]; then
|
|
||||||
echo "Embedded target : YES (BusyBox getty, and mdev instead of udev)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $dbus -ne 0 ]; then
|
|
||||||
echo "D-Bus : YES, remember to install dbus.so plugin as well!"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $remount -ne 0 ]; then
|
|
||||||
echo "Remount ROOT fs : YES, / will be remounted as read-write at bootstrap"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ x"$random" != x"" ]; then
|
|
||||||
echo "Random seed : $random"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $inetd -ne 0 ]; then
|
|
||||||
echo "Inetd : Built-in"
|
|
||||||
else
|
|
||||||
echo "Inetd : DISABLED"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ x"$libite" = x"" ]; then
|
|
||||||
echo "Libite (LITE) : Built-in"
|
|
||||||
else
|
|
||||||
echo "Libite (LITE) : $libite + {/lib, /include}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ x"$libuev" = x"" ]; then
|
|
||||||
echo "LibuEv : Built-in"
|
|
||||||
else
|
|
||||||
echo "LibuEv : $libuev + {/lib, /include}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $verbose -ne 1 ]; then
|
|
||||||
echo "Quiet Finit : YES"
|
|
||||||
else
|
|
||||||
echo "Quiet Finit : NO, verbose output (default)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $kernel_quiet -eq 1 ]; then
|
|
||||||
echo "Kernel Quiet : YES, silent after inital boot (default)"
|
|
||||||
else
|
|
||||||
echo "Kernel Quiet : NO"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $static -ne 0 ]; then
|
|
||||||
echo "Static Finit : YES"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $disable_plugins -eq 1 ]; then
|
|
||||||
echo "Plugins : DISABLED"
|
|
||||||
else
|
|
||||||
if [ x"$plugins" = x"" ]; then
|
|
||||||
echo "Plugins : ALL"
|
|
||||||
else
|
|
||||||
echo "Plugins : $plugins"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
echo
|
|
||||||
}
|
|
||||||
|
|
||||||
usage()
|
|
||||||
{
|
|
||||||
defaults
|
|
||||||
|
|
||||||
echo "Run this script to configure finit for your operating system."
|
|
||||||
echo
|
|
||||||
echo "Usage: $0 [ARG]"
|
|
||||||
echo
|
|
||||||
echo " --help This help text"
|
|
||||||
echo " --prefix=PREFIX Set installation prefix, default '$prefix'"
|
|
||||||
echo " --sysconfdir=CONF Set conf dir, default '$sysconfdir'"
|
|
||||||
echo " --sbindir=SBIN Set sbin dir, default '$sbindir'"
|
|
||||||
echo " --libdir=LIB Set lib dir, default '$libdir'"
|
|
||||||
echo " --plugindir=DIR Set plugin dir, default '\$libdir/$pdir'"
|
|
||||||
echo
|
|
||||||
echo " --with-fifo=FIFO FIFO for initctl plugin, default '$fifo'"
|
|
||||||
echo " --with-config=CONFIG Finit CONFIG file, default '\$sysconfdir/$conf'"
|
|
||||||
echo " --with-heading=GREET Display GREET instead of Finit version at boot"
|
|
||||||
echo " --with-randomseed=SEED Seed /dev/urandom at boot from SEED. Usually found in"
|
|
||||||
echo " standard Linux systems at $random"
|
|
||||||
echo " which is also the default. Requires urandom plugin!"
|
|
||||||
echo " --with-plugins=\"a b c\" Build plugins 'a', 'b' and 'c', either as dynamic .so"
|
|
||||||
echo " files, or as built-in if --enable-static is given,"
|
|
||||||
echo " defaults to all plugins. Exclude extension!"
|
|
||||||
echo " --with-rcsd=RCSD Finit RCSD directory, default '\$sysconfdir/$confdir'"
|
|
||||||
echo " --with-console=DEV Console to use, default: /dev/console"
|
|
||||||
# echo " --with-shell=PATH Fallback shell to use, default: /bin/sh"
|
|
||||||
echo " --with-sysroot=PATH Some distributions keep a different (writable) rootfs"
|
|
||||||
echo " that is used at runtime, usually /sysroot or /mnt"
|
|
||||||
echo " --with-username=USER User for 'startx' .conf option, default: root"
|
|
||||||
echo " --with-hostname=NAME Hostname, if /etc/hostname is missing, default: noname"
|
|
||||||
echo " --with-runlevel=LEVEL Runlevel to switch to after bootstrap (S), default: 2"
|
|
||||||
echo " --with-libite=PATH Look for libite in PATH/include and PATH/lib"
|
|
||||||
echo " This is for disabling the use of built-in libite."
|
|
||||||
echo " --with-libuev=PATH Look for libuEv in PATH/include and PATH/lib"
|
|
||||||
echo " This is for disabling the use of built-in libuEv."
|
|
||||||
echo
|
|
||||||
echo " --enable-embedded Embedded defaults, BusBox getty, mdev etc."
|
|
||||||
echo " --enable-dbus Enable D-Bus plugin. Note: install plugin as well!"
|
|
||||||
echo " --enable-rw-rootfs Remount / as read-write at bootstrap, not for embedded"
|
|
||||||
echo " --enable-debug Enable debug flags, '-O0, -g'"
|
|
||||||
echo " --enable-quiet Quiet mode, reduce screen output to absolute minimum"
|
|
||||||
echo " --enable-static Link statically. This disables a few features."
|
|
||||||
echo " --disable-inetd Disable inetd support if not needed."
|
|
||||||
echo " --disable-kernel-quiet Disable kernel cmdline quiet, default enabled."
|
|
||||||
echo " --disable-plugins Disable plugins"
|
|
||||||
echo
|
|
||||||
echo "The build system also supports external CFLAGS, CPPFLAGS, LDFLAGS, LDLIBS,"
|
|
||||||
echo "and DESTDIR, useful for packaging or cross-compiling."
|
|
||||||
echo
|
|
||||||
echo "Example:"
|
|
||||||
echo " ./configure --enable-embedded --with-plugins=\"initctl tty\""
|
|
||||||
echo
|
|
||||||
echo "Report bugs to https://github.com/troglobit/finit/issues"
|
|
||||||
echo
|
|
||||||
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
while [ "$*" != "" ]; do
|
|
||||||
opt=`expr "$1" : "--\([^=]*\)=.*"`
|
|
||||||
arg=`expr "$1" : "--[^=]*=\(.*\)"`
|
|
||||||
if [ -z "$opt" ]; then
|
|
||||||
opt=`expr "$1" : "--\(.*\)"`
|
|
||||||
fi
|
|
||||||
shift
|
|
||||||
|
|
||||||
case $opt in
|
|
||||||
prefix)
|
|
||||||
prefix="$arg"
|
|
||||||
;;
|
|
||||||
|
|
||||||
sysconfdir)
|
|
||||||
sysconfdir="$arg"
|
|
||||||
;;
|
|
||||||
|
|
||||||
sbindir)
|
|
||||||
sbindir="$arg"
|
|
||||||
;;
|
|
||||||
|
|
||||||
libdir)
|
|
||||||
libdir="$arg"
|
|
||||||
;;
|
|
||||||
|
|
||||||
plugindir)
|
|
||||||
plugindir="$arg"
|
|
||||||
;;
|
|
||||||
|
|
||||||
with-fifo)
|
|
||||||
fifo="$arg"
|
|
||||||
;;
|
|
||||||
|
|
||||||
with-config)
|
|
||||||
config="$arg"
|
|
||||||
;;
|
|
||||||
|
|
||||||
with-heading)
|
|
||||||
heading="\"$arg\""
|
|
||||||
;;
|
|
||||||
|
|
||||||
with-randomseed)
|
|
||||||
random="$arg"
|
|
||||||
;;
|
|
||||||
|
|
||||||
with-plugins)
|
|
||||||
plugins="$arg"
|
|
||||||
;;
|
|
||||||
|
|
||||||
with-rcsd)
|
|
||||||
rcsd="$arg"
|
|
||||||
;;
|
|
||||||
|
|
||||||
with-console)
|
|
||||||
console="\"$arg\""
|
|
||||||
;;
|
|
||||||
|
|
||||||
with-shell)
|
|
||||||
shell="\"$arg\""
|
|
||||||
;;
|
|
||||||
|
|
||||||
with-sysroot)
|
|
||||||
sysroot="$arg"
|
|
||||||
;;
|
|
||||||
|
|
||||||
with-usename)
|
|
||||||
defuser="$arg"
|
|
||||||
;;
|
|
||||||
|
|
||||||
with-hostname)
|
|
||||||
defhost="$arg"
|
|
||||||
;;
|
|
||||||
|
|
||||||
with-runlevel)
|
|
||||||
runlevel="$arg"
|
|
||||||
;;
|
|
||||||
|
|
||||||
with-libite)
|
|
||||||
libite="$arg"
|
|
||||||
;;
|
|
||||||
|
|
||||||
with-libuev)
|
|
||||||
libuev="$arg"
|
|
||||||
;;
|
|
||||||
|
|
||||||
enable-debug)
|
|
||||||
debug=1
|
|
||||||
;;
|
|
||||||
|
|
||||||
enable-embedded)
|
|
||||||
embedded=1
|
|
||||||
;;
|
|
||||||
|
|
||||||
enable-dbus)
|
|
||||||
dbus=1
|
|
||||||
;;
|
|
||||||
|
|
||||||
enable-rw-rootfs)
|
|
||||||
remount=1
|
|
||||||
;;
|
|
||||||
|
|
||||||
enable-quiet)
|
|
||||||
verbose=0
|
|
||||||
;;
|
|
||||||
|
|
||||||
enable-static)
|
|
||||||
static=1
|
|
||||||
;;
|
|
||||||
|
|
||||||
disable-inetd)
|
|
||||||
inetd=0
|
|
||||||
;;
|
|
||||||
|
|
||||||
disable-kernel-quiet)
|
|
||||||
kernel_quiet=0
|
|
||||||
;;
|
|
||||||
|
|
||||||
disable-plugins)
|
|
||||||
disable_plugins=1
|
|
||||||
;;
|
|
||||||
|
|
||||||
help)
|
|
||||||
usage
|
|
||||||
;;
|
|
||||||
|
|
||||||
*)
|
|
||||||
echo "Unknown option: $opt"
|
|
||||||
usage
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
# If no arguments given to configure script, use defaults
|
|
||||||
defaults
|
|
||||||
result
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
echo "# Generated by finit configure script." > config.mk
|
|
||||||
echo "prefix = $prefix" >> config.mk
|
|
||||||
echo "sysconfdir = $sysconfdir" >> config.mk
|
|
||||||
echo "sbindir = $sbindir" >> config.mk
|
|
||||||
echo "libdir = $libdir" >> config.mk
|
|
||||||
echo "plugindir = $plugindir" >> config.mk
|
|
||||||
echo "incdir = \$(prefix)/include/finit" >> config.mk
|
|
||||||
echo "datadir = \$(prefix)/share/doc/finit" >> config.mk
|
|
||||||
echo "mandir = \$(prefix)/share/man/man8" >> config.mk
|
|
||||||
echo "FINIT_RCSD = $rcsd" >> config.mk
|
|
||||||
|
|
||||||
if [ $inetd -eq 0 ]; then
|
|
||||||
echo >> config.mk
|
|
||||||
echo "OBJS := \$(filter-out inetd.o, \$(OBJS))" >> config.mk
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo >> config.mk
|
|
||||||
if [ $debug -eq 1 ]; then
|
|
||||||
echo "CFLAGS += -O0 -g" >> config.mk
|
|
||||||
else
|
|
||||||
echo "CFLAGS += -O2" >> config.mk
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo >> config.mk
|
|
||||||
if [ $static -ne 0 ]; then
|
|
||||||
echo "STATIC = 1" >> config.mk
|
|
||||||
echo "LDFLAGS += -static" >> config.mk
|
|
||||||
echo "CPPFLAGS += -DENABLE_STATIC" >> config.mk
|
|
||||||
echo "PLUGINS = \"\"" >> config.mk
|
|
||||||
if [ $disable_plugins -ne 1 ]; then
|
|
||||||
if [ x"$plugins" != x"" ]; then
|
|
||||||
echo "OBJS += \$(addsuffix .o, \$(addprefix plugins/, $plugins))" >> config.mk
|
|
||||||
else
|
|
||||||
echo "tmp += \$(wildcard plugins/*.c)" >> config.mk
|
|
||||||
echo "OBJS += \$(tmp:.c=.o)" >> config.mk
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "STATIC = 0" >> config.mk
|
|
||||||
echo "LDFLAGS += -rdynamic" >> config.mk
|
|
||||||
echo "LDLIBS += -ldl" >> config.mk
|
|
||||||
if [ x"$plugins" != x"" ]; then
|
|
||||||
echo "PLUGINS = \$(addsuffix .so, $plugins)" >> config.mk
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ x"$libite" != x"" ]; then
|
|
||||||
echo "LIBITE = $libite" >> config.mk
|
|
||||||
echo "CPPFLAGS += -I\$(LIBITE)/include" >> config.mk
|
|
||||||
echo "LDFLAGS += -L\$(LIBITE)/lib" >> config.mk
|
|
||||||
echo "LDLIBS += -l:libite.so.2" >> config.mk
|
|
||||||
else
|
|
||||||
echo "LDFLAGS += -L\$(TOPDIR)/libite" >> config.mk
|
|
||||||
echo "LDLIBS += -lite" >> config.mk
|
|
||||||
echo "DEPLIBS += libite/libite.a" >> config.mk
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ x"$libuev" != x"" ]; then
|
|
||||||
echo "LIBUEV = $libuev" >> config.mk
|
|
||||||
echo "CPPFLAGS += -I\$(LIBUEV)/include" >> config.mk
|
|
||||||
echo "LDFLAGS += -L\$(LIBUEV)/lib" >> config.mk
|
|
||||||
echo "LDLIBS += -l:libuev.so.1" >> config.mk
|
|
||||||
else
|
|
||||||
echo "LDFLAGS += -L\$(TOPDIR)/libuev" >> config.mk
|
|
||||||
echo "LDLIBS += -luev" >> config.mk
|
|
||||||
echo "DEPLIBS += libuev/libuev.a" >> config.mk
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo >> config.mk
|
|
||||||
echo "export libdir plugindir incdir" >> config.mk
|
|
||||||
echo "export CFLAGS CPPFLAGS LDFLAGS LDLIBS STATIC" >> config.mk
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
echo "/* Generated by finit configure script. */" > config.h
|
|
||||||
echo >> config.h
|
|
||||||
echo "#ifndef FINIT_CONFIG_H_" >> config.h
|
|
||||||
echo "#define FINIT_CONFIG_H_" >> config.h
|
|
||||||
echo >> config.h
|
|
||||||
echo "#define INIT_HEADING $heading" >> config.h
|
|
||||||
echo "#define VERBOSE_MODE $verbose" >> config.h
|
|
||||||
echo "#define KERNEL_QUIET $kernel_quiet" >> config.h
|
|
||||||
if [ $embedded -eq 1 ]; then
|
|
||||||
echo "#define EMBEDDED_SYSTEM 1" >> config.h
|
|
||||||
echo "#define SETUP_DEVFS \"/sbin/mdev -s\"" >> config.h
|
|
||||||
echo "#define GETTY \"/sbin/getty -L\"" >> config.h
|
|
||||||
echo "#define GETTY_BUSYBOX 1" >> config.h
|
|
||||||
echo "#define BAUDRATE 115200" >> config.h
|
|
||||||
else
|
|
||||||
echo "#define SETUP_DEVFS \"/sbin/udevd --daemon\"" >> config.h
|
|
||||||
echo "#define GETTY \"/sbin/getty -8\"" >> config.h
|
|
||||||
echo "#define GETTY_AGETTY 1" >> config.h
|
|
||||||
echo "#define BAUDRATE 38400" >> config.h
|
|
||||||
fi
|
|
||||||
if [ $remount -eq 1 ]; then
|
|
||||||
echo "#define REMOUNT_ROOTFS 1" >> config.h
|
|
||||||
fi
|
|
||||||
if [ $dbus -eq 1 ]; then
|
|
||||||
echo "#define HAVE_DBUS 1" >> config.h
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $inetd -eq 0 ]; then
|
|
||||||
echo "#define INETD_DISABLED" >> config.h
|
|
||||||
fi
|
|
||||||
echo "#define FINIT_FIFO \"$fifo\"" >> config.h
|
|
||||||
echo "#define FINIT_CONF \"$config\"" >> config.h
|
|
||||||
echo "#define FINIT_RCSD \"$rcsd\"" >> config.h
|
|
||||||
echo "#define CONSOLE $console" >> config.h
|
|
||||||
echo "#define FALLBACK_SHELL $shell" >> config.h
|
|
||||||
if [ x"$sysroot" != x"" ]; then
|
|
||||||
echo "#define SYSROOT \"$sysroot\"" >> config.h
|
|
||||||
fi
|
|
||||||
echo "#define PLUGIN_PATH \"$plugindir\"" >> config.h
|
|
||||||
if [ x"$random" != x"" ]; then
|
|
||||||
echo "#define RANDOMSEED \"$random\"" >> config.h
|
|
||||||
fi
|
|
||||||
echo "#define DEFUSER \"$defuser\"" >> config.h
|
|
||||||
echo "#define DEFHOST \"$defhost\"" >> config.h
|
|
||||||
echo "#define RUNLEVEL $runlevel" >> config.h
|
|
||||||
|
|
||||||
echo >> config.h
|
|
||||||
echo "#endif /* FINIT_CONFIG_H_ */" >> config.h
|
|
||||||
+210
@@ -0,0 +1,210 @@
|
|||||||
|
AC_INIT(Finit, 3.0-rc1, 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.4.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(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(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(shell,
|
||||||
|
AS_HELP_STRING([--with-shell=PATH], [Fallback shell to use, default: /bin/sh]),
|
||||||
|
[shell=$withval], [shell=/bin/sh])
|
||||||
|
|
||||||
|
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_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])])
|
||||||
|
|
||||||
|
### 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, 0, [Will print stopping/starting/etc messages at runtime])
|
||||||
|
], [
|
||||||
|
AC_DEFINE(QUIET_MODE, 1, [Silent at runtime, after initial boot, default])])
|
||||||
|
|
||||||
|
### 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_shell" != "xno"], [
|
||||||
|
AS_IF([test "x$shell" = "xyes"], [
|
||||||
|
shell=/bin/sh])])
|
||||||
|
AC_DEFINE_UNQUOTED(FALLBACK_SHELL, "$shell", [Used if no login getty])
|
||||||
|
|
||||||
|
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"])
|
||||||
|
|
||||||
|
# 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
|
||||||
@@ -1,7 +1,12 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# Alternative boot method for other distributions than Debian 6.0
|
# Alternative boot method for other distributions than Debian 6.0
|
||||||
# Place this file in a /etc/finit.d/ directory. At boot finit will
|
# Place this file in a /etc/start.d/ directory and add the following
|
||||||
# run all files, using its built-in run_parts(), in that directory.
|
# 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
|
# Here we chain load Debian /etc/rcS.d and /etc/rc2.d directories
|
||||||
# in sequence using the standard run-parts tool.
|
# in sequence using the standard run-parts tool.
|
||||||
@@ -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:
|
||||||
|
-->
|
||||||
+216
@@ -0,0 +1,216 @@
|
|||||||
|
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`.
|
||||||
|
|
||||||
|
|
||||||
|
/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:
|
||||||
|
-->
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
@@ -1,241 +0,0 @@
|
|||||||
/* Event aggregator, also serves as event cache, remembering GW and IFUP states
|
|
||||||
*
|
|
||||||
* 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 "config.h" /* Generated by configure script */
|
|
||||||
#include "libite/lite.h"
|
|
||||||
|
|
||||||
#include "finit.h"
|
|
||||||
#include "service.h"
|
|
||||||
|
|
||||||
struct ifc {
|
|
||||||
LIST_ENTRY(ifc) link;
|
|
||||||
|
|
||||||
int updown;
|
|
||||||
char ifname[IFNAMSIZ];
|
|
||||||
};
|
|
||||||
|
|
||||||
static int gwup = 0;
|
|
||||||
static LIST_HEAD(, ifc) ifcache = LIST_HEAD_INITIALIZER();
|
|
||||||
|
|
||||||
|
|
||||||
static int cache_gw(char *updown)
|
|
||||||
{
|
|
||||||
int oldgw = gwup;
|
|
||||||
|
|
||||||
if (!strncasecmp(updown, "UP", 2))
|
|
||||||
gwup = 1;
|
|
||||||
else
|
|
||||||
gwup = 0;
|
|
||||||
|
|
||||||
return (oldgw == gwup) ? 0 : gwup == 0 ? -1 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct ifc *find_if(char *ifname)
|
|
||||||
{
|
|
||||||
struct ifc *entry;
|
|
||||||
|
|
||||||
LIST_FOREACH(entry, &ifcache, link) {
|
|
||||||
if (!strncmp(entry->ifname, ifname, sizeof(entry->ifname)))
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int alloc_if(char *ifname, int updown)
|
|
||||||
{
|
|
||||||
struct ifc *entry = calloc(1, sizeof(struct ifc));
|
|
||||||
|
|
||||||
if (!entry) {
|
|
||||||
_pe("Failed recording interface event");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
_d("Creating new node for %s", ifname);
|
|
||||||
entry->updown = updown;
|
|
||||||
strlcpy(entry->ifname, ifname, sizeof(entry->ifname));
|
|
||||||
LIST_INSERT_HEAD(&ifcache, entry, link);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int free_if(char *ifname)
|
|
||||||
{
|
|
||||||
struct ifc *entry = find_if(ifname);
|
|
||||||
|
|
||||||
if (!entry)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
LIST_REMOVE(entry, link);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cache_if(char *ifname, int updown)
|
|
||||||
{
|
|
||||||
struct ifc *entry = find_if(ifname);
|
|
||||||
|
|
||||||
if (entry) {
|
|
||||||
int old = entry->updown;
|
|
||||||
|
|
||||||
entry->updown = updown;
|
|
||||||
return old == updown ? 0 : updown ? 1 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return alloc_if(ifname, updown);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* System events like GW/IF are cached, this function caters to that
|
|
||||||
* Returns: 0 if no change, -1 on condition low, +1 on condition high
|
|
||||||
*/
|
|
||||||
static int event_cache(char *msg)
|
|
||||||
{
|
|
||||||
if (!strncmp(msg, "GW:", 3))
|
|
||||||
return cache_gw(&msg[3]);
|
|
||||||
|
|
||||||
if (!strncmp(msg, "IFUP:", 5))
|
|
||||||
return cache_if(&msg[5], 1);
|
|
||||||
|
|
||||||
if (!strncmp(msg, "IFDN:", 5))
|
|
||||||
return cache_if(&msg[5], 0);
|
|
||||||
|
|
||||||
if (!strncmp(msg, "IFDEL:", 6))
|
|
||||||
return free_if(&msg[6]);
|
|
||||||
|
|
||||||
return 0; /* No chnage, unknown event. */
|
|
||||||
}
|
|
||||||
|
|
||||||
int event_cache_gw(void)
|
|
||||||
{
|
|
||||||
return gwup;
|
|
||||||
}
|
|
||||||
|
|
||||||
int event_cache_if(char *ifname)
|
|
||||||
{
|
|
||||||
struct ifc *entry = find_if(ifname);
|
|
||||||
|
|
||||||
if (!entry)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return entry->updown;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int has_events(char *events)
|
|
||||||
{
|
|
||||||
return events && events[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
static int matches_event(char *events, char *event)
|
|
||||||
{
|
|
||||||
return strcasestr(events, event) ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int event_service_cond(char *events)
|
|
||||||
{
|
|
||||||
int cond = 1;
|
|
||||||
char *msg;
|
|
||||||
char temp[MAX_ARG_LEN];
|
|
||||||
|
|
||||||
/* No required events, condition satisfied */
|
|
||||||
if (!has_events(events))
|
|
||||||
return cond;
|
|
||||||
|
|
||||||
strlcpy(temp, events, sizeof(temp));
|
|
||||||
msg = strtok(temp, ",");
|
|
||||||
while (msg) {
|
|
||||||
_d("Looking for %s (in %s), cond %d", msg, events, cond);
|
|
||||||
|
|
||||||
if (!strncmp(msg, "GW", 2))
|
|
||||||
cond &= event_cache_gw();
|
|
||||||
else if (!strncmp(msg, "IFUP:", 5))
|
|
||||||
cond &= event_cache_if(&msg[5]);
|
|
||||||
else if (!strncmp(msg, "IFDN:", 5))
|
|
||||||
cond &= event_cache_if(&msg[5]);
|
|
||||||
else
|
|
||||||
_e("Unknown event %s, discarding.", msg);
|
|
||||||
|
|
||||||
_d("=> cond %d", cond);
|
|
||||||
msg = strtok(NULL, ",");
|
|
||||||
}
|
|
||||||
|
|
||||||
return cond;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Dispatch an event
|
|
||||||
*
|
|
||||||
* Called by initctl (via api.c) or plugins/netlink.so
|
|
||||||
* May also cache for future reference.
|
|
||||||
*/
|
|
||||||
void event_dispatch(char *msg)
|
|
||||||
{
|
|
||||||
int change;
|
|
||||||
svc_t *svc;
|
|
||||||
|
|
||||||
if (!msg) {
|
|
||||||
_e("Invalid message received.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_d("%s", msg);
|
|
||||||
change = event_cache(msg);
|
|
||||||
if (!change) {
|
|
||||||
_d("Nothing to do");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Iterate over svc_t and call service_restart() for event matches */
|
|
||||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
|
||||||
if (svc->type != SVC_TYPE_SERVICE ||
|
|
||||||
!service_enabled(svc, 1, NULL) ||
|
|
||||||
!has_events(svc->events) ||
|
|
||||||
!matches_event(svc->events, msg)) {
|
|
||||||
_d("No match for %s in service %s", msg, svc->cmd);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (change == 1) {
|
|
||||||
_d("%s matches <%s> %s (re)starting ...", msg, svc->events, svc->cmd);
|
|
||||||
if (!svc->pid) {
|
|
||||||
service_start(svc);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (svc->sighup)
|
|
||||||
service_reload(svc);
|
|
||||||
else
|
|
||||||
service_restart(svc);
|
|
||||||
} else { /* change == -1 */
|
|
||||||
if (svc->pid && !event_service_cond(svc->events))
|
|
||||||
service_stop(svc, SVC_CONDHALT_STATE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Local Variables:
|
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
|
||||||
* c-file-style: "linux"
|
|
||||||
* End:
|
|
||||||
*/
|
|
||||||
@@ -26,25 +26,20 @@
|
|||||||
|
|
||||||
#include <ctype.h> /* isdigit() */
|
#include <ctype.h> /* isdigit() */
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
#include <lite/lite.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "sig.h"
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "libite/lite.h"
|
#include "sig.h"
|
||||||
|
#include "utmp-api.h"
|
||||||
|
|
||||||
#define NUM_ARGS 16
|
#define NUM_ARGS 16
|
||||||
|
|
||||||
|
int getty(char *tty, char *baud, char *term, char *user);
|
||||||
|
|
||||||
|
|
||||||
/* Wait for process completion, returns status of waitpid(2) syscall */
|
/* Wait for process completion, returns status of waitpid(2) syscall */
|
||||||
int complete(char *cmd, int pid)
|
int complete(char *cmd, int pid)
|
||||||
@@ -53,9 +48,9 @@ int complete(char *cmd, int pid)
|
|||||||
|
|
||||||
if (waitpid(pid, &status, 0) == -1) {
|
if (waitpid(pid, &status, 0) == -1) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
_e("Caught unblocked signal waiting for %s, aborting.", cmd);
|
_e("Caught unblocked signal waiting for %s, aborting", cmd);
|
||||||
else if (errno == ECHILD)
|
else if (errno == ECHILD)
|
||||||
_e("Caught SIGCHLD waiting for %s, aborting.", cmd);
|
_e("Caught SIGCHLD waiting for %s, aborting", cmd);
|
||||||
else
|
else
|
||||||
_e("Failed starting %s, error %d: %s", cmd, errno, strerror (errno));
|
_e("Failed starting %s, error %d: %s", cmd, errno, strerror (errno));
|
||||||
|
|
||||||
@@ -95,11 +90,7 @@ int run(char *cmd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
args[i] = NULL;
|
args[i] = NULL;
|
||||||
#if 0
|
|
||||||
_e("Splitting: '%s' =>", cmd);
|
|
||||||
for (i = 0; args[i]; i++)
|
|
||||||
_e("\t%s", args[i]);
|
|
||||||
#endif
|
|
||||||
if (i == NUM_ARGS && args[i]) {
|
if (i == NUM_ARGS && args[i]) {
|
||||||
_e("Command too long: %s", cmd);
|
_e("Command too long: %s", cmd);
|
||||||
free(backup);
|
free(backup);
|
||||||
@@ -172,7 +163,7 @@ int run_interactive(char *cmd, char *fmt, ...)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose && fmt) {
|
if (!silent && fmt) {
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
vsnprintf(line, sizeof(line), fmt, ap);
|
vsnprintf(line, sizeof(line), fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
@@ -204,7 +195,7 @@ int run_interactive(char *cmd, char *fmt, ...)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose && fmt)
|
if (!silent && fmt)
|
||||||
print_result(status);
|
print_result(status);
|
||||||
|
|
||||||
/* Dump any results of cmd on stderr after we've printed [ OK ] or [FAIL] */
|
/* Dump any results of cmd on stderr after we've printed [ OK ] or [FAIL] */
|
||||||
@@ -224,64 +215,25 @@ int run_interactive(char *cmd, char *fmt, ...)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_t run_getty(char *cmd, char *args[], int console)
|
pid_t run_getty(char *tty, char *speed, char *term, int console)
|
||||||
{
|
{
|
||||||
pid_t pid = fork();
|
pid_t pid;
|
||||||
|
|
||||||
|
pid = fork();
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
int fd;
|
/* Reset signal handlers that were set by the parent process */
|
||||||
char c;
|
|
||||||
|
|
||||||
if (console) {
|
|
||||||
/* Detach from initial controlling TTY */
|
|
||||||
vhangup();
|
|
||||||
|
|
||||||
close(STDERR_FILENO);
|
|
||||||
close(STDOUT_FILENO);
|
|
||||||
close(STDIN_FILENO);
|
|
||||||
|
|
||||||
/* Attach TTY to console */
|
|
||||||
fd = open(CONSOLE, O_RDWR);
|
|
||||||
if (fd != STDIN_FILENO)
|
|
||||||
exit(1);
|
|
||||||
|
|
||||||
dup2(0, STDIN_FILENO);
|
|
||||||
dup2(0, STDOUT_FILENO);
|
|
||||||
dup2(0, STDERR_FILENO);
|
|
||||||
|
|
||||||
prctl(PR_SET_NAME, "console", 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
sig_unblock();
|
sig_unblock();
|
||||||
|
|
||||||
setsid();
|
setsid();
|
||||||
|
|
||||||
if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0)
|
/* Set INIT_PROCESS UTMP entry */
|
||||||
_pe("Failed TIOCSCTTY");
|
utmp_set_init(tty, 0);
|
||||||
|
|
||||||
while (!fexist(SYNC_SHUTDOWN)) {
|
|
||||||
static const char msg[] = "\nPlease press Enter to activate this console.";
|
|
||||||
|
|
||||||
if (fexist(SYNC_STOPPED)) {
|
|
||||||
sleep(1);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (console) {
|
|
||||||
(void)write(STDERR_FILENO, msg, sizeof(msg));
|
|
||||||
while (read(STDIN_FILENO, &c, 1) == 1 && c != '\n')
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (fexist(SYNC_STOPPED))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
execv(cmd, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (console)
|
if (console)
|
||||||
close(fd);
|
prctl(PR_SET_NAME, "console", 0, 0, 0);
|
||||||
|
else
|
||||||
|
prctl(PR_SET_NAME, "finit-getty", 0, 0, 0);
|
||||||
|
|
||||||
exit(0);
|
_exit(getty(tty, speed, term, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
return pid;
|
return pid;
|
||||||
@@ -351,7 +303,6 @@ int run_parts(char *dir, char *cmd)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
@@ -24,10 +24,17 @@
|
|||||||
|
|
||||||
#include "config.h" /* Generated by configure script */
|
#include "config.h" /* Generated by configure script */
|
||||||
|
|
||||||
#include <sys/mount.h>
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <glob.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#ifdef HAVE_FSTAB_H
|
||||||
|
#include <fstab.h>
|
||||||
|
#endif
|
||||||
|
#include <mntent.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
#include <sys/stat.h> /* umask(), mkdir() */
|
#include <sys/stat.h> /* umask(), mkdir() */
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <lite/lite.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
@@ -36,13 +43,13 @@
|
|||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
#include "sig.h"
|
#include "sig.h"
|
||||||
|
#include "sm.h"
|
||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
#include "libite/lite.h"
|
#include "utmp-api.h"
|
||||||
#include "inetd.h"
|
|
||||||
|
|
||||||
int debug = 0;
|
int debug = 0;
|
||||||
int quiet = KERNEL_QUIET; /* Delayed disable of verbose mode. */
|
int quiet = QUIET_MODE; /* Delayed disable of silent mode. */
|
||||||
int verbose = VERBOSE_MODE;
|
int silent = SILENT_MODE; /* Completely silent, including boot */
|
||||||
int runlevel = 0; /* Bootstrap 'S' */
|
int runlevel = 0; /* Bootstrap 'S' */
|
||||||
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
|
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
|
||||||
int prevlevel = -1;
|
int prevlevel = -1;
|
||||||
@@ -61,7 +68,7 @@ static int banner(void)
|
|||||||
char buf[42] = INIT_HEADING;
|
char buf[42] = INIT_HEADING;
|
||||||
const char separator[] = "========================================================================";
|
const char separator[] = "========================================================================";
|
||||||
|
|
||||||
if (!verbose)
|
if (silent)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fprintf(stderr, "\e[2K\e[1m%s %.*s\e[0m\n", buf, 66 - (int)strlen(buf), separator);
|
fprintf(stderr, "\e[2K\e[1m%s %.*s\e[0m\n", buf, 66 - (int)strlen(buf), separator);
|
||||||
@@ -69,9 +76,164 @@ static int banner(void)
|
|||||||
return 0;
|
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)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
glob_t gl;
|
||||||
|
FILE *fp;
|
||||||
|
char buf[160];
|
||||||
|
|
||||||
|
/* Setup kernel specific settings, e.g. allow broadcast ping, etc. */
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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) {
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
/* 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[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
char *devfsd;
|
||||||
uev_ctx_t loop;
|
uev_ctx_t loop;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -81,6 +243,16 @@ int main(int argc, char* argv[])
|
|||||||
if (getpid() != 1)
|
if (getpid() != 1)
|
||||||
return client(argc, argv);
|
return client(argc, argv);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In case of emergency.
|
||||||
|
*/
|
||||||
|
emergency_shell();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hello world.
|
||||||
|
*/
|
||||||
|
banner();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initial setup of signals, ignore all until we're up.
|
* Initial setup of signals, ignore all until we're up.
|
||||||
*/
|
*/
|
||||||
@@ -92,6 +264,14 @@ int main(int argc, char* argv[])
|
|||||||
uev_init(&loop);
|
uev_init(&loop);
|
||||||
ctx = &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
|
* Mount base file system, kernel is assumed to run devtmpfs for /dev
|
||||||
*/
|
*/
|
||||||
@@ -100,10 +280,30 @@ int main(int argc, char* argv[])
|
|||||||
mount("none", "/proc", "proc", 0, NULL);
|
mount("none", "/proc", "proc", 0, NULL);
|
||||||
mount("none", "/proc/bus/usb", "usbfs", 0, NULL);
|
mount("none", "/proc/bus/usb", "usbfs", 0, NULL);
|
||||||
mount("none", "/sys", "sysfs", 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);
|
makedir("/dev/pts", 0755);
|
||||||
|
mount("devpts", "/dev/pts", "devpts", 0, "gid=5,mode=620");
|
||||||
|
|
||||||
makedir("/dev/shm", 0755);
|
makedir("/dev/shm", 0755);
|
||||||
mount("none", "/dev/pts", "devpts", 0, "gid=5,mode=620");
|
if (!fismnt("/dev/shm"))
|
||||||
mount("none", "/dev/shm", "tmpfs", 0, NULL);
|
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);
|
umask(022);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -111,25 +311,27 @@ int main(int argc, char* argv[])
|
|||||||
*/
|
*/
|
||||||
conf_parse_cmdline();
|
conf_parse_cmdline();
|
||||||
|
|
||||||
/*
|
|
||||||
* Hello world.
|
|
||||||
*/
|
|
||||||
banner();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Populate /dev and prepare for runtime events from kernel.
|
* Populate /dev and prepare for runtime events from kernel.
|
||||||
*/
|
*/
|
||||||
#ifdef EMBEDDED_SYSTEM
|
if (fexist("/sbin/mdev")) {
|
||||||
if (debug)
|
/* Embedded Linux systems usually have BusyBox mdev */
|
||||||
touch("/dev/mdev.log");
|
if (debug)
|
||||||
#endif
|
touch("/dev/mdev.log");
|
||||||
run_interactive(SETUP_DEVFS, "Populating device tree");
|
devfsd = "/sbin/mdev -s";
|
||||||
|
} else {
|
||||||
|
if (fexist("/sbin/udevd"))
|
||||||
|
devfsd = "/sbin/udevd --daemon";
|
||||||
|
else
|
||||||
|
devfsd = "/lib/systemd/systemd-udevd --daemon";
|
||||||
|
}
|
||||||
|
run_interactive(devfsd, "Populating device tree");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Load plugins first, finit.conf may contain references to
|
* Load plugins first, finit.conf may contain references to
|
||||||
* features implemented by plugins.
|
* features implemented by plugins.
|
||||||
*/
|
*/
|
||||||
plugin_load_all(&loop, PLUGIN_PATH);
|
plugin_init(&loop, PLUGIN_PATH);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse /etc/finit.conf, main configuration file
|
* Parse /etc/finit.conf, main configuration file
|
||||||
@@ -152,6 +354,10 @@ int main(int argc, char* argv[])
|
|||||||
mount(SYSROOT, "/", NULL, MS_MOVE, NULL);
|
mount(SYSROOT, "/", NULL, MS_MOVE, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Debian has this little script to copy generated rules while the system was read-only */
|
||||||
|
if (fexist("/lib/udev/udev-finish"))
|
||||||
|
run_interactive("/lib/udev/udev-finish", "Finalizing udev");
|
||||||
|
|
||||||
_d("Root FS up, calling hooks ...");
|
_d("Root FS up, calling hooks ...");
|
||||||
plugin_run_hooks(HOOK_ROOTFS_UP);
|
plugin_run_hooks(HOOK_ROOTFS_UP);
|
||||||
|
|
||||||
@@ -166,8 +372,8 @@ int main(int argc, char* argv[])
|
|||||||
run("/sbin/swapon -ea");
|
run("/sbin/swapon -ea");
|
||||||
umask(0022);
|
umask(0022);
|
||||||
|
|
||||||
/* Cleanup stale files, if any still linger on. */
|
/* Cleanup of stale files, if any still linger on. */
|
||||||
run_interactive("rm -rf /tmp/* /var/run/* /var/lock/*", "Cleanup temporary directories");
|
run_interactive("rm -rf /tmp/* /var/run/* /var/lock/*", "Cleaning up temporary directories");
|
||||||
|
|
||||||
/* Base FS up, enable standard SysV init signals */
|
/* Base FS up, enable standard SysV init signals */
|
||||||
sig_setup(&loop);
|
sig_setup(&loop);
|
||||||
@@ -176,20 +382,15 @@ int main(int argc, char* argv[])
|
|||||||
plugin_run_hooks(HOOK_BASEFS_UP);
|
plugin_run_hooks(HOOK_BASEFS_UP);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Start all bootstrap tasks, no network available!
|
* Initalize finit state machine and start all bootstrap tasks, no network available!
|
||||||
*/
|
*/
|
||||||
service_bootstrap();
|
sm_init(&sm);
|
||||||
|
sm_step(&sm);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Network stuff
|
* Network stuff
|
||||||
*/
|
*/
|
||||||
|
networking();
|
||||||
/* Setup kernel specific settings, e.g. allow broadcast ping, etc. */
|
|
||||||
run("/sbin/sysctl -e -p /etc/sysctl.conf >/dev/null");
|
|
||||||
|
|
||||||
ifconfig("lo", "127.0.0.1", "255.0.0.0", 1);
|
|
||||||
if (network)
|
|
||||||
run_interactive(network, "Starting networking: %s", network);
|
|
||||||
umask(022);
|
umask(022);
|
||||||
|
|
||||||
/* Hooks that rely on loopback, or basic networking being up. */
|
/* Hooks that rely on loopback, or basic networking being up. */
|
||||||
@@ -211,15 +412,19 @@ int main(int argc, char* argv[])
|
|||||||
run_parts(runparts, NULL);
|
run_parts(runparts, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
/* Hooks that should run at the very end */
|
/* Hooks that should run at the very end */
|
||||||
plugin_run_hooks(HOOK_SYSTEM_UP);
|
plugin_run_hooks(HOOK_SYSTEM_UP);
|
||||||
|
|
||||||
/* Start TTYs */
|
/* Start TTYs */
|
||||||
tty_runlevel(runlevel);
|
tty_runlevel(runlevel);
|
||||||
|
|
||||||
/* Disable verbose mode, if selected */
|
/* Enable silent mode, if selected */
|
||||||
if (quiet && !debug)
|
if (quiet && !debug)
|
||||||
verbose = 0;
|
silent = 1;
|
||||||
|
|
||||||
/* Start new initctl API responder */
|
/* Start new initctl API responder */
|
||||||
api_init(&loop);
|
api_init(&loop);
|
||||||
@@ -232,7 +437,6 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
@@ -33,26 +33,40 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <lite/lite.h>
|
||||||
#include "libite/lite.h"
|
#include <uev/uev.h>
|
||||||
|
|
||||||
#define CMD_SIZE 256
|
#define CMD_SIZE 256
|
||||||
#define LINE_SIZE 1024
|
#define LINE_SIZE 1024
|
||||||
#define BUF_SIZE 4096
|
#define BUF_SIZE 4096
|
||||||
|
|
||||||
/* We reuse the INIT_CMD_ for the new initctl tool, but telinit only
|
/*
|
||||||
* supports changing runlevel and reloading the configuration. */
|
* 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_SOCKET _PATH_VARRUN "finit.sock"
|
||||||
#define INIT_MAGIC 0x03091969
|
#define INIT_MAGIC 0x03091969
|
||||||
|
|
||||||
|
#define INIT_CMD_START 0
|
||||||
#define INIT_CMD_RUNLVL 1
|
#define INIT_CMD_RUNLVL 1
|
||||||
#define INIT_CMD_DEBUG 2 /* Toggle Finit debug */
|
#define INIT_CMD_POWERFAIL 2
|
||||||
#define INIT_CMD_RELOAD 3 /* Reload *.conf in /etc/finit.d/ */
|
#define INIT_CMD_POWERFAILNOW 3
|
||||||
#define INIT_CMD_START_SVC 4
|
#define INIT_CMD_POWEROK 4
|
||||||
#define INIT_CMD_STOP_SVC 5
|
#define INIT_CMD_BSD 5
|
||||||
#define INIT_CMD_RELOAD_SVC 6 /* SIGHUP service */
|
#define INIT_CMD_SETENV 6
|
||||||
#define INIT_CMD_RESTART_SVC 7 /* STOP + START service */
|
#define INIT_CMD_UNSETENV 7
|
||||||
#define INIT_CMD_QUERY_INETD 8
|
|
||||||
#define INIT_CMD_EMIT 9
|
/* 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_NACK 254
|
#define INIT_CMD_NACK 254
|
||||||
#define INIT_CMD_ACK 255
|
#define INIT_CMD_ACK 255
|
||||||
|
|
||||||
@@ -66,7 +80,7 @@ struct init_request {
|
|||||||
|
|
||||||
extern int debug;
|
extern int debug;
|
||||||
extern int quiet;
|
extern int quiet;
|
||||||
extern int verbose;
|
extern int silent;
|
||||||
extern int runlevel;
|
extern int runlevel;
|
||||||
extern int cfglevel;
|
extern int cfglevel;
|
||||||
extern int prevlevel;
|
extern int prevlevel;
|
||||||
@@ -77,13 +91,14 @@ extern char *hostname;
|
|||||||
extern char *username;
|
extern char *username;
|
||||||
extern char *runparts;
|
extern char *runparts;
|
||||||
extern char *console;
|
extern char *console;
|
||||||
|
extern uev_ctx_t *ctx;
|
||||||
|
|
||||||
extern char *__progname;
|
extern char *__progname;
|
||||||
|
|
||||||
#endif /* FINIT_H_ */
|
#endif /* FINIT_H_ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
@@ -0,0 +1,325 @@
|
|||||||
|
/* 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 <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);
|
||||||
|
|
||||||
|
/* Clear screen -- disabled until we decide on config to disable/enable */
|
||||||
|
//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:
|
||||||
|
*/
|
||||||
@@ -22,57 +22,45 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h> /* isblank() */
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <utmp.h>
|
#include <lite/lite.h>
|
||||||
|
#include <lite/conio.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "private.h"
|
#include "private.h"
|
||||||
#include "libite/lite.h"
|
#include "utmp-api.h"
|
||||||
|
|
||||||
static int encode(int lvl)
|
int _slup = 0; /* INTERNAL: Is syslog up yet? */
|
||||||
|
|
||||||
|
char *strip_line(char *line)
|
||||||
{
|
{
|
||||||
if (!lvl) return 0;
|
char *ptr;
|
||||||
return lvl + '0';
|
|
||||||
|
/* Trim leading whitespace */
|
||||||
|
while (*line && isblank(*line))
|
||||||
|
line++;
|
||||||
|
|
||||||
|
/* Strip any comment at end of line */
|
||||||
|
ptr = line;
|
||||||
|
while (*ptr && *ptr != '#')
|
||||||
|
ptr++;
|
||||||
|
*ptr = 0;
|
||||||
|
|
||||||
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
void runlevel_set(int pre, int now)
|
void runlevel_set(int pre, int now)
|
||||||
{
|
{
|
||||||
struct utmp utent;
|
utmp_set_runlevel(pre, now);
|
||||||
|
|
||||||
utent.ut_type = RUN_LVL;
|
|
||||||
utent.ut_pid = (encode(pre) << 8) | (encode(now) & 0xFF);
|
|
||||||
strlcpy(utent.ut_user, "runlevel", sizeof(utent.ut_user));
|
|
||||||
|
|
||||||
setutent();
|
|
||||||
pututline(&utent);
|
|
||||||
endutent();
|
|
||||||
}
|
|
||||||
|
|
||||||
int runlevel_get(void)
|
|
||||||
{
|
|
||||||
int lvl = '?'; /* Non-existing runlevel */
|
|
||||||
struct utmp *utent;
|
|
||||||
|
|
||||||
setutent();
|
|
||||||
while ((utent = getutent())) {
|
|
||||||
if (utent->ut_type == RUN_LVL) {
|
|
||||||
lvl = utent->ut_pid & 0xFF;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
endutent();
|
|
||||||
|
|
||||||
return lvl - '0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -139,10 +127,11 @@ void print(int action, const char *fmt, ...)
|
|||||||
va_list ap;
|
va_list ap;
|
||||||
const char success[] = " \e[1m[ OK ]\e[0m\n";
|
const char success[] = " \e[1m[ OK ]\e[0m\n";
|
||||||
const char failure[] = " \e[7m[FAIL]\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 pending[] = " \e[1m[ \\/ ]\e[0m\n";
|
||||||
const char dots[] = " .....................................................................";
|
const char dots[] = " .....................................................................";
|
||||||
|
|
||||||
if (!verbose)
|
if (silent)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (fmt) {
|
if (fmt) {
|
||||||
@@ -170,6 +159,10 @@ void print(int action, const char *fmt, ...)
|
|||||||
write(STDERR_FILENO, failure, sizeof(failure));
|
write(STDERR_FILENO, failure, sizeof(failure));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
write(STDERR_FILENO, warning, sizeof(warning));
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
write(STDERR_FILENO, pending, sizeof(pending));
|
write(STDERR_FILENO, pending, sizeof(pending));
|
||||||
break;
|
break;
|
||||||
@@ -187,9 +180,48 @@ int print_result(int fail)
|
|||||||
return fail;
|
return fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getuser(char *username)
|
/*
|
||||||
|
* Log to stderr until syslogd has started, then openlog() and continue
|
||||||
|
* logging as a regular daemon.
|
||||||
|
*
|
||||||
|
* TODO: Log to /dev/kmsg instead of stderr until syslogd has started
|
||||||
|
* Need to convert facility+prio => "<VAL> msg"
|
||||||
|
*/
|
||||||
|
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) {
|
||||||
|
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 (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
|
#ifdef ENABLE_STATIC
|
||||||
|
*home = "/"; /* XXX: Fixme */
|
||||||
return fgetint("/etc/passwd", "x:\n", username);
|
return fgetint("/etc/passwd", "x:\n", username);
|
||||||
#else
|
#else
|
||||||
struct passwd *usr;
|
struct passwd *usr;
|
||||||
@@ -197,7 +229,8 @@ int getuser(char *username)
|
|||||||
if (!username || (usr = getpwnam(username)) == NULL)
|
if (!username || (usr = getpwnam(username)) == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return usr->pw_uid;
|
*home = usr->pw_dir;
|
||||||
|
return usr->pw_uid;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,7 +259,6 @@ void set_hostname(char **hostname)
|
|||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
_d("Set hostname: %s", *hostname);
|
|
||||||
fp = fopen("/etc/hostname", "r");
|
fp = fopen("/etc/hostname", "r");
|
||||||
if (fp) {
|
if (fp) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
@@ -251,9 +283,50 @@ void set_hostname(char **hostname)
|
|||||||
sethostname(*hostname, strlen(*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:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
@@ -25,44 +25,30 @@
|
|||||||
#ifndef FINIT_HELPERS_H_
|
#ifndef FINIT_HELPERS_H_
|
||||||
#define FINIT_HELPERS_H_
|
#define FINIT_HELPERS_H_
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h> /* strerror() */
|
#include <string.h> /* strerror() */
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
#define DO_LOG(level, fmt, args...) \
|
/*
|
||||||
do { \
|
* Error and debug messages
|
||||||
openlog("finit", LOG_CONS | LOG_PID, LOG_DAEMON); \
|
*
|
||||||
syslog(level, fmt, ##args); \
|
* Use of logit() is preferred, but these are guaranteed to display on
|
||||||
closelog(); \
|
* /dev/console as well. Useful for critical errors and early debug.
|
||||||
} while (0)
|
*/
|
||||||
|
#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)
|
||||||
|
|
||||||
#define FLOG_DEBUG(fmt, args...) DO_LOG(LOG_DEBUG, fmt, ##args)
|
extern int _slup; /* INTERNAL: Is syslog up yet? */
|
||||||
#define FLOG_INFO(fmt, args...) DO_LOG(LOG_INFO, fmt, ##args)
|
|
||||||
#define FLOG_WARN(fmt, args...) DO_LOG(LOG_WARNING, fmt, ##args)
|
|
||||||
#define FLOG_ERROR(fmt, args...) DO_LOG(LOG_CRIT, fmt, ##args)
|
|
||||||
#define FLOG_PERROR(fmt, args...) DO_LOG(LOG_CRIT, fmt ". Error %d: %s", ##args, errno, strerror(errno))
|
|
||||||
|
|
||||||
|
char *strip_line (char *line);
|
||||||
/* Esc[2JEsc[1;1H Clear screen and move cursor to 1,1 (upper left) pos. */
|
|
||||||
#define clrscr() fputs("\e[2J\e[1;1H", stderr)
|
|
||||||
/* Esc[K Erases from the current cursor position to the end of the current line. */
|
|
||||||
#define clreol() fputs("\e[K", stderr)
|
|
||||||
/* Esc[2K Erases the entire current line. */
|
|
||||||
#define delline() fputs("\e[2K", stderr)
|
|
||||||
/* Esc[Line;ColumnH Moves the cursor to the specified position (coordinates) */
|
|
||||||
#define gotoxy(x,y) fprintf(stderr, "\e[%d;%dH", y, x)
|
|
||||||
/* Esc[?25l (lower case L) Hide Cursor */
|
|
||||||
#define hidecursor() fputs("\e[?25l", stderr)
|
|
||||||
/* Esc[?25h (lower case H) Show Cursor */
|
|
||||||
#define showcursor() fputs("\e[?25h", stderr)
|
|
||||||
|
|
||||||
#define echo(fmt, args...) do { fprintf(stderr, fmt "\n", ##args); } while (0)
|
|
||||||
#define _d(fmt, args...) do { if (debug) { fprintf(stderr, "finit:%s:%s() - " fmt "\n", __FILE__, __func__, ##args); } } while (0)
|
|
||||||
#define _e(fmt, args...) do { fprintf(stderr, "finit:%s:%s() - " fmt "\n", __FILE__, __func__, ##args); } while (0)
|
|
||||||
#define _pe(fmt, args...) do { fprintf(stderr, "finit:%s:%s() - " fmt ". Error %d: %s\n", __FILE__, __func__, ##args, errno, strerror(errno)); } while (0)
|
|
||||||
|
|
||||||
void runlevel_set (int pre, int now);
|
void runlevel_set (int pre, int now);
|
||||||
int runlevel_get (void);
|
|
||||||
char *runlevel_string (int levels);
|
char *runlevel_string (int levels);
|
||||||
|
|
||||||
int pid_alive (pid_t pid);
|
int pid_alive (pid_t pid);
|
||||||
@@ -73,23 +59,41 @@ void procname_set (char *name, char *args[]);
|
|||||||
void print (int action, const char *fmt, ...);
|
void print (int action, const char *fmt, ...);
|
||||||
void print_desc (char *action, char *desc);
|
void print_desc (char *action, char *desc);
|
||||||
int print_result (int fail);
|
int print_result (int fail);
|
||||||
|
|
||||||
|
void logit (int prio, const char *fmt, ...);
|
||||||
|
|
||||||
int start_process (char *cmd, char *args[], int console);
|
int start_process (char *cmd, char *args[], int console);
|
||||||
void do_sleep (unsigned int sec);
|
void do_sleep (unsigned int sec);
|
||||||
int getuser (char *username);
|
int getuser (char *username, char **home);
|
||||||
int getgroup (char *group);
|
int getgroup (char *group);
|
||||||
void set_hostname (char **hostname);
|
void set_hostname (char **hostname);
|
||||||
|
|
||||||
int complete (char *cmd, int pid);
|
int complete (char *cmd, int pid);
|
||||||
int run (char *cmd);
|
int run (char *cmd);
|
||||||
int run_interactive (char *cmd, char *fmt, ...);
|
int run_interactive (char *cmd, char *fmt, ...);
|
||||||
pid_t run_getty (char *cmd, char *args[], int console);
|
pid_t run_getty (char *tty, char *speed, char *term, int console);
|
||||||
int run_parts (char *dir, char *cmd);
|
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_ */
|
#endif /* FINIT_HELPERS_H_ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
@@ -25,9 +25,8 @@
|
|||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <uev/uev.h>
|
||||||
#include "libuev/uev.h"
|
#include <lite/lite.h>
|
||||||
#include "libite/lite.h"
|
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "inetd.h"
|
#include "inetd.h"
|
||||||
@@ -35,83 +34,16 @@
|
|||||||
#include "private.h"
|
#include "private.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
|
|
||||||
#define ENABLE_SOCKOPT(sd, level, opt) \
|
#define ENABLE_SOCKOPT(sd, level, opt) \
|
||||||
do { \
|
do { \
|
||||||
int val = 1; \
|
int val = 1; \
|
||||||
if (setsockopt(sd, level, opt, &val, sizeof(val)) < 0) \
|
if (setsockopt(sd, level, opt, &val, sizeof(val)) < 0) \
|
||||||
FLOG_PERROR("Failed setting %s on %s service.", \
|
logit(LOG_CRIT, "Failed enabling %s on %s service", \
|
||||||
#opt, inetd->name); \
|
#opt, inetd->name); \
|
||||||
} while (0);
|
} while (0);
|
||||||
|
|
||||||
/* Socket callback, looks up correct svc and starts it as an inetd service */
|
|
||||||
static void socket_cb(uev_t *w, void *arg, int UNUSED(events))
|
|
||||||
{
|
|
||||||
svc_t *svc = (svc_t *)arg;
|
|
||||||
|
|
||||||
if (SVC_START != service_enabled(svc, -1, NULL))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!svc->inetd.forking)
|
|
||||||
uev_io_stop(w);
|
|
||||||
|
|
||||||
service_start(svc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Launch Inet socket for service.
|
|
||||||
* TODO: Add filtering ALLOW/DENY per interface.
|
|
||||||
*/
|
|
||||||
static void spawn_socket(inetd_t *inetd)
|
|
||||||
{
|
|
||||||
int sd;
|
|
||||||
socklen_t len = sizeof(struct sockaddr);
|
|
||||||
struct sockaddr_in s;
|
|
||||||
|
|
||||||
if (!inetd->type) {
|
|
||||||
FLOG_ERROR("Skipping invalid inetd service %s", inetd->name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_d("Spawning server socket for inetd %s ...", inetd->name);
|
|
||||||
sd = socket(AF_INET, inetd->type | SOCK_NONBLOCK | SOCK_CLOEXEC, inetd->proto);
|
|
||||||
if (-1 == sd) {
|
|
||||||
FLOG_PERROR("Failed opening inetd socket type %d proto %d", inetd->type, inetd->proto);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
FLOG_PERROR("Failed binding to port %d, maybe another %s server is already running",
|
|
||||||
inetd->port, inetd->name);
|
|
||||||
close(sd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inetd->port) {
|
|
||||||
if (inetd->type == SOCK_STREAM) {
|
|
||||||
if (-1 == listen(sd, 20)) {
|
|
||||||
FLOG_PERROR("Failed listening to inetd service %s", inetd->name);
|
|
||||||
close(sd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else { /* SOCK_DGRAM */
|
|
||||||
/* Set extra sockopt to get ifindex from inbound packets */
|
|
||||||
ENABLE_SOCKOPT(sd, SOL_IP, IP_PKTINFO);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uev_io_init(ctx, &inetd->watcher, socket_cb, inetd->arg, sd, UEV_READ);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Peek into SOCK_DGRAM socket to figure out where an inbound packet comes from. */
|
/* Peek into SOCK_DGRAM socket to figure out where an inbound packet comes from. */
|
||||||
int inetd_dgram_peek(int sd, char *ifname)
|
static int inetd_dgram_peek(int sd, char *ifname)
|
||||||
{
|
{
|
||||||
char cmbuf[0x100];
|
char cmbuf[0x100];
|
||||||
struct msghdr msgh;
|
struct msghdr msgh;
|
||||||
@@ -139,7 +71,7 @@ int inetd_dgram_peek(int sd, char *ifname)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Peek into SOCK_STREAM on accepted client socket to figure out inbound interface */
|
/* Peek into SOCK_STREAM on accepted client socket to figure out inbound interface */
|
||||||
int inetd_stream_peek(int sd, char *ifname)
|
static int inetd_stream_peek(int sd, char *ifname)
|
||||||
{
|
{
|
||||||
struct ifaddrs *ifaddr, *ifa;
|
struct ifaddrs *ifaddr, *ifa;
|
||||||
struct sockaddr_in sin;
|
struct sockaddr_in sin;
|
||||||
@@ -173,49 +105,223 @@ int inetd_stream_peek(int sd, char *ifname)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Inetd monitor, called by service_monitor() */
|
static int get_stdin(svc_t *svc)
|
||||||
int inetd_respawn(pid_t pid)
|
|
||||||
{
|
{
|
||||||
svc_t *svc = svc_find_by_pid(pid);
|
int stdin = svc->inetd.watcher.fd;
|
||||||
|
char ifname[IF_NAMESIZE] = "UNKNOWN";
|
||||||
|
|
||||||
if (svc_is_inetd(svc)) {
|
if (svc->inetd.type == SOCK_STREAM) {
|
||||||
inetd_t *inetd = &svc->inetd;
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
svc->pid = 0;
|
_d("New client socket %d accepted for inetd service %d/tcp", stdin, svc->inetd.port);
|
||||||
|
|
||||||
if (svc_in_runlevel(svc, runlevel) && !inetd->forking)
|
inetd_stream_peek(stdin, ifname);
|
||||||
uev_io_set(&inetd->watcher, inetd->watcher.fd, UEV_READ);
|
} else { /* SOCK_DGRAM */
|
||||||
|
inetd_dgram_peek(stdin, ifname);
|
||||||
return 1; /* It was us! */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0; /* Not an inetd service */
|
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 */
|
||||||
void inetd_start(inetd_t *inetd)
|
static void socket_cb(uev_t *UNUSED(w), void *arg, int UNUSED(events))
|
||||||
{
|
{
|
||||||
if (inetd->watcher.fd == -1)
|
svc_t *svc = (svc_t *)arg, *task;
|
||||||
spawn_socket(inetd);
|
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)
|
void inetd_stop(inetd_t *inetd)
|
||||||
{
|
{
|
||||||
svc_t *svc = (svc_t *)inetd->arg;
|
|
||||||
|
|
||||||
if (inetd->watcher.fd != -1) {
|
if (inetd->watcher.fd != -1) {
|
||||||
|
_d("Stopping %s socket watcher ...", inetd->svc->cmd);
|
||||||
uev_io_stop(&inetd->watcher);
|
uev_io_stop(&inetd->watcher);
|
||||||
shutdown(inetd->watcher.fd, SHUT_RDWR);
|
|
||||||
close(inetd->watcher.fd);
|
|
||||||
inetd->watcher.fd = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stop any running service, not allowed anymore. */
|
/* For dgram inetd services we block the parent SVC
|
||||||
if (svc->pid)
|
* and halt the watcher, so don't close the socket! */
|
||||||
service_stop(svc, SVC_WAITING_STATE);
|
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 int getent(char *service, char *proto, struct servent **sv, struct protoent **pv)
|
static struct servent *getent_service(char *service, char *proto)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_STATIC
|
#ifdef ENABLE_STATIC
|
||||||
int service_num;
|
int service_num;
|
||||||
@@ -228,11 +334,44 @@ static int getent(char *service, char *proto, struct servent **sv, struct protoe
|
|||||||
lfs.s_proto = NULL;
|
lfs.s_proto = NULL;
|
||||||
if (!strcmp("tcp", proto) || !strcmp("udp", proto))
|
if (!strcmp("tcp", proto) || !strcmp("udp", proto))
|
||||||
lfs.s_proto = proto;
|
lfs.s_proto = proto;
|
||||||
*sv = &lfs;
|
|
||||||
|
return &lfs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
#else
|
#else
|
||||||
*sv = getservbyname(service, proto);
|
return getservbyname(service, proto);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct protoent *getent_proto(char *proto)
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_STATIC
|
||||||
|
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;
|
||||||
|
#else
|
||||||
|
return getprotobyname(proto);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
if (!*sv) {
|
||||||
const char *errstr;
|
const char *errstr;
|
||||||
static struct servent s;
|
static struct servent s;
|
||||||
@@ -244,31 +383,19 @@ static int getent(char *service, char *proto, struct servent **sv, struct protoe
|
|||||||
s.s_proto = proto;
|
s.s_proto = proto;
|
||||||
|
|
||||||
if (errstr || !s.s_proto) {
|
if (errstr || !s.s_proto) {
|
||||||
_e("Invalid/unknown inetd service, cannot create custom entry.");
|
_e("Invalid/unknown inetd service, cannot create custom entry");
|
||||||
return errno = EINVAL;
|
return errno = EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("Creating cutom inetd service %s/%s.", service, proto);
|
_d("Creating cutom inetd service %s/%s", service, proto);
|
||||||
s.s_port = htons(s.s_port);
|
s.s_port = htons(s.s_port);
|
||||||
*sv = &s;
|
*sv = &s;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pv && (*sv)->s_proto) {
|
if (pv && (*sv)->s_proto) {
|
||||||
#ifdef ENABLE_STATIC
|
*pv = getent_proto((*sv)->s_proto);
|
||||||
int proto_num;
|
|
||||||
static struct protoent lfp;
|
|
||||||
|
|
||||||
proto_num = fgetint("/etc/protocols", " \n\t", (*sv)->s_proto);
|
|
||||||
if (proto_num > 0) {
|
|
||||||
lfp.p_name = proto;
|
|
||||||
lfp.p_proto = proto_num;
|
|
||||||
}
|
|
||||||
*pv = &lfp;
|
|
||||||
#else
|
|
||||||
*pv = getprotobyname((*sv)->s_proto);
|
|
||||||
#endif
|
|
||||||
if (!*pv) {
|
if (!*pv) {
|
||||||
_e("Cannot find proto %s, skipping.", (*sv)->s_proto);
|
_e("Cannot find proto %s, skipping ...", (*sv)->s_proto);
|
||||||
return errno = EINVAL;
|
return errno = EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -318,6 +445,18 @@ inetd_filter_t *inetd_filter_match(inetd_t *inetd, char *ifname)
|
|||||||
return NULL;
|
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 */
|
/* Poor man's tcpwrappers filtering */
|
||||||
int inetd_allow(inetd_t *inetd, char *ifname)
|
int inetd_allow(inetd_t *inetd, char *ifname)
|
||||||
{
|
{
|
||||||
@@ -331,7 +470,7 @@ int inetd_allow(inetd_t *inetd, char *ifname)
|
|||||||
|
|
||||||
filter = inetd_filter_match(inetd, ifname);
|
filter = inetd_filter_match(inetd, ifname);
|
||||||
if (filter) {
|
if (filter) {
|
||||||
_d("Filter %s for inetd %s already exists, skipping.", ifname, inetd->name);
|
_d("Filter %s for inetd %s already exists, skipping ...", ifname, inetd->name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,7 +500,7 @@ int inetd_deny(inetd_t *inetd, char *ifname)
|
|||||||
|
|
||||||
filter = find_filter(inetd, ifname);
|
filter = find_filter(inetd, ifname);
|
||||||
if (filter) {
|
if (filter) {
|
||||||
_d("%s filter %s for inetd %s already exists, cannot set deny filter for same, skipping.",
|
_d("%s filter %s for inetd %s already exists, cannot set deny filter for same, skipping ...",
|
||||||
filter->deny ? "Deny" : "Allow", ifname, inetd->name);
|
filter->deny ? "Deny" : "Allow", ifname, inetd->name);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -497,7 +636,7 @@ int inetd_filter_str(inetd_t *inetd, char *str, size_t len)
|
|||||||
* If equivalent service exists already service_register() will instead call
|
* If equivalent service exists already service_register() will instead call
|
||||||
* inetd_allow().
|
* inetd_allow().
|
||||||
*/
|
*/
|
||||||
int inetd_new(inetd_t *inetd, char *name, char *service, char *proto, int forking, void *arg)
|
int inetd_new(inetd_t *inetd, char *name, char *service, char *proto, int forking, svc_t *svc)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
struct servent *sv = NULL;
|
struct servent *sv = NULL;
|
||||||
@@ -515,6 +654,7 @@ int inetd_new(inetd_t *inetd, char *name, char *service, char *proto, int forkin
|
|||||||
inetd->port = ntohs(sv->s_port);
|
inetd->port = ntohs(sv->s_port);
|
||||||
inetd->proto = pv->p_proto;
|
inetd->proto = pv->p_proto;
|
||||||
inetd->forking = !!forking;
|
inetd->forking = !!forking;
|
||||||
|
inetd->next_id = 2;
|
||||||
if (!name)
|
if (!name)
|
||||||
name = service;
|
name = service;
|
||||||
strlcpy(inetd->name, name, sizeof(inetd->name));
|
strlcpy(inetd->name, name, sizeof(inetd->name));
|
||||||
@@ -526,11 +666,16 @@ int inetd_new(inetd_t *inetd, char *name, char *service, char *proto, int forkin
|
|||||||
else
|
else
|
||||||
inetd->type = SOCK_DGRAM;
|
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 */
|
/* Reset descriptor, used internally */
|
||||||
inetd->watcher.fd = -1;
|
inetd->watcher.fd = -1;
|
||||||
|
|
||||||
/* Setup socket callback argument */
|
/* Setup socket callback argument */
|
||||||
inetd->arg = arg;
|
inetd->svc = svc;
|
||||||
|
|
||||||
_d("New service %s (default port %d proto %s:%d)", name, inetd->port, sv->s_proto, pv->p_proto);
|
_d("New service %s (default port %d proto %s:%d)", name, inetd->port, sv->s_proto, pv->p_proto);
|
||||||
|
|
||||||
@@ -539,17 +684,14 @@ int inetd_new(inetd_t *inetd, char *name, char *service, char *proto, int forkin
|
|||||||
|
|
||||||
int inetd_del(inetd_t *inetd)
|
int inetd_del(inetd_t *inetd)
|
||||||
{
|
{
|
||||||
inetd_filter_t *filter, *tmp;
|
svc_unblock(inetd->svc);
|
||||||
|
inetd_stop(inetd);
|
||||||
|
|
||||||
TAILQ_FOREACH_SAFE(filter, &inetd->filters, link, tmp)
|
return inetd_flush(inetd);
|
||||||
free(filter);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
@@ -26,10 +26,10 @@
|
|||||||
|
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
|
#include <uev/uev.h>
|
||||||
|
#include <lite/queue.h> /* BSD sys/queue.h API */
|
||||||
|
|
||||||
#include "queue.h"
|
typedef struct svc svc_t;
|
||||||
#include "libuev/uev.h"
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct inetd_filter {
|
typedef struct inetd_filter {
|
||||||
TAILQ_ENTRY(inetd_filter) link;
|
TAILQ_ENTRY(inetd_filter) link;
|
||||||
@@ -39,33 +39,34 @@ typedef struct inetd_filter {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uev_t watcher;
|
uev_t watcher;
|
||||||
void *arg; /* svc_t pointer for the socket callback */
|
svc_t *svc; /* svc_t pointer for the socket callback */
|
||||||
|
|
||||||
int type; /* Socket type: SOCK_STREAM/SOCK_DGRAM */
|
int type; /* Socket type: SOCK_STREAM/SOCK_DGRAM */
|
||||||
int std; /* Standard proto/port from /etc/services */
|
int std; /* Standard proto/port from /etc/services */
|
||||||
int proto;
|
int proto;
|
||||||
int port;
|
int port;
|
||||||
int forking;
|
int forking;
|
||||||
|
int builtin; /* Set by built-in inetd services only */
|
||||||
|
int next_id; /* Next child job's id */
|
||||||
char name[10];
|
char name[10];
|
||||||
int (*cmd)(int type); /* internal inetd service, like 'time' */
|
int (*cmd)(int type); /* internal inetd service, like 'time' */
|
||||||
|
|
||||||
TAILQ_HEAD(, inetd_filter) filters;
|
TAILQ_HEAD(, inetd_filter) filters;
|
||||||
} inetd_t;
|
} inetd_t;
|
||||||
|
|
||||||
int inetd_dgram_peek (int sd, char *ifname);
|
int inetd_check_loop (struct sockaddr *sa, socklen_t len, char *name);
|
||||||
int inetd_stream_peek (int sd, char *ifname);
|
|
||||||
|
|
||||||
void inetd_start (inetd_t *inetd);
|
int inetd_start (inetd_t *inetd);
|
||||||
void inetd_stop (inetd_t *inetd);
|
void inetd_stop (inetd_t *inetd);
|
||||||
|
|
||||||
int inetd_respawn (pid_t pid);
|
int inetd_new (inetd_t *inetd, char *name, char *service, char *proto,
|
||||||
|
int forking, svc_t *svc);
|
||||||
int inetd_new (inetd_t *inetd, char *name, char *service, char *proto, int forking, void *arg);
|
|
||||||
int inetd_del (inetd_t *inetd);
|
int inetd_del (inetd_t *inetd);
|
||||||
|
|
||||||
int inetd_match (inetd_t *inetd, 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_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_allow (inetd_t *inetd, char *ifname);
|
||||||
int inetd_deny (inetd_t *inetd, char *ifname);
|
int inetd_deny (inetd_t *inetd, char *ifname);
|
||||||
int inetd_is_allowed (inetd_t *inetd, char *ifname);
|
int inetd_is_allowed (inetd_t *inetd, char *ifname);
|
||||||
@@ -74,7 +75,6 @@ int inetd_is_allowed (inetd_t *inetd, char *ifname);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* New client tool, complements old /dev/initctl API and telinit tool
|
/* New client tool, complements old /dev/initctl API and telinit tool
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015 Joachim Nilsson <troglobit@gmail.com>
|
* Copyright (c) 2015-2016 Joachim Nilsson <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -21,17 +21,26 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#include <glob.h>
|
||||||
|
#include <paths.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
#include <lite/lite.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
|
#include "cond.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
|
#include "utmp-api.h"
|
||||||
|
|
||||||
#include "libite/lite.h"
|
#define _PATH_COND _PATH_VARRUN "finit/cond/"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *cmd;
|
char *cmd;
|
||||||
@@ -40,6 +49,7 @@ typedef struct {
|
|||||||
|
|
||||||
int debug = 0;
|
int debug = 0;
|
||||||
int verbose = 0;
|
int verbose = 0;
|
||||||
|
int silent = 1; /* For helpers.c */
|
||||||
int runlevel = 0;
|
int runlevel = 0;
|
||||||
|
|
||||||
static int do_send(struct init_request *rq, ssize_t len)
|
static int do_send(struct init_request *rq, ssize_t len)
|
||||||
@@ -72,6 +82,42 @@ exit:
|
|||||||
return result;
|
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))
|
static int toggle_debug(char *UNUSED(arg))
|
||||||
{
|
{
|
||||||
struct init_request rq = {
|
struct init_request rq = {
|
||||||
@@ -107,29 +153,154 @@ static int do_svc(int cmd, char *arg)
|
|||||||
.cmd = cmd,
|
.cmd = cmd,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!arg || !arg[0]) {
|
|
||||||
if (cmd == INIT_CMD_RELOAD_SVC) {
|
|
||||||
rq.cmd = INIT_CMD_RELOAD;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
strlcpy(rq.data, arg, sizeof(rq.data));
|
strlcpy(rq.data, arg, sizeof(rq.data));
|
||||||
|
|
||||||
exit:
|
|
||||||
return do_send(&rq, sizeof(rq));
|
return do_send(&rq, sizeof(rq));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_emit (char *arg) { return do_svc(INIT_CMD_EMIT, arg); }
|
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_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_stop (char *arg) { return do_svc(INIT_CMD_STOP_SVC, arg); }
|
||||||
static int do_reload (char *arg) { return do_svc(INIT_CMD_RELOAD_SVC, arg); }
|
|
||||||
static int do_restart(char *arg) { return do_svc(INIT_CMD_RESTART_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))
|
static int show_version(char *UNUSED(arg))
|
||||||
{
|
{
|
||||||
puts("v" VERSION);
|
puts("v" PACKAGE_VERSION);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +341,7 @@ static int show_status(char *arg)
|
|||||||
|
|
||||||
if (!verbose) {
|
if (!verbose) {
|
||||||
printf("# Status PID Runlevels Service Description\n");
|
printf("# Status PID Runlevels Service Description\n");
|
||||||
printf("====================================================================================\n");
|
printf("===============================================================================\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
||||||
@@ -181,7 +352,12 @@ static int show_status(char *arg)
|
|||||||
else
|
else
|
||||||
snprintf(jobid, sizeof(jobid), "%d:%d", svc->job, svc->id);
|
snprintf(jobid, sizeof(jobid), "%d:%d", svc->job, svc->id);
|
||||||
|
|
||||||
printf("%-5s %7s %-6d ", jobid, svc_status(svc), svc->pid);
|
printf("%-5s %7s ", jobid, svc_status(svc));
|
||||||
|
if (svc_is_inetd(svc))
|
||||||
|
printf("inetd ");
|
||||||
|
else
|
||||||
|
printf("%-6d ", svc->pid);
|
||||||
|
|
||||||
lvls = runlevel_string(svc->runlevels);
|
lvls = runlevel_string(svc->runlevels);
|
||||||
if (strchr(lvls, '\e'))
|
if (strchr(lvls, '\e'))
|
||||||
printf("%-18.18s ", lvls);
|
printf("%-18.18s ", lvls);
|
||||||
@@ -189,7 +365,14 @@ static int show_status(char *arg)
|
|||||||
printf("%-10.10s ", lvls);
|
printf("%-10.10s ", lvls);
|
||||||
|
|
||||||
if (!verbose) {
|
if (!verbose) {
|
||||||
printf("%-20s %s\n", svc->cmd, svc->desc);
|
char *name = strrchr(svc->cmd, '/');
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
name = svc->cmd;
|
||||||
|
else
|
||||||
|
name++;
|
||||||
|
|
||||||
|
printf("%-20.20s %-21.21s\n", name, svc->desc);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,19 +426,19 @@ static int usage(int rc)
|
|||||||
"Commands:\n"
|
"Commands:\n"
|
||||||
" debug Toggle Finit (daemon) debug\n"
|
" debug Toggle Finit (daemon) debug\n"
|
||||||
" help This help text\n"
|
" help This help text\n"
|
||||||
" emit <EV> Emit event; a predefined event: RELOAD, STOP, START\n"
|
" reload Reload *.conf in /etc/finit.d and activate changes\n"
|
||||||
" or a custom string matching an event in a service\n"
|
|
||||||
" stanza, e.g: GW:UP, IFUP:IFNAME, IFDN:IFNAME. Where\n"
|
|
||||||
" IFNAME is the interface name, e.g. eth0\n"
|
|
||||||
" reload Reload *.conf in /etc/finit.d/ and activate changes\n"
|
|
||||||
" runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot\n"
|
" runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot\n"
|
||||||
" status | show Show status of services\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"
|
" start <JOB|NAME>[:ID] Start service by job# or name, with optional ID\n"
|
||||||
" stop <JOB|NAME>[:ID] Stop/Pause a running service by job# or name\n"
|
" stop <JOB|NAME>[:ID] Stop/Pause a running service by job# or name\n"
|
||||||
" restart <JOB|NAME>[:ID] Restart (stop/start) service by job# or name\n"
|
" restart <JOB|NAME>[:ID] Restart (stop/start) service by job# or name\n"
|
||||||
" reload <JOB|NAME>[:ID] Reload (SIGHUP) service by job# or name\n"
|
" reboot Reboot system\n"
|
||||||
" status <JOB|NAME>[:ID] Show status of a service by job# or name\n"
|
" halt Halt system\n"
|
||||||
" show <JOB|NAME>[:ID] Alias to 'status <JOB|NAME>[:ID]'\n"
|
" poweroff Halt and power off system\n"
|
||||||
|
" utmp show Raw dump of UTMP/WTMP db\n"
|
||||||
" version Show Finit version\n\n", __progname);
|
" version Show Finit version\n\n", __progname);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
@@ -266,14 +449,18 @@ int main(int argc, char *argv[])
|
|||||||
int c;
|
int c;
|
||||||
command_t command[] = {
|
command_t command[] = {
|
||||||
{ "debug", toggle_debug },
|
{ "debug", toggle_debug },
|
||||||
{ "emit", do_emit },
|
|
||||||
{ "reload", do_reload },
|
{ "reload", do_reload },
|
||||||
{ "runlevel", do_runlevel },
|
{ "runlevel", do_runlevel },
|
||||||
{ "status", show_status },
|
{ "status", show_status },
|
||||||
{ "show", show_status }, /* Convenience alias */
|
{ "show", show_status }, /* Convenience alias */
|
||||||
|
{ "cond", do_cond },
|
||||||
{ "start", do_start },
|
{ "start", do_start },
|
||||||
{ "stop", do_stop },
|
{ "stop", do_stop },
|
||||||
{ "restart", do_restart },
|
{ "restart", do_restart },
|
||||||
|
{ "reboot", do_reboot },
|
||||||
|
{ "halt", do_halt },
|
||||||
|
{ "poweroff", do_poweroff },
|
||||||
|
{ "utmp", do_utmp },
|
||||||
{ "version", show_version },
|
{ "version", show_version },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
@@ -284,7 +471,6 @@ int main(int argc, char *argv[])
|
|||||||
{NULL, 0, NULL, 0}
|
{NULL, 0, NULL, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
verbose = 0;
|
|
||||||
while ((c = getopt_long(argc, argv, "dh?v", long_options, NULL)) != EOF) {
|
while ((c = getopt_long(argc, argv, "dh?v", long_options, NULL)) != EOF) {
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case 'h':
|
case 'h':
|
||||||
@@ -300,6 +486,7 @@ int main(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
silent = !verbose;
|
||||||
|
|
||||||
if (optind < argc) {
|
if (optind < argc) {
|
||||||
char *cmd = argv[optind++];
|
char *cmd = argv[optind++];
|
||||||
@@ -321,7 +508,6 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
-1
Submodule libite deleted from 12ed342d55
-1
Submodule libuev deleted from cf5e729dd3
@@ -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:
|
||||||
|
*/
|
||||||
@@ -26,9 +26,9 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <lite/lite.h>
|
||||||
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "libite/lite.h"
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -92,7 +92,6 @@ char *pid_get_name(pid_t pid, char *name, size_t len)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
@@ -26,15 +26,21 @@
|
|||||||
#include <dirent.h> /* readdir() et al */
|
#include <dirent.h> /* readdir() et al */
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <lite/lite.h>
|
||||||
|
#include <lite/queue.h> /* BSD sys/queue.h API */
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "private.h"
|
#include "private.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
#include "queue.h" /* BSD sys/queue.h API */
|
|
||||||
#include "libite/lite.h"
|
|
||||||
|
|
||||||
#define is_io_plugin(p) ((p)->io.cb && (p)->io.fd >= 0)
|
#define is_io_plugin(p) ((p)->io.cb && (p)->io.fd > 0)
|
||||||
|
#define SEARCH_PLUGIN(str) \
|
||||||
|
PLUGIN_ITERATOR(p, tmp) { \
|
||||||
|
if (!strcmp(p->name, str)) \
|
||||||
|
return p; \
|
||||||
|
}
|
||||||
|
|
||||||
static char *plugpath = NULL; /* Set by first load. */
|
static char *plugpath = NULL; /* Set by first load. */
|
||||||
static TAILQ_HEAD(plugin_head, plugin) plugins = TAILQ_HEAD_INITIALIZER(plugins);
|
static TAILQ_HEAD(plugin_head, plugin) plugins = TAILQ_HEAD_INITIALIZER(plugins);
|
||||||
@@ -43,6 +49,22 @@ static TAILQ_HEAD(plugin_head, plugin) plugins = TAILQ_HEAD_INITIALIZER(plugins
|
|||||||
static void check_plugin_depends(plugin_t *plugin);
|
static void check_plugin_depends(plugin_t *plugin);
|
||||||
#endif
|
#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)
|
int plugin_register(plugin_t *plugin)
|
||||||
{
|
{
|
||||||
if (!plugin) {
|
if (!plugin) {
|
||||||
@@ -55,18 +77,19 @@ int plugin_register(plugin_t *plugin)
|
|||||||
#ifndef ENABLE_STATIC
|
#ifndef ENABLE_STATIC
|
||||||
Dl_info info;
|
Dl_info info;
|
||||||
|
|
||||||
if (!dladdr(plugin, &info) || !info.dli_fname)
|
if (dladdr(plugin, &info) && info.dli_fname)
|
||||||
plugin->name = "unknown";
|
plugin->name = basename(info.dli_fname);
|
||||||
else
|
|
||||||
plugin->name = (char *)info.dli_fname;
|
|
||||||
#else
|
|
||||||
plugin->name = "unknown";
|
|
||||||
#endif
|
#endif
|
||||||
|
if (!plugin->name)
|
||||||
|
plugin->name = "unknown";
|
||||||
}
|
}
|
||||||
|
plugin->name = trim_ext(strdup(plugin->name));
|
||||||
|
|
||||||
/* Already registered? */
|
/* Already registered? */
|
||||||
if (plugin_find(plugin->name)) {
|
if (plugin_find(plugin->name)) {
|
||||||
_d("... %s already loaded.", plugin->name);
|
_d("... %s already loaded", plugin->name);
|
||||||
|
free(plugin->name);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,25 +109,8 @@ int plugin_unregister(plugin_t *plugin)
|
|||||||
#ifndef ENABLE_STATIC
|
#ifndef ENABLE_STATIC
|
||||||
TAILQ_REMOVE(&plugins, plugin, link);
|
TAILQ_REMOVE(&plugins, plugin, link);
|
||||||
|
|
||||||
if (plugin->svc.cb) {
|
_d("%s exiting ...", plugin->name);
|
||||||
svc_t *svc;
|
free(plugin->name);
|
||||||
|
|
||||||
/* Unregister plugin callback for all matching services */
|
|
||||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
|
||||||
if (strcmp(svc->cmd, plugin->name))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
svc->cb = NULL;
|
|
||||||
svc->dynamic = 0;
|
|
||||||
svc->dynamic_stop = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Unload plugin */
|
|
||||||
if (dlclose(plugin->handle)) {
|
|
||||||
_e("Failed unloading %s ...", plugin->name);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
_d("Finit built statically, cannot unload %s ...", plugin->name);
|
_d("Finit built statically, cannot unload %s ...", plugin->name);
|
||||||
#endif
|
#endif
|
||||||
@@ -112,14 +118,6 @@ int plugin_unregister(plugin_t *plugin)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// _d("Comparing %s against plugin %s", str, p->name);
|
|
||||||
#define SEARCH_PLUGIN(str) \
|
|
||||||
PLUGIN_ITERATOR(p, tmp) { \
|
|
||||||
if (!strcmp(p->name, str)) \
|
|
||||||
return p; \
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* plugin_find - Find a plugin by name
|
* plugin_find - Find a plugin by name
|
||||||
* @name: With or without path, or .so extension
|
* @name: With or without path, or .so extension
|
||||||
@@ -153,9 +151,9 @@ plugin_t *plugin_find(char *name)
|
|||||||
char path[CMD_SIZE];
|
char path[CMD_SIZE];
|
||||||
|
|
||||||
noext = strcmp(name + strlen(name) - 3, ".so");
|
noext = strcmp(name + strlen(name) - 3, ".so");
|
||||||
snprintf (path, sizeof(path), "%s%s%s%s", plugpath,
|
snprintf(path, sizeof(path), "%s%s%s%s", plugpath,
|
||||||
fisslashdir(plugpath) ? "" : "/",
|
fisslashdir(plugpath) ? "" : "/",
|
||||||
name, noext ? ".so" : "");
|
name, noext ? ".so" : "");
|
||||||
|
|
||||||
SEARCH_PLUGIN(path);
|
SEARCH_PLUGIN(path);
|
||||||
}
|
}
|
||||||
@@ -165,18 +163,26 @@ plugin_t *plugin_find(char *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Private daemon API *******************************************************/
|
/* Private daemon API *******************************************************/
|
||||||
void plugin_run_hooks(hook_point_t no)
|
|
||||||
|
/* 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_t *p, *tmp;
|
||||||
|
|
||||||
PLUGIN_ITERATOR(p, tmp) {
|
PLUGIN_ITERATOR(p, tmp) {
|
||||||
if (p->hook[no].cb) {
|
if (p->hook[no].cb) {
|
||||||
_d("Calling %s hook n:o %d from runloop...", basename(p->name), no);
|
_d("Calling %s hook n:o %d (arg: %p) ...", basename(p->name), no, arg);
|
||||||
p->hook[no].cb(p->hook[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 */
|
/* 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)
|
static void generic_io_cb(uev_t *w, void *arg, int events)
|
||||||
{
|
{
|
||||||
@@ -194,17 +200,32 @@ static void generic_io_cb(uev_t *w, void *arg, int events)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup any I/O callbacks for plugins that use them */
|
int plugin_io_init(plugin_t *p)
|
||||||
static void init_plugins(uev_ctx_t *ctx)
|
|
||||||
{
|
{
|
||||||
|
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_t *p, *tmp;
|
||||||
|
|
||||||
PLUGIN_ITERATOR(p, tmp) {
|
PLUGIN_ITERATOR(p, tmp) {
|
||||||
if (is_io_plugin(p)) {
|
if (plugin_io_init(p))
|
||||||
_d("Initializing plugin %s for I/O", basename(p->name));
|
fail++;
|
||||||
uev_io_init(ctx, &p->watcher, generic_io_cb, p, p->io.fd, p->io.flags);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef ENABLE_STATIC
|
#ifndef ENABLE_STATIC
|
||||||
@@ -239,10 +260,7 @@ static int load_one(char *path, char *name)
|
|||||||
snprintf(sofile, sizeof(sofile), "%s/%s%s", path, name, noext ? ".so" : "");
|
snprintf(sofile, sizeof(sofile), "%s/%s%s", path, name, noext ? ".so" : "");
|
||||||
|
|
||||||
_d("Loading plugin %s ...", basename(sofile));
|
_d("Loading plugin %s ...", basename(sofile));
|
||||||
/* Ignore leak, we do not support unloading of plugins atm.
|
handle = dlopen(sofile, RTLD_LAZY | RTLD_LOCAL);
|
||||||
* TODO: Add handle to list of loaded plugins, dlclose() on
|
|
||||||
* plugin_unregister() */
|
|
||||||
handle = dlopen(sofile, RTLD_LAZY | RTLD_GLOBAL);
|
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
_e("Failed loading plugin %s: %s", sofile, dlerror());
|
_e("Failed loading plugin %s: %s", sofile, dlerror());
|
||||||
return 1;
|
return 1;
|
||||||
@@ -250,7 +268,7 @@ static int load_one(char *path, char *name)
|
|||||||
|
|
||||||
plugin = TAILQ_LAST(&plugins, plugin_head);
|
plugin = TAILQ_LAST(&plugins, plugin_head);
|
||||||
if (!plugin) {
|
if (!plugin) {
|
||||||
_e("Plugin %s failed to register, unloading from memory.", sofile);
|
_e("Plugin %s failed to register, unloading from memory", sofile);
|
||||||
dlclose(handle);
|
dlclose(handle);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -286,21 +304,20 @@ static void check_plugin_depends(plugin_t *plugin)
|
|||||||
load_one(plugpath, plugin->depends[i]);
|
load_one(plugpath, plugin->depends[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* ENABLE_STATIC */
|
|
||||||
|
|
||||||
int plugin_load_all(uev_ctx_t *ctx, char *path)
|
static int load_plugins(char *path)
|
||||||
{
|
{
|
||||||
int fail = 0;
|
int fail = 0;
|
||||||
#ifndef ENABLE_STATIC
|
DIR *dp;
|
||||||
DIR *dp = opendir(path);
|
|
||||||
struct dirent *entry;
|
struct dirent *entry;
|
||||||
|
|
||||||
if (verbose)
|
if (!silent)
|
||||||
print_desc("Loading plugins", NULL);
|
print_desc("Loading plugins", NULL);
|
||||||
|
|
||||||
|
dp = opendir(path);
|
||||||
if (!dp) {
|
if (!dp) {
|
||||||
_e("Failed, cannot open plugin directory %s: %s", path, strerror(errno));
|
_e("Failed, cannot open plugin directory %s: %s", path, strerror(errno));
|
||||||
fail = 1;
|
return 1;
|
||||||
goto exit;
|
|
||||||
}
|
}
|
||||||
plugpath = path;
|
plugpath = path;
|
||||||
|
|
||||||
@@ -308,34 +325,51 @@ int plugin_load_all(uev_ctx_t *ctx, char *path)
|
|||||||
if (entry->d_name[0] == '.')
|
if (entry->d_name[0] == '.')
|
||||||
continue; /* Skip . and .. directories */
|
continue; /* Skip . and .. directories */
|
||||||
|
|
||||||
// print_desc(" Loading plugin ", basename(plugin));
|
|
||||||
if (load_one(path, entry->d_name))
|
if (load_one(path, entry->d_name))
|
||||||
fail++;
|
fail++;
|
||||||
// print_result(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
closedir(dp);
|
closedir(dp);
|
||||||
|
|
||||||
|
return fail;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
_d("Finit built statically, not loading plugins from %s ...", path);
|
static int load_plugins(char *UNUSED(path))
|
||||||
if (verbose)
|
{
|
||||||
|
if (!silent)
|
||||||
print_desc("Initializing plugins", NULL);
|
print_desc("Initializing plugins", NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif /* ENABLE_STATIC */
|
#endif /* ENABLE_STATIC */
|
||||||
|
|
||||||
/* Always initialize plugins */
|
int plugin_init(uev_ctx_t *ctx, char *path)
|
||||||
init_plugins(ctx);
|
{
|
||||||
|
int fail = 1;
|
||||||
|
|
||||||
#ifndef ENABLE_STATIC
|
if (!load_plugins(path))
|
||||||
exit:
|
fail = init_plugins(ctx);
|
||||||
#endif
|
|
||||||
if (verbose)
|
if (!silent)
|
||||||
print_result(fail);
|
print_result(fail);
|
||||||
|
|
||||||
return 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:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
@@ -24,9 +24,14 @@
|
|||||||
#ifndef FINIT_PLUGIN_H_
|
#ifndef FINIT_PLUGIN_H_
|
||||||
#define FINIT_PLUGIN_H_
|
#define FINIT_PLUGIN_H_
|
||||||
|
|
||||||
#include "queue.h" /* BSD sys/queue.h API */
|
#include <uev/uev.h>
|
||||||
|
#include <lite/queue.h> /* BSD sys/queue.h API */
|
||||||
|
|
||||||
#include "svc.h"
|
#include "svc.h"
|
||||||
#include "libuev/uev.h"
|
|
||||||
|
#ifndef PLUGIN_PATH /* Fallback for --enable-static builds */
|
||||||
|
#define PLUGIN_PATH "/dev/null"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define PLUGIN_DEP_MAX 10
|
#define PLUGIN_DEP_MAX 10
|
||||||
#define PLUGIN_IO_READ UEV_READ
|
#define PLUGIN_IO_READ UEV_READ
|
||||||
@@ -51,6 +56,8 @@ typedef enum {
|
|||||||
|
|
||||||
/* Runtime hooks */
|
/* Runtime hooks */
|
||||||
HOOK_SVC_RECONF,
|
HOOK_SVC_RECONF,
|
||||||
|
HOOK_SVC_LOST,
|
||||||
|
HOOK_SVC_START,
|
||||||
HOOK_RUNLEVEL_CHANGE,
|
HOOK_RUNLEVEL_CHANGE,
|
||||||
|
|
||||||
/* Shutdown hooks */
|
/* Shutdown hooks */
|
||||||
@@ -97,13 +104,6 @@ typedef struct plugin {
|
|||||||
* NOTE: Must match cmd for services or inetd plugins! */
|
* NOTE: Must match cmd for services or inetd plugins! */
|
||||||
char *name;
|
char *name;
|
||||||
|
|
||||||
/* Service callback to be called once per lap of runloop. */
|
|
||||||
struct {
|
|
||||||
int dynamic; /* Callback wants external events as well. */
|
|
||||||
int dynamic_stop; /* Callback allows dynamic events to stop. */
|
|
||||||
svc_cmd_t (*cb)(svc_t *svc, int event, void *event_arg);
|
|
||||||
} svc;
|
|
||||||
|
|
||||||
/* List of hook callbacks. */
|
/* List of hook callbacks. */
|
||||||
struct {
|
struct {
|
||||||
void *arg; /* Optional argument to callback func. */
|
void *arg; /* Optional argument to callback func. */
|
||||||
@@ -127,6 +127,8 @@ typedef struct plugin {
|
|||||||
} plugin_t;
|
} plugin_t;
|
||||||
|
|
||||||
/* Public plugin API */
|
/* Public plugin API */
|
||||||
|
int plugin_io_init (plugin_t *plugin);
|
||||||
|
|
||||||
int plugin_register (plugin_t *plugin);
|
int plugin_register (plugin_t *plugin);
|
||||||
int plugin_unregister (plugin_t *plugin);
|
int plugin_unregister (plugin_t *plugin);
|
||||||
|
|
||||||
@@ -137,7 +139,6 @@ plugin_t *plugin_find (char *name);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
/*.la
|
||||||
|
/*.lo
|
||||||
|
/.deps/*
|
||||||
|
/.libs/*
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
# Plugin based services architecture for finit
|
|
||||||
-include ../config.mk
|
|
||||||
|
|
||||||
TOPDIR ?= $(shell pwd)
|
|
||||||
CFLAGS += -fPIC
|
|
||||||
LDFLAGS := $(filter-out -rdynamic, $(LDFLAGS))
|
|
||||||
LDFLAGS += -shared
|
|
||||||
ifneq ($(STATIC), 1)
|
|
||||||
PLUGINS ?= initctl.so alsa-utils.so bootmisc.so dbus.so hwclock.so \
|
|
||||||
resolvconf.so urandom.so x11-common.so tty.so time.so \
|
|
||||||
netlink.so
|
|
||||||
DEPS := $(PLUGINS:.so=.d)
|
|
||||||
endif
|
|
||||||
|
|
||||||
include ../common.mk
|
|
||||||
|
|
||||||
ifneq ($(STATIC), 1)
|
|
||||||
all: $(PLUGINS)
|
|
||||||
else
|
|
||||||
all:
|
|
||||||
@true
|
|
||||||
endif
|
|
||||||
|
|
||||||
clean:
|
|
||||||
-@$(RM) $(PLUGINS)
|
|
||||||
|
|
||||||
distclean:
|
|
||||||
-@$(RM) *.o *.so $(JUNK) $(DEPS)
|
|
||||||
|
|
||||||
ifneq ($(STATIC), 1)
|
|
||||||
install: all
|
|
||||||
@install -d $(DESTDIR)$(plugindir)
|
|
||||||
@for plugin in $(PLUGINS); do \
|
|
||||||
echo " INSTALL $(DESTDIR)$(plugindir)/$$plugin"; \
|
|
||||||
$(STRIPINST) $$plugin $(DESTDIR)$(plugindir)/$$plugin; \
|
|
||||||
done
|
|
||||||
|
|
||||||
uninstall:
|
|
||||||
-@for plugin in $(PLUGINS); do \
|
|
||||||
echo " RM $(DESTDIR)$(plugindir)/$$plugin"; \
|
|
||||||
rm $(DESTDIR)$(plugindir)/$$plugin 2>/dev/null; \
|
|
||||||
done
|
|
||||||
-@rmdir $(DESTDIR)$(plugindir) 2>/dev/null
|
|
||||||
else
|
|
||||||
install:
|
|
||||||
@true
|
|
||||||
uninstall:
|
|
||||||
@true
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifneq ($(MAKECMDGOALS),distclean)
|
|
||||||
-include $(DEPS)
|
|
||||||
endif
|
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
AM_LDFLAGS = -module -avoid-version -shared
|
||||||
|
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 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 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
|
||||||
+14
-13
@@ -1,6 +1,6 @@
|
|||||||
/* Save and restore ALSA sound settings using alsactl
|
/* Save and restore ALSA sound settings using alsactl
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com>
|
* Copyright (c) 2012-2016 Joachim Nilsson <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -21,31 +21,33 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <lite/lite.h>
|
||||||
#include "../finit.h"
|
#include "../finit.h"
|
||||||
#include "../helpers.h"
|
#include "../helpers.h"
|
||||||
#include "../plugin.h"
|
#include "../plugin.h"
|
||||||
#include "libite/lite.h"
|
|
||||||
|
#define ALSACTL "/usr/sbin/alsactl"
|
||||||
|
|
||||||
static void save(void *UNUSED(arg))
|
static void save(void *UNUSED(arg))
|
||||||
{
|
{
|
||||||
_d("Saving sound settings ...");
|
if (fexist(ALSACTL)) {
|
||||||
run_interactive("/usr/sbin/alsactl -g store", "Saving sound settings");
|
_d("Saving sound settings ...");
|
||||||
|
run_interactive(ALSACTL " -g store", "Saving sound settings");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void restore(void *UNUSED(arg))
|
static void restore(void *UNUSED(arg))
|
||||||
{
|
{
|
||||||
_d("Restoring sound settings ...");
|
if (fexist(ALSACTL)) {
|
||||||
run_interactive("/usr/sbin/alsactl -g restore", "Restoring sound settings");
|
_d("Restoring sound settings ...");
|
||||||
|
run_interactive(ALSACTL " -g restore", "Restoring sound settings");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
.name = __FILE__,
|
.name = __FILE__,
|
||||||
.hook[HOOK_BASEFS_UP] = {
|
.hook[HOOK_BASEFS_UP] = { .cb = restore },
|
||||||
.cb = restore
|
.hook[HOOK_SHUTDOWN] = { .cb = save }
|
||||||
},
|
|
||||||
.hook[HOOK_SHUTDOWN] = {
|
|
||||||
.cb = save
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
@@ -61,7 +63,6 @@ PLUGIN_EXIT(plugin_exit)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
+43
-24
@@ -1,6 +1,6 @@
|
|||||||
/* Setup necessary files for UTMP, tracking logins
|
/* Setup necessary system files for, e.g. UTMP (tracking logins)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com>
|
* Copyright (c) 2012-2016 Joachim Nilsson <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -22,23 +22,26 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <utmp.h>
|
#include <lite/lite.h>
|
||||||
|
|
||||||
#include "../config.h"
|
#include "../config.h"
|
||||||
#include "../finit.h"
|
#include "../finit.h"
|
||||||
#include "../helpers.h"
|
#include "../helpers.h"
|
||||||
#include "../plugin.h"
|
#include "../plugin.h"
|
||||||
#include "libite/lite.h"
|
#include "../utmp-api.h"
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup standard FHS 2.3 structure in /var, and
|
* Setup standard FHS 2.3 structure in /var, and write runlevel to UTMP
|
||||||
* write runlevel to UTMP, needed by, e.g., printerdrake.
|
|
||||||
*/
|
*/
|
||||||
static void setup(void *UNUSED(arg))
|
static void setup(void *UNUSED(arg))
|
||||||
{
|
{
|
||||||
#ifdef RUNLEVEL
|
int gid;
|
||||||
struct utmp entry;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_d("Setting up FHS structure in /var ...");
|
_d("Setting up FHS structure in /var ...");
|
||||||
makedir("/var/cache", 0755);
|
makedir("/var/cache", 0755);
|
||||||
@@ -47,28 +50,44 @@ static void setup(void *UNUSED(arg))
|
|||||||
makedir("/var/lib/misc", 0755);
|
makedir("/var/lib/misc", 0755);
|
||||||
makedir("/var/lib/alarm", 0755);
|
makedir("/var/lib/alarm", 0755);
|
||||||
makedir("/var/lib/urandom",0755);
|
makedir("/var/lib/urandom",0755);
|
||||||
makedir("/var/lock", 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/lock/subsys",0755); /* Needed by D-Bus plugin */
|
||||||
makedir("/var/log", 0755);
|
makedir("/var/log", 0755);
|
||||||
makedir("/var/mail", 0755);
|
makedir("/var/mail", 0755);
|
||||||
makedir("/var/opt", 0755);
|
makedir("/var/opt", 0755);
|
||||||
makedir("/var/run", 0755);
|
|
||||||
makedir("/var/spool", 0755);
|
makedir("/var/spool", 0755);
|
||||||
makedir("/var/spool/cron", 0755);
|
makedir("/var/spool/cron", 0755);
|
||||||
makedir("/var/tmp", 0755);
|
makedir("/var/tmp", 0755);
|
||||||
makedir("/var/empty", 0755);
|
makedir("/var/empty", 0755);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If /etc/group or "utmp" group is missing,
|
||||||
|
* default to "root"/"wheel" group
|
||||||
|
*/
|
||||||
_d("Setting up necessary UTMP files ...");
|
_d("Setting up necessary UTMP files ...");
|
||||||
touch("/var/run/utmp");
|
gid = getgroup("utmp");
|
||||||
chown("/var/run/utmp", 0, getgroup("utmp"));
|
if (gid < 0)
|
||||||
|
gid = 0;
|
||||||
|
|
||||||
#ifdef RUNLEVEL
|
/*
|
||||||
memset(&entry, 0, sizeof(struct utmp));
|
* UTMP actually needs multiple db files
|
||||||
entry.ut_type = RUN_LVL;
|
*/
|
||||||
entry.ut_pid = '0' + RUNLEVEL;
|
create("/var/run/utmp", 0644, 0, gid); /* Currently logged in */
|
||||||
setutent();
|
create("/var/log/wtmp", 0644, 0, gid); /* Login history */
|
||||||
pututline(&entry);
|
create("/var/log/btmp", 0600, 0, gid); /* Failed logins */
|
||||||
endutent();
|
create("/var/log/lastlog", 0644, 0, gid);
|
||||||
#endif
|
|
||||||
|
/* Set BOOT_TIME UTMP entry */
|
||||||
|
utmp_set_boot();
|
||||||
|
|
||||||
#ifdef TOUCH_ETC_NETWORK_RUN_IFSTATE
|
#ifdef TOUCH_ETC_NETWORK_RUN_IFSTATE
|
||||||
touch("/etc/network/run/ifstate");
|
touch("/etc/network/run/ifstate");
|
||||||
@@ -77,12 +96,13 @@ static void setup(void *UNUSED(arg))
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
_d("Setting up misc files ...");
|
_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/lldpd", 0755); /* Needed by lldpd */
|
||||||
makedir("/var/run/pluto", 0755); /* Needed by Openswan */
|
makedir("/var/run/pluto", 0755); /* Needed by Openswan */
|
||||||
makedir("/var/run/quagga", 0755); /* Needed by Quagga */
|
makedir("/var/run/quagga", 0755); /* Needed by Quagga */
|
||||||
makedir("/var/log/quagga", 0755); /* Needed by Quagga */
|
makedir("/var/log/quagga", 0755); /* Needed by Quagga */
|
||||||
makedir("/var/run/sshd", 01755); /* OpenSSH */
|
makedir("/var/run/sshd", 01755); /* OpenSSH */
|
||||||
makefifo("/dev/xconsole", 0640); /* sysklogd */
|
makefifo("/dev/xconsole", 0640); /* sysklogd */
|
||||||
chown("/dev/xconsole", 0, getgroup("tty"));
|
chown("/dev/xconsole", 0, getgroup("tty"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +125,6 @@ PLUGIN_EXIT(plugin_exit)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
@@ -0,0 +1,114 @@
|
|||||||
|
/* 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 len)
|
||||||
|
{
|
||||||
|
size_t num;
|
||||||
|
static size_t pos = 0;
|
||||||
|
const char pattern[] = PATTERN;
|
||||||
|
|
||||||
|
len = 72;
|
||||||
|
if (pos + len > sizeof(pattern)) {
|
||||||
|
num = sizeof(pattern) - pos;
|
||||||
|
len -= num;
|
||||||
|
} else {
|
||||||
|
num = 72;
|
||||||
|
len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(&buf[0], &pattern[pos], num--);
|
||||||
|
if (len++)
|
||||||
|
strncpy(&buf[num], pattern, len);
|
||||||
|
strcat(buf, "\r\n");
|
||||||
|
|
||||||
|
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 type)
|
||||||
|
{
|
||||||
|
int sd = STDIN_FILENO;
|
||||||
|
ssize_t len;
|
||||||
|
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 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:
|
||||||
|
*/
|
||||||
+1
-4
@@ -22,23 +22,21 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <lite/lite.h>
|
||||||
|
|
||||||
#include "../finit.h"
|
#include "../finit.h"
|
||||||
#include "../config.h"
|
#include "../config.h"
|
||||||
#include "../helpers.h"
|
#include "../helpers.h"
|
||||||
#include "../plugin.h"
|
#include "../plugin.h"
|
||||||
#include "libite/lite.h"
|
|
||||||
|
|
||||||
static void setup(void *UNUSED(arg))
|
static void setup(void *UNUSED(arg))
|
||||||
{
|
{
|
||||||
#ifdef HAVE_DBUS
|
|
||||||
_d("Starting D-Bus ...");
|
_d("Starting D-Bus ...");
|
||||||
makedir("/var/run/dbus", 0755);
|
makedir("/var/run/dbus", 0755);
|
||||||
makedir("/var/lock/subsys/messagebus", 0755);
|
makedir("/var/lock/subsys/messagebus", 0755);
|
||||||
run("dbus-uuidgen --ensure");
|
run("dbus-uuidgen --ensure");
|
||||||
erase("/var/run/dbus/pid");
|
erase("/var/run/dbus/pid");
|
||||||
run_interactive("dbus-daemon --system", "Starting D-Bus");
|
run_interactive("dbus-daemon --system", "Starting D-Bus");
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
@@ -61,7 +59,6 @@ PLUGIN_EXIT(plugin_exit)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* 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 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:
|
||||||
|
*/
|
||||||
+2
-2
@@ -21,10 +21,11 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <lite/lite.h>
|
||||||
|
|
||||||
#include "../finit.h"
|
#include "../finit.h"
|
||||||
#include "../helpers.h"
|
#include "../helpers.h"
|
||||||
#include "../plugin.h"
|
#include "../plugin.h"
|
||||||
#include "libite/lite.h"
|
|
||||||
|
|
||||||
static void save(void *UNUSED(arg))
|
static void save(void *UNUSED(arg))
|
||||||
{
|
{
|
||||||
@@ -62,7 +63,6 @@ PLUGIN_EXIT(plugin_exit)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
+58
-9
@@ -30,6 +30,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h> /* read() */
|
#include <unistd.h> /* read() */
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <lite/lite.h>
|
||||||
|
|
||||||
#include "../finit.h"
|
#include "../finit.h"
|
||||||
#include "../conf.h"
|
#include "../conf.h"
|
||||||
@@ -37,9 +38,16 @@
|
|||||||
#include "../plugin.h"
|
#include "../plugin.h"
|
||||||
#include "../sig.h"
|
#include "../sig.h"
|
||||||
#include "../service.h"
|
#include "../service.h"
|
||||||
#include "libite/lite.h"
|
|
||||||
|
/*
|
||||||
|
* Old-style SysV shutdown sends a setenv cmd INIT_HALT with "=HALT",
|
||||||
|
* "=POWERDOWN", or "" to cancel shutdown, before requesting change to
|
||||||
|
* runlevel 6 over the /dev/initctl FIFO.
|
||||||
|
*/
|
||||||
|
shutop_t halt = SHUT_DEFAULT;
|
||||||
|
|
||||||
static void parse(void *arg, int fd, int events);
|
static void parse(void *arg, int fd, int events);
|
||||||
|
static void setup(void *arg);
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
.name = __FILE__,
|
.name = __FILE__,
|
||||||
@@ -47,6 +55,10 @@ static plugin_t plugin = {
|
|||||||
.cb = parse,
|
.cb = parse,
|
||||||
.flags = PLUGIN_IO_READ,
|
.flags = PLUGIN_IO_READ,
|
||||||
},
|
},
|
||||||
|
.hook[HOOK_BASEFS_UP] = {
|
||||||
|
.cb = setup
|
||||||
|
},
|
||||||
|
.depends = { "bootmisc", },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void fifo_open(void)
|
static void fifo_open(void)
|
||||||
@@ -58,7 +70,36 @@ static void fifo_open(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Standard reboot/shutdown utilities talk to init using /dev/initctl.
|
/*
|
||||||
|
* 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 /dev/initctl.
|
||||||
* We should check if the fifo was recreated and reopen it.
|
* We should check if the fifo was recreated and reopen it.
|
||||||
*/
|
*/
|
||||||
static void parse(void *UNUSED(arg), int fd, int UNUSED(events))
|
static void parse(void *UNUSED(arg), int fd, int UNUSED(events))
|
||||||
@@ -92,13 +133,12 @@ static void parse(void *UNUSED(arg), int fd, int UNUSED(events))
|
|||||||
case INIT_CMD_RUNLVL:
|
case INIT_CMD_RUNLVL:
|
||||||
switch (rq.runlevel) {
|
switch (rq.runlevel) {
|
||||||
case '0':
|
case '0':
|
||||||
_d("Halting system (SIGUSR2)");
|
_d("Halting system (SIGUSR1 or SIGUSR2)");
|
||||||
do_shutdown(SIGUSR2);
|
do_shutdown(halt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
case 'S':
|
case 'S':
|
||||||
_d("Cannot enter bootstrap after boot ...");
|
|
||||||
rq.runlevel = '1';
|
rq.runlevel = '1';
|
||||||
/* Fall through to regular processing */
|
/* Fall through to regular processing */
|
||||||
|
|
||||||
@@ -109,8 +149,8 @@ static void parse(void *UNUSED(arg), int fd, int UNUSED(events))
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case '6':
|
case '6':
|
||||||
_d("Rebooting system (SIGUSR1)");
|
_d("Rebooting system (SIGTERM)");
|
||||||
do_shutdown(SIGUSR1);
|
do_shutdown(SHUT_REBOOT);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -123,6 +163,10 @@ static void parse(void *UNUSED(arg), int fd, int UNUSED(events))
|
|||||||
service_reload_dynamic();
|
service_reload_dynamic();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case INIT_CMD_SETENV:
|
||||||
|
set_env(rq.data);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_d("Unsupported cmd: %d", rq.cmd);
|
_d("Unsupported cmd: %d", rq.cmd);
|
||||||
break;
|
break;
|
||||||
@@ -133,12 +177,18 @@ static void parse(void *UNUSED(arg), int fd, int UNUSED(events))
|
|||||||
fifo_open();
|
fifo_open();
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
/* 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);
|
_d("Setting up %s", FINIT_FIFO);
|
||||||
makefifo(FINIT_FIFO, 0600);
|
makefifo(FINIT_FIFO, 0600);
|
||||||
|
|
||||||
fifo_open();
|
fifo_open();
|
||||||
|
plugin_io_init(&plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
PLUGIN_INIT(plugin_init)
|
||||||
|
{
|
||||||
plugin_register(&plugin);
|
plugin_register(&plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,7 +199,6 @@ PLUGIN_EXIT(plugin_exit)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* 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:
|
||||||
|
*/
|
||||||
+22
-16
@@ -16,6 +16,7 @@
|
|||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <net/if.h> /* IFNAMSIZ */
|
#include <net/if.h> /* IFNAMSIZ */
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
@@ -25,7 +26,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "../finit.h"
|
#include "../finit.h"
|
||||||
#include "../event.h"
|
#include "../cond.h"
|
||||||
#include "../helpers.h"
|
#include "../helpers.h"
|
||||||
#include "../plugin.h"
|
#include "../plugin.h"
|
||||||
|
|
||||||
@@ -86,13 +87,10 @@ static void nl_route(struct nlmsghdr *nlmsg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((!dst && !mask) && (gw || idx)) {
|
if ((!dst && !mask) && (gw || idx)) {
|
||||||
char msg[MAX_ARG_LEN];
|
|
||||||
|
|
||||||
if (nlmsg->nlmsg_type == RTM_DELROUTE)
|
if (nlmsg->nlmsg_type == RTM_DELROUTE)
|
||||||
snprintf(msg, sizeof(msg), "GW:DN");
|
cond_clear("net/route/default");
|
||||||
else
|
else
|
||||||
snprintf(msg, sizeof(msg), "GW:UP");
|
cond_set("net/route/default");
|
||||||
event_dispatch(msg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,19 +121,28 @@ static void nl_link(struct nlmsghdr *nlmsg)
|
|||||||
* New interface has appearad, or interface flags has changed.
|
* New interface has appearad, or interface flags has changed.
|
||||||
* Check ifi_flags here to see if the interface is UP/DOWN
|
* Check ifi_flags here to see if the interface is UP/DOWN
|
||||||
*/
|
*/
|
||||||
if (i->ifi_change & IFF_UP)
|
if (i->ifi_change & IFF_UP) {
|
||||||
snprintf(msg, sizeof(msg), "IF%s:%s",
|
snprintf(msg, sizeof(msg), "net/%s/up", ifname);
|
||||||
(i->ifi_flags & IFF_UP) ? "UP" : "DN",
|
|
||||||
ifname);
|
if (i->ifi_flags & IFF_UP)
|
||||||
else
|
cond_set(msg);
|
||||||
snprintf(msg, sizeof(msg), "IFADD:%s", ifname);
|
else
|
||||||
event_dispatch(msg);
|
cond_clear(msg);
|
||||||
|
|
||||||
|
if (string_compare("lo", ifname)) {
|
||||||
|
snprintf(msg, sizeof(msg), "net/%s/exist", ifname);
|
||||||
|
cond_set(msg);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
snprintf(msg, sizeof(msg), "net/%s/exist", ifname);
|
||||||
|
cond_set(msg);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTM_DELLINK:
|
case RTM_DELLINK:
|
||||||
/* NOTE: Interface has dissapeared, not link down ... */
|
/* NOTE: Interface has dissapeared, not link down ... */
|
||||||
snprintf(msg, sizeof(msg), "IFDEL:%s", ifname);
|
snprintf(msg, sizeof(msg), "net/%s/exist", ifname);
|
||||||
event_dispatch(msg);
|
cond_clear(msg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTM_NEWADDR:
|
case RTM_NEWADDR:
|
||||||
@@ -220,7 +227,6 @@ PLUGIN_EXIT(plugin_exit)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* 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:
|
||||||
|
*/
|
||||||
@@ -21,10 +21,11 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <lite/lite.h>
|
||||||
|
|
||||||
#include "../finit.h"
|
#include "../finit.h"
|
||||||
#include "../helpers.h"
|
#include "../helpers.h"
|
||||||
#include "../plugin.h"
|
#include "../plugin.h"
|
||||||
#include "libite/lite.h"
|
|
||||||
|
|
||||||
static void setup(void *UNUSED(arg))
|
static void setup(void *UNUSED(arg))
|
||||||
{
|
{
|
||||||
@@ -85,7 +86,6 @@ PLUGIN_EXIT(plugin_exit)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
+51
-22
@@ -1,4 +1,4 @@
|
|||||||
/* Optional inetd plugin for time (rdate) protocol RFC 868
|
/* Optional inetd plugin for Time Protocol (rdate), RFC 868
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015 Joachim Nilsson <troglobit@gmail.com>
|
* Copyright (c) 2015 Joachim Nilsson <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
@@ -28,43 +28,73 @@
|
|||||||
|
|
||||||
#include "../plugin.h"
|
#include "../plugin.h"
|
||||||
|
|
||||||
|
#define NAME "time"
|
||||||
|
|
||||||
/* UNIX epoch starts midnight, 1st Jan, 1970 */
|
/* UNIX epoch starts midnight, 1st Jan, 1970 */
|
||||||
#define EPOCH_OFFSET 2208988800ULL
|
#define EPOCH_OFFSET 2208988800ULL
|
||||||
|
|
||||||
/* Return number of seconds since midnight, 1st Jan, 1900 */
|
/* Return number of seconds since midnight, 1st Jan, 1900 */
|
||||||
static int rfc868(int type)
|
static char *rfctime(char *buf, size_t *len)
|
||||||
{
|
{
|
||||||
int sd = STDIN_FILENO;
|
|
||||||
time_t now;
|
time_t now;
|
||||||
struct sockaddr_storage sa;
|
|
||||||
socklen_t sa_len = sizeof(sa);
|
|
||||||
|
|
||||||
if (SOCK_DGRAM == type) {
|
|
||||||
int dummy;
|
|
||||||
|
|
||||||
/* Read empty datagram in UDP mode before sending reply. */
|
|
||||||
if (-1 == recvfrom(sd, &dummy, sizeof(dummy), MSG_DONTWAIT, (struct sockaddr *)&sa, &sa_len))
|
|
||||||
return -1; /* On error, close connection. */
|
|
||||||
}
|
|
||||||
|
|
||||||
now = time(NULL);
|
now = time(NULL);
|
||||||
if ((time_t)-1 == now)
|
if ((time_t)-1 == now)
|
||||||
return -1; /* On error, close connection. */
|
return NULL;
|
||||||
|
|
||||||
/* Account for UNIX epoch offset */
|
/*
|
||||||
|
* Account for UNIX epoch offset, and
|
||||||
|
* convert to network byte order
|
||||||
|
*/
|
||||||
now += EPOCH_OFFSET;
|
now += EPOCH_OFFSET;
|
||||||
|
now = htonl(now);
|
||||||
|
|
||||||
/* Convert to network byte order, not explicitly stated in RFC */
|
*len = sizeof(now);
|
||||||
now = htonl(now);
|
memcpy(buf, &now, *len);
|
||||||
|
|
||||||
/* Send reply, ignore error, simply close connection. */
|
return buf;
|
||||||
return sendto(sd, &now, sizeof(now), MSG_DONTWAIT, (struct sockaddr *)&sa, sa_len);
|
}
|
||||||
|
|
||||||
|
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, &len);
|
||||||
|
if (!now)
|
||||||
|
return -1; /* On error, close connection. */
|
||||||
|
|
||||||
|
return sendto(sd, now, len, MSG_DONTWAIT, sa, sa_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cb(int 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 = {
|
static plugin_t plugin = {
|
||||||
.name = "time", /* Must match the inetd /etc/services entry */
|
.name = NAME, /* Must match the inetd /etc/services entry */
|
||||||
.inetd = {
|
.inetd = {
|
||||||
.cmd = rfc868
|
.cmd = cb
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -80,7 +110,6 @@ PLUGIN_EXIT(plugin_exit)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
+5
-4
@@ -27,17 +27,16 @@
|
|||||||
#include <unistd.h> /* read() */
|
#include <unistd.h> /* read() */
|
||||||
#include <sys/inotify.h>
|
#include <sys/inotify.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <lite/lite.h>
|
||||||
|
|
||||||
#include "../finit.h"
|
#include "../finit.h"
|
||||||
#include "../helpers.h"
|
#include "../helpers.h"
|
||||||
#include "../plugin.h"
|
#include "../plugin.h"
|
||||||
#include "../tty.h"
|
#include "../tty.h"
|
||||||
#include "libite/lite.h"
|
|
||||||
|
|
||||||
static void watcher(void *arg, int fd, int events);
|
static void watcher(void *arg, int fd, int events);
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
.name = __FILE__,
|
|
||||||
.io = {
|
.io = {
|
||||||
.cb = watcher,
|
.cb = watcher,
|
||||||
.flags = PLUGIN_IO_READ,
|
.flags = PLUGIN_IO_READ,
|
||||||
@@ -51,7 +50,7 @@ static void setup(void)
|
|||||||
|
|
||||||
plugin.io.fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
plugin.io.fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
||||||
if (-1 == plugin.io.fd || inotify_add_watch(plugin.io.fd, "/dev", IN_CREATE | IN_DELETE) < 0)
|
if (-1 == plugin.io.fd || inotify_add_watch(plugin.io.fd, "/dev", IN_CREATE | IN_DELETE) < 0)
|
||||||
_e("Failed starting TTY watcher: %s", strerror(errno));
|
_pe("Failed starting TTY watcher");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void watcher(void *UNUSED(arg), int fd, int UNUSED(events))
|
static void watcher(void *UNUSED(arg), int fd, int UNUSED(events))
|
||||||
@@ -90,12 +89,14 @@ PLUGIN_INIT(plugin_init)
|
|||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(plugin_exit)
|
||||||
{
|
{
|
||||||
|
if (plugin.io.fd)
|
||||||
|
close(plugin.io.fd);
|
||||||
|
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
+1
-2
@@ -25,12 +25,12 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/time.h> /* gettimeofday() */
|
#include <sys/time.h> /* gettimeofday() */
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <lite/lite.h>
|
||||||
|
|
||||||
#include "../config.h"
|
#include "../config.h"
|
||||||
#include "../finit.h"
|
#include "../finit.h"
|
||||||
#include "../helpers.h"
|
#include "../helpers.h"
|
||||||
#include "../plugin.h"
|
#include "../plugin.h"
|
||||||
#include "libite/lite.h"
|
|
||||||
|
|
||||||
static void setup(void *UNUSED(arg))
|
static void setup(void *UNUSED(arg))
|
||||||
{
|
{
|
||||||
@@ -94,7 +94,6 @@ PLUGIN_EXIT(plugin_exit)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
@@ -24,11 +24,11 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <lite/lite.h>
|
||||||
|
|
||||||
#include "../finit.h"
|
#include "../finit.h"
|
||||||
#include "../helpers.h"
|
#include "../helpers.h"
|
||||||
#include "../plugin.h"
|
#include "../plugin.h"
|
||||||
#include "libite/lite.h"
|
|
||||||
|
|
||||||
static void setup(void *UNUSED(arg))
|
static void setup(void *UNUSED(arg))
|
||||||
{
|
{
|
||||||
@@ -51,6 +51,9 @@ static void setup(void *UNUSED(arg))
|
|||||||
|
|
||||||
makedir("/tmp/.X11-unix", 01777);
|
makedir("/tmp/.X11-unix", 01777);
|
||||||
makedir("/tmp/.ICE-unix", 01777);
|
makedir("/tmp/.ICE-unix", 01777);
|
||||||
|
|
||||||
|
if (fexist("/sbin/restorecon"))
|
||||||
|
run("/sbin/restorecon /tmp/.ICE-unix /tmp/.X11-unix");
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
@@ -73,7 +76,6 @@ PLUGIN_EXIT(plugin_exit)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
@@ -28,22 +28,28 @@
|
|||||||
#include "svc.h"
|
#include "svc.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
|
||||||
uev_ctx_t *ctx; /* Main loop context */
|
/*
|
||||||
|
* Main loop context
|
||||||
|
*/
|
||||||
|
uev_ctx_t *ctx;
|
||||||
|
|
||||||
int api_init (uev_ctx_t *ctx);
|
int api_init (uev_ctx_t *ctx);
|
||||||
|
int api_exit (void);
|
||||||
|
|
||||||
int client (int argc, char *argv[]);
|
int client (int argc, char *argv[]);
|
||||||
|
|
||||||
void service_bootstrap(void);
|
|
||||||
void service_monitor (pid_t lost);
|
void service_monitor (pid_t lost);
|
||||||
|
|
||||||
|
void plugin_run_hook (hook_point_t no, void *arg);
|
||||||
void plugin_run_hooks (hook_point_t no);
|
void plugin_run_hooks (hook_point_t no);
|
||||||
int plugin_load_all (uev_ctx_t *ctx, char *path);
|
|
||||||
|
int plugin_init (uev_ctx_t *ctx, char *path);
|
||||||
|
void plugin_exit (void);
|
||||||
|
|
||||||
#endif /* FINIT_PRIVATE_H_ */
|
#endif /* FINIT_PRIVATE_H_ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
@@ -1,648 +0,0 @@
|
|||||||
/* $OpenBSD: queue.h,v 1.38 2013/07/03 15:05:21 fgsch Exp $ */
|
|
||||||
/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 1991, 1993
|
|
||||||
* The Regents of the University of California. All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the University nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* @(#)queue.h 8.5 (Berkeley) 8/20/94
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _SYS_QUEUE_H_
|
|
||||||
#define _SYS_QUEUE_H_
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file defines five types of data structures: singly-linked lists,
|
|
||||||
* lists, simple queues, tail queues, and circular queues.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* A singly-linked list is headed by a single forward pointer. The elements
|
|
||||||
* are singly linked for minimum space and pointer manipulation overhead at
|
|
||||||
* the expense of O(n) removal for arbitrary elements. New elements can be
|
|
||||||
* added to the list after an existing element or at the head of the list.
|
|
||||||
* Elements being removed from the head of the list should use the explicit
|
|
||||||
* macro for this purpose for optimum efficiency. A singly-linked list may
|
|
||||||
* only be traversed in the forward direction. Singly-linked lists are ideal
|
|
||||||
* for applications with large datasets and few or no removals or for
|
|
||||||
* implementing a LIFO queue.
|
|
||||||
*
|
|
||||||
* A list is headed by a single forward pointer (or an array of forward
|
|
||||||
* pointers for a hash table header). The elements are doubly linked
|
|
||||||
* so that an arbitrary element can be removed without a need to
|
|
||||||
* traverse the list. New elements can be added to the list before
|
|
||||||
* or after an existing element or at the head of the list. A list
|
|
||||||
* may only be traversed in the forward direction.
|
|
||||||
*
|
|
||||||
* A simple queue is headed by a pair of pointers, one the head of the
|
|
||||||
* list and the other to the tail of the list. The elements are singly
|
|
||||||
* linked to save space, so elements can only be removed from the
|
|
||||||
* head of the list. New elements can be added to the list before or after
|
|
||||||
* an existing element, at the head of the list, or at the end of the
|
|
||||||
* list. A simple queue may only be traversed in the forward direction.
|
|
||||||
*
|
|
||||||
* A tail queue is headed by a pair of pointers, one to the head of the
|
|
||||||
* list and the other to the tail of the list. The elements are doubly
|
|
||||||
* linked so that an arbitrary element can be removed without a need to
|
|
||||||
* traverse the list. New elements can be added to the list before or
|
|
||||||
* after an existing element, at the head of the list, or at the end of
|
|
||||||
* the list. A tail queue may be traversed in either direction.
|
|
||||||
*
|
|
||||||
* A circle queue is headed by a pair of pointers, one to the head of the
|
|
||||||
* list and the other to the tail of the list. The elements are doubly
|
|
||||||
* linked so that an arbitrary element can be removed without a need to
|
|
||||||
* traverse the list. New elements can be added to the list before or after
|
|
||||||
* an existing element, at the head of the list, or at the end of the list.
|
|
||||||
* A circle queue may be traversed in either direction, but has a more
|
|
||||||
* complex end of list detection.
|
|
||||||
*
|
|
||||||
* For details on the use of these macros, see the queue(3) manual page.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC))
|
|
||||||
#define _Q_INVALIDATE(a) (a) = ((void *)-1)
|
|
||||||
#else
|
|
||||||
#define _Q_INVALIDATE(a)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Singly-linked List definitions.
|
|
||||||
*/
|
|
||||||
#define SLIST_HEAD(name, type) \
|
|
||||||
struct name { \
|
|
||||||
struct type *slh_first; /* first element */ \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define SLIST_HEAD_INITIALIZER(head) \
|
|
||||||
{ NULL }
|
|
||||||
|
|
||||||
#define SLIST_ENTRY(type) \
|
|
||||||
struct { \
|
|
||||||
struct type *sle_next; /* next element */ \
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Singly-linked List access methods.
|
|
||||||
*/
|
|
||||||
#define SLIST_FIRST(head) ((head)->slh_first)
|
|
||||||
#define SLIST_END(head) NULL
|
|
||||||
#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
|
|
||||||
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
|
|
||||||
|
|
||||||
#define SLIST_FOREACH(var, head, field) \
|
|
||||||
for((var) = SLIST_FIRST(head); \
|
|
||||||
(var) != SLIST_END(head); \
|
|
||||||
(var) = SLIST_NEXT(var, field))
|
|
||||||
|
|
||||||
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
|
|
||||||
for ((var) = SLIST_FIRST(head); \
|
|
||||||
(var) && ((tvar) = SLIST_NEXT(var, field), 1); \
|
|
||||||
(var) = (tvar))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Singly-linked List functions.
|
|
||||||
*/
|
|
||||||
#define SLIST_INIT(head) { \
|
|
||||||
SLIST_FIRST(head) = SLIST_END(head); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
|
|
||||||
(elm)->field.sle_next = (slistelm)->field.sle_next; \
|
|
||||||
(slistelm)->field.sle_next = (elm); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define SLIST_INSERT_HEAD(head, elm, field) do { \
|
|
||||||
(elm)->field.sle_next = (head)->slh_first; \
|
|
||||||
(head)->slh_first = (elm); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define SLIST_REMOVE_AFTER(elm, field) do { \
|
|
||||||
(elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define SLIST_REMOVE_HEAD(head, field) do { \
|
|
||||||
(head)->slh_first = (head)->slh_first->field.sle_next; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define SLIST_REMOVE(head, elm, type, field) do { \
|
|
||||||
if ((head)->slh_first == (elm)) { \
|
|
||||||
SLIST_REMOVE_HEAD((head), field); \
|
|
||||||
} else { \
|
|
||||||
struct type *curelm = (head)->slh_first; \
|
|
||||||
\
|
|
||||||
while (curelm->field.sle_next != (elm)) \
|
|
||||||
curelm = curelm->field.sle_next; \
|
|
||||||
curelm->field.sle_next = \
|
|
||||||
curelm->field.sle_next->field.sle_next; \
|
|
||||||
_Q_INVALIDATE((elm)->field.sle_next); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* List definitions.
|
|
||||||
*/
|
|
||||||
#define LIST_HEAD(name, type) \
|
|
||||||
struct name { \
|
|
||||||
struct type *lh_first; /* first element */ \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define LIST_HEAD_INITIALIZER(head) \
|
|
||||||
{ NULL }
|
|
||||||
|
|
||||||
#define LIST_ENTRY(type) \
|
|
||||||
struct { \
|
|
||||||
struct type *le_next; /* next element */ \
|
|
||||||
struct type **le_prev; /* address of previous next element */ \
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* List access methods
|
|
||||||
*/
|
|
||||||
#define LIST_FIRST(head) ((head)->lh_first)
|
|
||||||
#define LIST_END(head) NULL
|
|
||||||
#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
|
|
||||||
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
|
|
||||||
|
|
||||||
#define LIST_FOREACH(var, head, field) \
|
|
||||||
for((var) = LIST_FIRST(head); \
|
|
||||||
(var)!= LIST_END(head); \
|
|
||||||
(var) = LIST_NEXT(var, field))
|
|
||||||
|
|
||||||
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
|
|
||||||
for ((var) = LIST_FIRST(head); \
|
|
||||||
(var) && ((tvar) = LIST_NEXT(var, field), 1); \
|
|
||||||
(var) = (tvar))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* List functions.
|
|
||||||
*/
|
|
||||||
#define LIST_INIT(head) do { \
|
|
||||||
LIST_FIRST(head) = LIST_END(head); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
|
|
||||||
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
|
|
||||||
(listelm)->field.le_next->field.le_prev = \
|
|
||||||
&(elm)->field.le_next; \
|
|
||||||
(listelm)->field.le_next = (elm); \
|
|
||||||
(elm)->field.le_prev = &(listelm)->field.le_next; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
|
|
||||||
(elm)->field.le_prev = (listelm)->field.le_prev; \
|
|
||||||
(elm)->field.le_next = (listelm); \
|
|
||||||
*(listelm)->field.le_prev = (elm); \
|
|
||||||
(listelm)->field.le_prev = &(elm)->field.le_next; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define LIST_INSERT_HEAD(head, elm, field) do { \
|
|
||||||
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
|
|
||||||
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
|
|
||||||
(head)->lh_first = (elm); \
|
|
||||||
(elm)->field.le_prev = &(head)->lh_first; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define LIST_REMOVE(elm, field) do { \
|
|
||||||
if ((elm)->field.le_next != NULL) \
|
|
||||||
(elm)->field.le_next->field.le_prev = \
|
|
||||||
(elm)->field.le_prev; \
|
|
||||||
*(elm)->field.le_prev = (elm)->field.le_next; \
|
|
||||||
_Q_INVALIDATE((elm)->field.le_prev); \
|
|
||||||
_Q_INVALIDATE((elm)->field.le_next); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define LIST_REPLACE(elm, elm2, field) do { \
|
|
||||||
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
|
|
||||||
(elm2)->field.le_next->field.le_prev = \
|
|
||||||
&(elm2)->field.le_next; \
|
|
||||||
(elm2)->field.le_prev = (elm)->field.le_prev; \
|
|
||||||
*(elm2)->field.le_prev = (elm2); \
|
|
||||||
_Q_INVALIDATE((elm)->field.le_prev); \
|
|
||||||
_Q_INVALIDATE((elm)->field.le_next); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Simple queue definitions.
|
|
||||||
*/
|
|
||||||
#define SIMPLEQ_HEAD(name, type) \
|
|
||||||
struct name { \
|
|
||||||
struct type *sqh_first; /* first element */ \
|
|
||||||
struct type **sqh_last; /* addr of last next element */ \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define SIMPLEQ_HEAD_INITIALIZER(head) \
|
|
||||||
{ NULL, &(head).sqh_first }
|
|
||||||
|
|
||||||
#define SIMPLEQ_ENTRY(type) \
|
|
||||||
struct { \
|
|
||||||
struct type *sqe_next; /* next element */ \
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Simple queue access methods.
|
|
||||||
*/
|
|
||||||
#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
|
|
||||||
#define SIMPLEQ_END(head) NULL
|
|
||||||
#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
|
|
||||||
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
|
|
||||||
|
|
||||||
#define SIMPLEQ_FOREACH(var, head, field) \
|
|
||||||
for((var) = SIMPLEQ_FIRST(head); \
|
|
||||||
(var) != SIMPLEQ_END(head); \
|
|
||||||
(var) = SIMPLEQ_NEXT(var, field))
|
|
||||||
|
|
||||||
#define SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \
|
|
||||||
for ((var) = SIMPLEQ_FIRST(head); \
|
|
||||||
(var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1); \
|
|
||||||
(var) = (tvar))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Simple queue functions.
|
|
||||||
*/
|
|
||||||
#define SIMPLEQ_INIT(head) do { \
|
|
||||||
(head)->sqh_first = NULL; \
|
|
||||||
(head)->sqh_last = &(head)->sqh_first; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
|
|
||||||
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
|
|
||||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
|
||||||
(head)->sqh_first = (elm); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
|
|
||||||
(elm)->field.sqe_next = NULL; \
|
|
||||||
*(head)->sqh_last = (elm); \
|
|
||||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
|
||||||
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
|
|
||||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
|
||||||
(listelm)->field.sqe_next = (elm); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
|
|
||||||
if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
|
|
||||||
(head)->sqh_last = &(head)->sqh_first; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
|
|
||||||
if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
|
|
||||||
== NULL) \
|
|
||||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* XOR Simple queue definitions.
|
|
||||||
*/
|
|
||||||
#define XSIMPLEQ_HEAD(name, type) \
|
|
||||||
struct name { \
|
|
||||||
struct type *sqx_first; /* first element */ \
|
|
||||||
struct type **sqx_last; /* addr of last next element */ \
|
|
||||||
unsigned long sqx_cookie; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define XSIMPLEQ_ENTRY(type) \
|
|
||||||
struct { \
|
|
||||||
struct type *sqx_next; /* next element */ \
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* XOR Simple queue access methods.
|
|
||||||
*/
|
|
||||||
#define XSIMPLEQ_XOR(head, ptr) ((__typeof(ptr))((head)->sqx_cookie ^ \
|
|
||||||
(unsigned long)(ptr)))
|
|
||||||
#define XSIMPLEQ_FIRST(head) XSIMPLEQ_XOR(head, ((head)->sqx_first))
|
|
||||||
#define XSIMPLEQ_END(head) NULL
|
|
||||||
#define XSIMPLEQ_EMPTY(head) (XSIMPLEQ_FIRST(head) == XSIMPLEQ_END(head))
|
|
||||||
#define XSIMPLEQ_NEXT(head, elm, field) XSIMPLEQ_XOR(head, ((elm)->field.sqx_next))
|
|
||||||
|
|
||||||
|
|
||||||
#define XSIMPLEQ_FOREACH(var, head, field) \
|
|
||||||
for ((var) = XSIMPLEQ_FIRST(head); \
|
|
||||||
(var) != XSIMPLEQ_END(head); \
|
|
||||||
(var) = XSIMPLEQ_NEXT(head, var, field))
|
|
||||||
|
|
||||||
#define XSIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \
|
|
||||||
for ((var) = XSIMPLEQ_FIRST(head); \
|
|
||||||
(var) && ((tvar) = XSIMPLEQ_NEXT(head, var, field), 1); \
|
|
||||||
(var) = (tvar))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* XOR Simple queue functions.
|
|
||||||
*/
|
|
||||||
#define XSIMPLEQ_INIT(head) do { \
|
|
||||||
arc4random_buf(&(head)->sqx_cookie, sizeof((head)->sqx_cookie)); \
|
|
||||||
(head)->sqx_first = XSIMPLEQ_XOR(head, NULL); \
|
|
||||||
(head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define XSIMPLEQ_INSERT_HEAD(head, elm, field) do { \
|
|
||||||
if (((elm)->field.sqx_next = (head)->sqx_first) == \
|
|
||||||
XSIMPLEQ_XOR(head, NULL)) \
|
|
||||||
(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
|
|
||||||
(head)->sqx_first = XSIMPLEQ_XOR(head, (elm)); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define XSIMPLEQ_INSERT_TAIL(head, elm, field) do { \
|
|
||||||
(elm)->field.sqx_next = XSIMPLEQ_XOR(head, NULL); \
|
|
||||||
*(XSIMPLEQ_XOR(head, (head)->sqx_last)) = XSIMPLEQ_XOR(head, (elm)); \
|
|
||||||
(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define XSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
|
||||||
if (((elm)->field.sqx_next = (listelm)->field.sqx_next) == \
|
|
||||||
XSIMPLEQ_XOR(head, NULL)) \
|
|
||||||
(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
|
|
||||||
(listelm)->field.sqx_next = XSIMPLEQ_XOR(head, (elm)); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define XSIMPLEQ_REMOVE_HEAD(head, field) do { \
|
|
||||||
if (((head)->sqx_first = XSIMPLEQ_XOR(head, \
|
|
||||||
(head)->sqx_first)->field.sqx_next) == XSIMPLEQ_XOR(head, NULL)) \
|
|
||||||
(head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define XSIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
|
|
||||||
if (((elm)->field.sqx_next = XSIMPLEQ_XOR(head, \
|
|
||||||
(elm)->field.sqx_next)->field.sqx_next) \
|
|
||||||
== XSIMPLEQ_XOR(head, NULL)) \
|
|
||||||
(head)->sqx_last = \
|
|
||||||
XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Tail queue definitions.
|
|
||||||
*/
|
|
||||||
#define TAILQ_HEAD(name, type) \
|
|
||||||
struct name { \
|
|
||||||
struct type *tqh_first; /* first element */ \
|
|
||||||
struct type **tqh_last; /* addr of last next element */ \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define TAILQ_HEAD_INITIALIZER(head) \
|
|
||||||
{ NULL, &(head).tqh_first }
|
|
||||||
|
|
||||||
#define TAILQ_ENTRY(type) \
|
|
||||||
struct { \
|
|
||||||
struct type *tqe_next; /* next element */ \
|
|
||||||
struct type **tqe_prev; /* address of previous next element */ \
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* tail queue access methods
|
|
||||||
*/
|
|
||||||
#define TAILQ_FIRST(head) ((head)->tqh_first)
|
|
||||||
#define TAILQ_END(head) NULL
|
|
||||||
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
|
|
||||||
#define TAILQ_LAST(head, headname) \
|
|
||||||
(*(((struct headname *)((head)->tqh_last))->tqh_last))
|
|
||||||
/* XXX */
|
|
||||||
#define TAILQ_PREV(elm, headname, field) \
|
|
||||||
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
|
|
||||||
#define TAILQ_EMPTY(head) \
|
|
||||||
(TAILQ_FIRST(head) == TAILQ_END(head))
|
|
||||||
|
|
||||||
#define TAILQ_FOREACH(var, head, field) \
|
|
||||||
for((var) = TAILQ_FIRST(head); \
|
|
||||||
(var) != TAILQ_END(head); \
|
|
||||||
(var) = TAILQ_NEXT(var, field))
|
|
||||||
|
|
||||||
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
|
|
||||||
for ((var) = TAILQ_FIRST(head); \
|
|
||||||
(var) != TAILQ_END(head) && \
|
|
||||||
((tvar) = TAILQ_NEXT(var, field), 1); \
|
|
||||||
(var) = (tvar))
|
|
||||||
|
|
||||||
|
|
||||||
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
|
|
||||||
for((var) = TAILQ_LAST(head, headname); \
|
|
||||||
(var) != TAILQ_END(head); \
|
|
||||||
(var) = TAILQ_PREV(var, headname, field))
|
|
||||||
|
|
||||||
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
|
|
||||||
for ((var) = TAILQ_LAST(head, headname); \
|
|
||||||
(var) != TAILQ_END(head) && \
|
|
||||||
((tvar) = TAILQ_PREV(var, headname, field), 1); \
|
|
||||||
(var) = (tvar))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Tail queue functions.
|
|
||||||
*/
|
|
||||||
#define TAILQ_INIT(head) do { \
|
|
||||||
(head)->tqh_first = NULL; \
|
|
||||||
(head)->tqh_last = &(head)->tqh_first; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
|
|
||||||
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
|
|
||||||
(head)->tqh_first->field.tqe_prev = \
|
|
||||||
&(elm)->field.tqe_next; \
|
|
||||||
else \
|
|
||||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
|
||||||
(head)->tqh_first = (elm); \
|
|
||||||
(elm)->field.tqe_prev = &(head)->tqh_first; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
|
|
||||||
(elm)->field.tqe_next = NULL; \
|
|
||||||
(elm)->field.tqe_prev = (head)->tqh_last; \
|
|
||||||
*(head)->tqh_last = (elm); \
|
|
||||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
|
||||||
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
|
|
||||||
(elm)->field.tqe_next->field.tqe_prev = \
|
|
||||||
&(elm)->field.tqe_next; \
|
|
||||||
else \
|
|
||||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
|
||||||
(listelm)->field.tqe_next = (elm); \
|
|
||||||
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
|
|
||||||
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
|
|
||||||
(elm)->field.tqe_next = (listelm); \
|
|
||||||
*(listelm)->field.tqe_prev = (elm); \
|
|
||||||
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define TAILQ_REMOVE(head, elm, field) do { \
|
|
||||||
if (((elm)->field.tqe_next) != NULL) \
|
|
||||||
(elm)->field.tqe_next->field.tqe_prev = \
|
|
||||||
(elm)->field.tqe_prev; \
|
|
||||||
else \
|
|
||||||
(head)->tqh_last = (elm)->field.tqe_prev; \
|
|
||||||
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
|
|
||||||
_Q_INVALIDATE((elm)->field.tqe_prev); \
|
|
||||||
_Q_INVALIDATE((elm)->field.tqe_next); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define TAILQ_REPLACE(head, elm, elm2, field) do { \
|
|
||||||
if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
|
|
||||||
(elm2)->field.tqe_next->field.tqe_prev = \
|
|
||||||
&(elm2)->field.tqe_next; \
|
|
||||||
else \
|
|
||||||
(head)->tqh_last = &(elm2)->field.tqe_next; \
|
|
||||||
(elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
|
|
||||||
*(elm2)->field.tqe_prev = (elm2); \
|
|
||||||
_Q_INVALIDATE((elm)->field.tqe_prev); \
|
|
||||||
_Q_INVALIDATE((elm)->field.tqe_next); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Circular queue definitions.
|
|
||||||
*/
|
|
||||||
#define CIRCLEQ_HEAD(name, type) \
|
|
||||||
struct name { \
|
|
||||||
struct type *cqh_first; /* first element */ \
|
|
||||||
struct type *cqh_last; /* last element */ \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define CIRCLEQ_HEAD_INITIALIZER(head) \
|
|
||||||
{ CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
|
|
||||||
|
|
||||||
#define CIRCLEQ_ENTRY(type) \
|
|
||||||
struct { \
|
|
||||||
struct type *cqe_next; /* next element */ \
|
|
||||||
struct type *cqe_prev; /* previous element */ \
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Circular queue access methods
|
|
||||||
*/
|
|
||||||
#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
|
|
||||||
#define CIRCLEQ_LAST(head) ((head)->cqh_last)
|
|
||||||
#define CIRCLEQ_END(head) ((void *)(head))
|
|
||||||
#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
|
|
||||||
#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
|
|
||||||
#define CIRCLEQ_EMPTY(head) \
|
|
||||||
(CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
|
|
||||||
|
|
||||||
#define CIRCLEQ_FOREACH(var, head, field) \
|
|
||||||
for((var) = CIRCLEQ_FIRST(head); \
|
|
||||||
(var) != CIRCLEQ_END(head); \
|
|
||||||
(var) = CIRCLEQ_NEXT(var, field))
|
|
||||||
|
|
||||||
#define CIRCLEQ_FOREACH_SAFE(var, head, field, tvar) \
|
|
||||||
for ((var) = CIRCLEQ_FIRST(head); \
|
|
||||||
(var) != CIRCLEQ_END(head) && \
|
|
||||||
((tvar) = CIRCLEQ_NEXT(var, field), 1); \
|
|
||||||
(var) = (tvar))
|
|
||||||
|
|
||||||
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
|
|
||||||
for((var) = CIRCLEQ_LAST(head); \
|
|
||||||
(var) != CIRCLEQ_END(head); \
|
|
||||||
(var) = CIRCLEQ_PREV(var, field))
|
|
||||||
|
|
||||||
#define CIRCLEQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
|
|
||||||
for ((var) = CIRCLEQ_LAST(head, headname); \
|
|
||||||
(var) != CIRCLEQ_END(head) && \
|
|
||||||
((tvar) = CIRCLEQ_PREV(var, headname, field), 1); \
|
|
||||||
(var) = (tvar))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Circular queue functions.
|
|
||||||
*/
|
|
||||||
#define CIRCLEQ_INIT(head) do { \
|
|
||||||
(head)->cqh_first = CIRCLEQ_END(head); \
|
|
||||||
(head)->cqh_last = CIRCLEQ_END(head); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
|
||||||
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
|
|
||||||
(elm)->field.cqe_prev = (listelm); \
|
|
||||||
if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
|
|
||||||
(head)->cqh_last = (elm); \
|
|
||||||
else \
|
|
||||||
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
|
|
||||||
(listelm)->field.cqe_next = (elm); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
|
|
||||||
(elm)->field.cqe_next = (listelm); \
|
|
||||||
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
|
|
||||||
if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
|
|
||||||
(head)->cqh_first = (elm); \
|
|
||||||
else \
|
|
||||||
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
|
|
||||||
(listelm)->field.cqe_prev = (elm); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
|
|
||||||
(elm)->field.cqe_next = (head)->cqh_first; \
|
|
||||||
(elm)->field.cqe_prev = CIRCLEQ_END(head); \
|
|
||||||
if ((head)->cqh_last == CIRCLEQ_END(head)) \
|
|
||||||
(head)->cqh_last = (elm); \
|
|
||||||
else \
|
|
||||||
(head)->cqh_first->field.cqe_prev = (elm); \
|
|
||||||
(head)->cqh_first = (elm); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
|
|
||||||
(elm)->field.cqe_next = CIRCLEQ_END(head); \
|
|
||||||
(elm)->field.cqe_prev = (head)->cqh_last; \
|
|
||||||
if ((head)->cqh_first == CIRCLEQ_END(head)) \
|
|
||||||
(head)->cqh_first = (elm); \
|
|
||||||
else \
|
|
||||||
(head)->cqh_last->field.cqe_next = (elm); \
|
|
||||||
(head)->cqh_last = (elm); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define CIRCLEQ_REMOVE(head, elm, field) do { \
|
|
||||||
if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
|
|
||||||
(head)->cqh_last = (elm)->field.cqe_prev; \
|
|
||||||
else \
|
|
||||||
(elm)->field.cqe_next->field.cqe_prev = \
|
|
||||||
(elm)->field.cqe_prev; \
|
|
||||||
if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
|
|
||||||
(head)->cqh_first = (elm)->field.cqe_next; \
|
|
||||||
else \
|
|
||||||
(elm)->field.cqe_prev->field.cqe_next = \
|
|
||||||
(elm)->field.cqe_next; \
|
|
||||||
_Q_INVALIDATE((elm)->field.cqe_prev); \
|
|
||||||
_Q_INVALIDATE((elm)->field.cqe_next); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
|
|
||||||
if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
|
|
||||||
CIRCLEQ_END(head)) \
|
|
||||||
(head)->cqh_last = (elm2); \
|
|
||||||
else \
|
|
||||||
(elm2)->field.cqe_next->field.cqe_prev = (elm2); \
|
|
||||||
if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
|
|
||||||
CIRCLEQ_END(head)) \
|
|
||||||
(head)->cqh_first = (elm2); \
|
|
||||||
else \
|
|
||||||
(elm2)->field.cqe_prev->field.cqe_next = (elm2); \
|
|
||||||
_Q_INVALIDATE((elm)->field.cqe_prev); \
|
|
||||||
_Q_INVALIDATE((elm)->field.cqe_next); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#endif /* !_SYS_QUEUE_H_ */
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/* reboot for finit
|
/* reboot, halt, poweroff, shutdown, suspend for finit
|
||||||
*
|
*
|
||||||
* Copyright (c) 2009-2012 Joachim Nilsson <troglobit@gmail.com>
|
* Copyright (c) 2009-2016 Joachim Nilsson <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -21,16 +21,182 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <getopt.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/reboot.h>
|
||||||
|
|
||||||
int main (void)
|
#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;
|
||||||
|
extern char *__progname;
|
||||||
|
|
||||||
|
static void translate(void)
|
||||||
{
|
{
|
||||||
return !!kill(1, SIGINT);
|
if (cmd == CMD_UNKNOWN) {
|
||||||
|
if (!strcmp(__progname, "halt") || !strcmp(__progname, "shutdown"))
|
||||||
|
cmd = CMD_HALT;
|
||||||
|
else if (!strcmp(__progname, "poweroff"))
|
||||||
|
cmd = CMD_POWEROFF;
|
||||||
|
else if (!strcmp(__progname, "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", __progname, 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 */
|
||||||
|
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);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
@@ -30,21 +30,19 @@
|
|||||||
void service_runlevel (int newlevel);
|
void service_runlevel (int newlevel);
|
||||||
int service_register (int type, char *line, time_t mtime, char *username);
|
int service_register (int type, char *line, time_t mtime, char *username);
|
||||||
void service_unregister (svc_t *svc);
|
void service_unregister (svc_t *svc);
|
||||||
svc_cmd_t service_enabled (svc_t *svc, int event, void *arg);
|
int service_enabled (svc_t *svc);
|
||||||
|
|
||||||
int service_start (svc_t *svc);
|
|
||||||
int service_stop (svc_t *svc, int state);
|
|
||||||
void service_start_dynamic (void);
|
|
||||||
void service_stop_dynamic (void);
|
|
||||||
int service_restart (svc_t *svc);
|
|
||||||
int service_reload (svc_t *svc);
|
|
||||||
void service_reload_dynamic (void);
|
void service_reload_dynamic (void);
|
||||||
|
|
||||||
|
void service_step(svc_t *svc);
|
||||||
|
void service_step_all(int types);
|
||||||
|
|
||||||
|
int service_stop_is_done(void);
|
||||||
|
|
||||||
#endif /* FINIT_SERVICE_H_ */
|
#endif /* FINIT_SERVICE_H_ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
@@ -21,27 +21,54 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*
|
*
|
||||||
* The standard SysV init only responds to the following signals:
|
* Finit is often used on embedded and small Linux systems with BusyBox.
|
||||||
* SIGHUP
|
* For compatibility with its existing toolset (halt, poweroff, reboot),
|
||||||
* Has the same effect as telinit q.
|
* the following signals have been adopted:
|
||||||
*
|
*
|
||||||
* SIGUSR1
|
* SIGHUP
|
||||||
* On receipt of this signals, init closes and re-opens its control
|
* Same effect as init/telinit q, reloads *.conf in /etc/finit.d/
|
||||||
* fifo, /dev/initctl. Useful for bootscripts when /dev is remounted.
|
|
||||||
*
|
*
|
||||||
* SIGINT
|
* SIGUSR1
|
||||||
* Normally the kernel sends this signal to init when CTRL-ALT-DEL is
|
* Calls shutdown hooks, including HOOK_SHUTDOWN, stops all running
|
||||||
* pressed. It activates the ctrlaltdel action.
|
* processes, and unmounts all file systems. Then tells kernel to
|
||||||
|
* halt. Most people these days want SIGUSR2 though.
|
||||||
*
|
*
|
||||||
* SIGWINCH
|
* (SysV init and systemd use this to re-open their FIFO/D-Bus.)
|
||||||
* The kernel sends this signal when the KeyboardSignal key is hit.
|
*
|
||||||
* It activates the kbrequest action.
|
* 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.
|
||||||
|
*
|
||||||
|
* SIGWINCH
|
||||||
|
* Sent from kernel when the KeyboardSignal key is pressed. Some
|
||||||
|
* users bind keys, see loadkeys(1), to create consoles on demand.
|
||||||
|
* Finit currently ignores this signal.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
#include <string.h> /* strerror() */
|
#include <string.h> /* strerror() */
|
||||||
#include <sys/reboot.h>
|
#include <sys/reboot.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
#include <lite/lite.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
@@ -51,15 +78,20 @@
|
|||||||
#include "private.h"
|
#include "private.h"
|
||||||
#include "sig.h"
|
#include "sig.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
#include "libite/lite.h"
|
#include "utmp-api.h"
|
||||||
|
|
||||||
static int stopped = 0;
|
static int stopped = 0;
|
||||||
static uev_t sighup_watcher, sigint_watcher, sigpwr_watcher;
|
static uev_t sigterm_watcher, sigusr1_watcher, sigusr2_watcher;
|
||||||
|
static uev_t sighup_watcher, sigint_watcher, sigpwr_watcher;
|
||||||
static uev_t sigchld_watcher, sigsegv_watcher;
|
static uev_t sigchld_watcher, sigsegv_watcher;
|
||||||
static uev_t sigstop_watcher, sigtstp_watcher, sigcont_watcher;
|
static uev_t sigstop_watcher, sigtstp_watcher, sigcont_watcher;
|
||||||
|
|
||||||
|
void mdadm_wait(void);
|
||||||
|
void unmount_tmpfs(void);
|
||||||
|
void unmount_regular(void);
|
||||||
|
|
||||||
void do_shutdown(int sig)
|
|
||||||
|
void do_shutdown(shutop_t op)
|
||||||
{
|
{
|
||||||
touch(SYNC_SHUTDOWN);
|
touch(SYNC_SHUTDOWN);
|
||||||
|
|
||||||
@@ -68,8 +100,8 @@ void do_shutdown(int sig)
|
|||||||
|
|
||||||
/* If we enabled terse mode at boot, restore to previous setting at shutdown */
|
/* If we enabled terse mode at boot, restore to previous setting at shutdown */
|
||||||
if (quiet) {
|
if (quiet) {
|
||||||
verbose = VERBOSE_MODE;
|
silent = SILENT_MODE;
|
||||||
if (verbose) {
|
if (!silent) {
|
||||||
sched_yield();
|
sched_yield();
|
||||||
fputs("\n", stderr);
|
fputs("\n", stderr);
|
||||||
}
|
}
|
||||||
@@ -78,28 +110,64 @@ void do_shutdown(int sig)
|
|||||||
/* Call all shutdown hooks before rebooting... */
|
/* Call all shutdown hooks before rebooting... */
|
||||||
plugin_run_hooks(HOOK_SHUTDOWN);
|
plugin_run_hooks(HOOK_SHUTDOWN);
|
||||||
|
|
||||||
|
/* Update UTMP db */
|
||||||
|
utmp_set_halt();
|
||||||
|
|
||||||
/* Here is where we signal watchdogd to do a forced reset for us */
|
/* Here is where we signal watchdogd to do a forced reset for us */
|
||||||
_d("Sending SIGTERM to all processes.");
|
_d("Sending SIGTERM to all processes");
|
||||||
kill(-1, SIGTERM);
|
kill(-1, SIGTERM);
|
||||||
|
|
||||||
/* Wait for WDT to timeout, should be no more than ~1 sec. */
|
/* Wait for WDT to timeout, should be no more than ~1 sec. */
|
||||||
do_sleep(2);
|
do_sleep(2);
|
||||||
|
|
||||||
_d("Sending SIGKILL to remaining processes.");
|
_d("Sending SIGKILL to remaining processes");
|
||||||
kill(-1, SIGKILL);
|
kill(-1, SIGKILL);
|
||||||
|
|
||||||
sync();
|
/* Exit plugins and API gracefully */
|
||||||
sync();
|
plugin_exit();
|
||||||
_d("Unmounting file systems, remounting / read-only.");
|
api_exit();
|
||||||
run("/bin/umount -fa 2>/dev/null");
|
|
||||||
run("/bin/mount -n -o remount,ro / 2>/dev/null");
|
|
||||||
run("/sbin/swapoff -ea");
|
|
||||||
|
|
||||||
_d("%s.", sig == SIGINT || sig == SIGUSR1 ? "Rebooting" : "Halting");
|
/* Reap 'em */
|
||||||
if (sig == SIGINT || sig == SIGUSR1)
|
while (waitpid(-1, NULL, WNOHANG) > 0)
|
||||||
|
;
|
||||||
|
|
||||||
|
/* Close all local non-console descriptors */
|
||||||
|
for (int fd = 3; fd < 128; fd++)
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
if (vfork()) {
|
||||||
|
/*
|
||||||
|
* Put PID 1 aside and let child perform reboot/halt
|
||||||
|
* kernel may exit child and we don't want to exit PID 1
|
||||||
|
* ... causing "aiii killing init" during reboot ...
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unmount any tmpfs before unmounting swap ... */
|
||||||
|
unmount_tmpfs();
|
||||||
|
run("/sbin/swapoff -e -a");
|
||||||
|
|
||||||
|
/* ... unmount remaining regular file systems. */
|
||||||
|
unmount_regular();
|
||||||
|
|
||||||
|
/* We sit on / so we must remount it ro, try all the things! */
|
||||||
|
run("/bin/mount -n -o remount,ro -t dummytype dummydev /");
|
||||||
|
run("/bin/mount -n -o remount,ro dummydev /");
|
||||||
|
run("/bin/mount -n -o remount,ro /");
|
||||||
|
|
||||||
|
/* Call mdadm to mark any RAID array(s) as clean before halting. */
|
||||||
|
mdadm_wait();
|
||||||
|
|
||||||
|
_d("%s", op == SHUT_REBOOT ? "Rebooting" : "Halting");
|
||||||
|
if (op == SHUT_REBOOT)
|
||||||
reboot(RB_AUTOBOOT);
|
reboot(RB_AUTOBOOT);
|
||||||
|
|
||||||
reboot(RB_POWER_OFF);
|
if (op == SHUT_OFF)
|
||||||
|
reboot(RB_POWER_OFF);
|
||||||
|
|
||||||
|
/* Also fallback if any of the other two fails */
|
||||||
|
reboot(RB_HALT_SYSTEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -112,11 +180,35 @@ static void sighup_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Shut down on INT PWR
|
* SIGINT: Should generate <sys/key/ctrlaltdel> condition, for now reboot
|
||||||
*/
|
*/
|
||||||
static void sigint_cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
|
static void sigint_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
||||||
{
|
{
|
||||||
do_shutdown(w->signo);
|
do_shutdown(SHUT_REBOOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SIGUSR1: BusyBox style halt
|
||||||
|
*/
|
||||||
|
static void sigusr1_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
||||||
|
{
|
||||||
|
do_shutdown(SHUT_HALT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SIGUSR2: BusyBox style poweroff
|
||||||
|
*/
|
||||||
|
static void sigusr2_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
||||||
|
{
|
||||||
|
do_shutdown(SHUT_OFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SIGTERM: BusyBox style reboot
|
||||||
|
*/
|
||||||
|
static void sigterm_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
||||||
|
{
|
||||||
|
do_shutdown(SHUT_REBOOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -207,6 +299,9 @@ void sig_unblock(void)
|
|||||||
sigaddset(&nmask, SIGSTOP);
|
sigaddset(&nmask, SIGSTOP);
|
||||||
sigaddset(&nmask, SIGTSTP);
|
sigaddset(&nmask, SIGTSTP);
|
||||||
sigaddset(&nmask, SIGCONT);
|
sigaddset(&nmask, SIGCONT);
|
||||||
|
sigaddset(&nmask, SIGTERM);
|
||||||
|
sigaddset(&nmask, SIGUSR1);
|
||||||
|
sigaddset(&nmask, SIGUSR2);
|
||||||
sigprocmask(SIG_UNBLOCK, &nmask, NULL);
|
sigprocmask(SIG_UNBLOCK, &nmask, NULL);
|
||||||
|
|
||||||
/* Reset signal handlers that were set by the parent process */
|
/* Reset signal handlers that were set by the parent process */
|
||||||
@@ -231,12 +326,10 @@ void sig_setup(uev_ctx_t *ctx)
|
|||||||
uev_signal_init(ctx, &sigint_watcher, sigint_cb, NULL, SIGINT);
|
uev_signal_init(ctx, &sigint_watcher, sigint_cb, NULL, SIGINT);
|
||||||
uev_signal_init(ctx, &sigpwr_watcher, sigint_cb, NULL, SIGPWR);
|
uev_signal_init(ctx, &sigpwr_watcher, sigint_cb, NULL, SIGPWR);
|
||||||
|
|
||||||
/* Ignore SIGUSR1/2 for now, only BusyBox init implements them as reboot+halt. */
|
/* BusyBox init style signals for halt, power-off and reboot. */
|
||||||
// uev_signal_init(&ctx, &sigusr1_watcher, reopen_initctl_cb, NULL, SIGUSR1);
|
uev_signal_init(ctx, &sigusr1_watcher, sigusr1_cb, NULL, SIGUSR1);
|
||||||
// uev_signal_init(&ctx, &sigusr2_watcher, pwrdwn_cb, NULL, SIGUSR2);
|
uev_signal_init(ctx, &sigusr2_watcher, sigusr2_cb, NULL, SIGUSR2);
|
||||||
|
uev_signal_init(ctx, &sigterm_watcher, sigterm_cb, NULL, SIGTERM);
|
||||||
/* Init must ignore SIGTERM. May otherwise get false SIGTERM in forked children! */
|
|
||||||
IGNSIG(sa, SIGTERM, 0);
|
|
||||||
|
|
||||||
/* Some C APIs may need SIGALRM for implementing timers. */
|
/* Some C APIs may need SIGALRM for implementing timers. */
|
||||||
IGNSIG(sa, SIGALRM, 0);
|
IGNSIG(sa, SIGALRM, 0);
|
||||||
@@ -255,14 +348,11 @@ void sig_setup(uev_ctx_t *ctx)
|
|||||||
uev_signal_init(ctx, &sigtstp_watcher, sigstop_cb, NULL, SIGTSTP);
|
uev_signal_init(ctx, &sigtstp_watcher, sigstop_cb, NULL, SIGTSTP);
|
||||||
uev_signal_init(ctx, &sigcont_watcher, sigcont_cb, NULL, SIGCONT);
|
uev_signal_init(ctx, &sigcont_watcher, sigcont_cb, NULL, SIGCONT);
|
||||||
|
|
||||||
/* Disable CTRL-ALT-DELETE from kernel, we handle shutdown gracefully with SIGINT, above */
|
|
||||||
reboot(RB_DISABLE_CAD);
|
|
||||||
setsid();
|
setsid();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
#define FINIT_SIG_H_
|
#define FINIT_SIG_H_
|
||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include "libuev/uev.h"
|
#include <uev/uev.h>
|
||||||
|
|
||||||
#define SYNC_SHUTDOWN "/var/lock/finit.shutdown"
|
#define SYNC_SHUTDOWN "/var/lock/finit.shutdown"
|
||||||
#define SYNC_STOPPED "/var/lock/finit.stopped"
|
#define SYNC_STOPPED "/var/lock/finit.stopped"
|
||||||
@@ -55,7 +55,18 @@
|
|||||||
sigaction(sig, &sa, NULL); \
|
sigaction(sig, &sa, NULL); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
void do_shutdown (int sig);
|
/*
|
||||||
|
* For old-style /dev/initctl shutdown we default to halt
|
||||||
|
*/
|
||||||
|
#define SHUT_DEFAULT SHUT_HALT
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SHUT_OFF,
|
||||||
|
SHUT_HALT,
|
||||||
|
SHUT_REBOOT
|
||||||
|
} shutop_t;
|
||||||
|
|
||||||
|
void do_shutdown (shutop_t op);
|
||||||
int sig_stopped (void);
|
int sig_stopped (void);
|
||||||
void sig_init (void);
|
void sig_init (void);
|
||||||
void sig_unblock (void);
|
void sig_unblock (void);
|
||||||
@@ -65,7 +76,6 @@ void sig_setup (uev_ctx_t *ctx);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
@@ -0,0 +1,228 @@
|
|||||||
|
/* Finit state machine
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016 Jonas Johansson <jonas.johansson@westermo.se>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h" /* Generated by configure script */
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "finit.h"
|
||||||
|
#include "cond.h"
|
||||||
|
#include "conf.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
#include "private.h"
|
||||||
|
#include "service.h"
|
||||||
|
#include "sig.h"
|
||||||
|
#include "tty.h"
|
||||||
|
#include "sm.h"
|
||||||
|
|
||||||
|
sm_t sm;
|
||||||
|
|
||||||
|
void sm_init(sm_t *sm)
|
||||||
|
{
|
||||||
|
sm->state = SM_BOOTSTRAP_STATE;
|
||||||
|
sm->newlevel = -1;
|
||||||
|
sm->reload = 0;
|
||||||
|
sm->in_teardown = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *sm_status(sm_t *sm)
|
||||||
|
{
|
||||||
|
switch (sm->state) {
|
||||||
|
case SM_BOOTSTRAP_STATE:
|
||||||
|
return "bootstrap";
|
||||||
|
|
||||||
|
case SM_RUNNING_STATE:
|
||||||
|
return "running";
|
||||||
|
|
||||||
|
case SM_RUNLEVEL_CHANGE_STATE:
|
||||||
|
return "runlevel/change";
|
||||||
|
|
||||||
|
case SM_RUNLEVEL_WAIT_STATE:
|
||||||
|
return "runlevel/wait";
|
||||||
|
|
||||||
|
case SM_RELOAD_CHANGE_STATE:
|
||||||
|
return "reload/change";
|
||||||
|
|
||||||
|
case SM_RELOAD_WAIT_STATE:
|
||||||
|
return "reload/wait";
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sm_set_runlevel(sm_t *sm, int newlevel)
|
||||||
|
{
|
||||||
|
sm->newlevel = newlevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sm_set_reload(sm_t *sm)
|
||||||
|
{
|
||||||
|
sm->reload = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sm_is_in_teardown(sm_t *sm)
|
||||||
|
{
|
||||||
|
return sm->in_teardown;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sm_step(sm_t *sm)
|
||||||
|
{
|
||||||
|
sm_state_t old_state;
|
||||||
|
|
||||||
|
restart:
|
||||||
|
old_state = sm->state;
|
||||||
|
|
||||||
|
_d("state: %s", sm_status(sm));
|
||||||
|
|
||||||
|
switch (sm->state) {
|
||||||
|
case SM_BOOTSTRAP_STATE:
|
||||||
|
_d("Bootstrapping all services in runlevel S from %s", FINIT_CONF);
|
||||||
|
service_step_all(SVC_TYPE_RUN | SVC_TYPE_TASK | SVC_TYPE_SERVICE);
|
||||||
|
sm->state = SM_RUNNING_STATE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SM_RUNNING_STATE:
|
||||||
|
/* runlevel changed? */
|
||||||
|
if (sm->newlevel >= 0 && sm->newlevel <= 9) {
|
||||||
|
if (runlevel == sm->newlevel) {
|
||||||
|
sm->newlevel = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sm->state = SM_RUNLEVEL_CHANGE_STATE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* reload ? */
|
||||||
|
if (sm->reload) {
|
||||||
|
sm->reload = 0;
|
||||||
|
sm->state = SM_RELOAD_CHANGE_STATE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SM_RUNLEVEL_CHANGE_STATE:
|
||||||
|
prevlevel = runlevel;
|
||||||
|
runlevel = sm->newlevel;
|
||||||
|
sm->newlevel = -1;
|
||||||
|
|
||||||
|
_d("Setting new runlevel --> %d <-- previous %d", runlevel, prevlevel);
|
||||||
|
runlevel_set(prevlevel, runlevel);
|
||||||
|
|
||||||
|
/* Make sure to (re)load all *.conf in /etc/finit.d/ */
|
||||||
|
conf_reload_dynamic();
|
||||||
|
|
||||||
|
_d("Stopping services services not allowed in new runlevel ...");
|
||||||
|
sm->in_teardown = 1;
|
||||||
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
|
||||||
|
sm->state = SM_RUNLEVEL_WAIT_STATE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SM_RUNLEVEL_WAIT_STATE:
|
||||||
|
/* Need to wait for any services to stop? If so, exit early
|
||||||
|
* and perform second stage from service_monitor later. */
|
||||||
|
if (!service_stop_is_done())
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Prev runlevel services stopped, call hooks before starting new runlevel ... */
|
||||||
|
_d("All services have been stoppped, calling runlevel change hooks ...");
|
||||||
|
plugin_run_hooks(HOOK_RUNLEVEL_CHANGE); /* Reconfigure HW/VLANs/etc here */
|
||||||
|
|
||||||
|
_d("Starting services services new to this runlevel ...");
|
||||||
|
sm->in_teardown = 0;
|
||||||
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
|
||||||
|
/* Cleanup stale services */
|
||||||
|
svc_clean_dynamic(service_unregister);
|
||||||
|
|
||||||
|
/* Disable login in single-user mode as well as shutdown/reboot */
|
||||||
|
if (runlevel == 1 || runlevel == 0 || runlevel == 6)
|
||||||
|
touch("/etc/nologin");
|
||||||
|
else
|
||||||
|
erase("/etc/nologin");
|
||||||
|
|
||||||
|
if (0 == runlevel) {
|
||||||
|
do_shutdown(SHUT_OFF);
|
||||||
|
sm->state = SM_RUNNING_STATE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (6 == runlevel) {
|
||||||
|
do_shutdown(SHUT_REBOOT);
|
||||||
|
sm->state = SM_RUNNING_STATE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No TTYs run at bootstrap, they have a delayed start. */
|
||||||
|
if (prevlevel > 0)
|
||||||
|
tty_runlevel(runlevel);
|
||||||
|
|
||||||
|
sm->state = SM_RUNNING_STATE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SM_RELOAD_CHANGE_STATE:
|
||||||
|
/* First reload all *.conf in /etc/finit.d/ */
|
||||||
|
conf_reload_dynamic();
|
||||||
|
|
||||||
|
/* Then, mark all affected service conditions as in-flux and
|
||||||
|
* let all affected services move to WAITING/HALTED */
|
||||||
|
_d("Stopping services services not allowed after reconf ...");
|
||||||
|
sm->in_teardown = 1;
|
||||||
|
cond_reload();
|
||||||
|
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_INETD);
|
||||||
|
|
||||||
|
sm->state = SM_RELOAD_WAIT_STATE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SM_RELOAD_WAIT_STATE:
|
||||||
|
/* Need to wait for any services to stop? If so, exit early
|
||||||
|
* and perform second stage from service_monitor later. */
|
||||||
|
if (!service_stop_is_done())
|
||||||
|
break;
|
||||||
|
|
||||||
|
sm->in_teardown = 0;
|
||||||
|
/* Cleanup stale services */
|
||||||
|
svc_clean_dynamic(service_unregister);
|
||||||
|
|
||||||
|
_d("Starting services after reconf ...");
|
||||||
|
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_INETD);
|
||||||
|
|
||||||
|
_d("Calling reconf hooks ...");
|
||||||
|
plugin_run_hooks(HOOK_SVC_RECONF);
|
||||||
|
|
||||||
|
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_INETD);
|
||||||
|
_d("Reconfiguration done");
|
||||||
|
|
||||||
|
sm->state = SM_RUNNING_STATE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sm->state != old_state) {
|
||||||
|
goto restart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Variables:
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/* Finit state machine
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016 Jonas Johansson <jonas.johansson@westermo.se>
|
||||||
|
*
|
||||||
|
* 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_SM_H_
|
||||||
|
#define FINIT_SM_H_
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SM_BOOTSTRAP_STATE = 0, /* Init state, bootstrap services */
|
||||||
|
SM_RUNNING_STATE, /* Normal state, services running */
|
||||||
|
SM_RUNLEVEL_CHANGE_STATE, /* A runlevel change has occured */
|
||||||
|
SM_RUNLEVEL_WAIT_STATE, /* Waiting for all stopped runlevel processes to be halted */
|
||||||
|
SM_RELOAD_CHANGE_STATE, /* A reload event has occured */
|
||||||
|
SM_RELOAD_WAIT_STATE, /* Waiting for all stopped reload processes to be halted */
|
||||||
|
} sm_state_t;
|
||||||
|
|
||||||
|
typedef struct sm {
|
||||||
|
sm_state_t state; /* Running, Changed, Waiting, ... */
|
||||||
|
int newlevel; /* Set on runlevel change to new runlevel, -1 if not change */
|
||||||
|
int reload; /* Set on reload event, else 0 */
|
||||||
|
int in_teardown; /* Set when waiting for all processes to be halted */
|
||||||
|
} sm_t;
|
||||||
|
|
||||||
|
extern sm_t sm;
|
||||||
|
|
||||||
|
void sm_init(sm_t *sm);
|
||||||
|
void sm_step(sm_t *sm);
|
||||||
|
void sm_set_runlevel(sm_t *sm, int newlevel);
|
||||||
|
void sm_set_reload(sm_t *sm);
|
||||||
|
int sm_is_in_teardown(sm_t *sm);
|
||||||
|
|
||||||
|
#endif /* FINIT_SM_H_ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Variables:
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
@@ -23,7 +23,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "libite/lite.h"
|
#include <strings.h>
|
||||||
|
#include <lite/lite.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "svc.h"
|
#include "svc.h"
|
||||||
@@ -74,12 +75,22 @@ svc_t *svc_new(char *cmd, int id, int type)
|
|||||||
svc_t *svc = &list[i];
|
svc_t *svc = &list[i];
|
||||||
|
|
||||||
if (svc->type == SVC_TYPE_FREE) {
|
if (svc->type == SVC_TYPE_FREE) {
|
||||||
|
char *desc;
|
||||||
|
|
||||||
memset(svc, 0, sizeof(*svc));
|
memset(svc, 0, sizeof(*svc));
|
||||||
svc->type = type;
|
svc->type = type;
|
||||||
svc->job = job;
|
svc->job = job;
|
||||||
svc->id = id;
|
svc->id = id;
|
||||||
strlcpy(svc->cmd, cmd, sizeof(svc->cmd));
|
strlcpy(svc->cmd, cmd, sizeof(svc->cmd));
|
||||||
|
|
||||||
|
/* Default description, if missing */
|
||||||
|
desc = rindex(cmd, '/');
|
||||||
|
if (desc)
|
||||||
|
desc++;
|
||||||
|
else
|
||||||
|
desc = cmd;
|
||||||
|
strlcpy(svc->desc, desc, sizeof(svc->desc));
|
||||||
|
|
||||||
return svc;
|
return svc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -352,17 +363,27 @@ void svc_mark_dynamic(void)
|
|||||||
svc_t *svc = svc_dynamic_iterator(1);
|
svc_t *svc = svc_dynamic_iterator(1);
|
||||||
|
|
||||||
while (svc) {
|
while (svc) {
|
||||||
svc->dirty = -1;
|
*((int *)&svc->dirty) = -1;
|
||||||
svc = svc_dynamic_iterator(0);
|
svc = svc_dynamic_iterator(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void svc_mark_dirty(svc_t *svc)
|
||||||
|
{
|
||||||
|
*((int *)&svc->dirty) = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void svc_mark_clean(svc_t *svc)
|
||||||
|
{
|
||||||
|
*((int *)&svc->dirty) = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void svc_check_dirty(svc_t *svc, time_t mtime)
|
void svc_check_dirty(svc_t *svc, time_t mtime)
|
||||||
{
|
{
|
||||||
if (svc->mtime != mtime)
|
if (svc->mtime != mtime)
|
||||||
svc->dirty = 1;
|
svc_mark_dirty(svc);
|
||||||
else
|
else
|
||||||
svc->dirty = 0;
|
svc_mark_clean(svc);
|
||||||
svc->mtime = mtime;
|
svc->mtime = mtime;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,7 +402,6 @@ void svc_clean_dynamic(void (*cb)(svc_t *))
|
|||||||
if (svc->dirty == -1 && cb)
|
if (svc->dirty == -1 && cb)
|
||||||
cb(svc);
|
cb(svc);
|
||||||
|
|
||||||
svc->dirty = 0;
|
|
||||||
svc = svc_dynamic_iterator(0);
|
svc = svc_dynamic_iterator(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -406,36 +426,66 @@ int svc_clean_bootstrap(svc_t *svc)
|
|||||||
|
|
||||||
char *svc_status(svc_t *svc)
|
char *svc_status(svc_t *svc)
|
||||||
{
|
{
|
||||||
if (!svc_in_runlevel(svc, runlevel))
|
|
||||||
return "halted";
|
|
||||||
|
|
||||||
switch (svc->state) {
|
switch (svc->state) {
|
||||||
|
case SVC_HALTED_STATE:
|
||||||
|
switch (svc->block) {
|
||||||
|
case SVC_BLOCK_NONE:
|
||||||
|
return "halted";
|
||||||
|
|
||||||
|
case SVC_BLOCK_MISSING:
|
||||||
|
return "missing";
|
||||||
|
|
||||||
|
case SVC_BLOCK_CRASHING:
|
||||||
|
return "crashed";
|
||||||
|
|
||||||
|
case SVC_BLOCK_USER:
|
||||||
|
return "blocked";
|
||||||
|
|
||||||
|
case SVC_BLOCK_INETD_BUSY:
|
||||||
|
return "busy";
|
||||||
|
|
||||||
|
case SVC_BLOCK_RESTARTING:
|
||||||
|
return "restart";
|
||||||
|
}
|
||||||
|
|
||||||
|
case SVC_DONE_STATE:
|
||||||
|
return "done";
|
||||||
|
|
||||||
|
case SVC_STOPPING_STATE:
|
||||||
|
switch (svc->type) {
|
||||||
|
case SVC_TYPE_INETD_CONN:
|
||||||
|
case SVC_TYPE_RUN:
|
||||||
|
case SVC_TYPE_TASK:
|
||||||
|
return "active";
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "stopping";
|
||||||
|
}
|
||||||
|
|
||||||
case SVC_WAITING_STATE:
|
case SVC_WAITING_STATE:
|
||||||
return "waiting";
|
return "waiting";
|
||||||
|
|
||||||
case SVC_PAUSED_STATE:
|
case SVC_READY_STATE:
|
||||||
return "stopped";
|
return "ready";
|
||||||
|
|
||||||
case SVC_CONDHALT_STATE:
|
|
||||||
return "nocond";
|
|
||||||
|
|
||||||
case SVC_RESTART_STATE:
|
|
||||||
return "restart";
|
|
||||||
|
|
||||||
case SVC_RELOAD_STATE:
|
|
||||||
return "reload";
|
|
||||||
|
|
||||||
case SVC_RUNNING_STATE:
|
case SVC_RUNNING_STATE:
|
||||||
if (svc->pid)
|
return "running";
|
||||||
return "running";
|
|
||||||
/* Fall through */
|
|
||||||
|
|
||||||
case SVC_HALTED_STATE:
|
|
||||||
default:
|
default:
|
||||||
break;
|
return "UNKNOWN";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return "halted";
|
const char *svc_dirtystr(svc_t *svc)
|
||||||
|
{
|
||||||
|
if (svc_is_removed(svc))
|
||||||
|
return "removed";
|
||||||
|
if (svc_is_updated(svc))
|
||||||
|
return "updated";
|
||||||
|
if (svc_is_changed(svc))
|
||||||
|
return "UNKNOWN";
|
||||||
|
|
||||||
|
return "clean";
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Same base service, return unique ID */
|
/* Same base service, return unique ID */
|
||||||
@@ -478,7 +528,6 @@ int svc_is_unique(svc_t *svc)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
@@ -28,34 +28,42 @@
|
|||||||
#include <sys/ipc.h> /* IPC_CREAT */
|
#include <sys/ipc.h> /* IPC_CREAT */
|
||||||
#include <sys/shm.h> /* shmat() */
|
#include <sys/shm.h> /* shmat() */
|
||||||
#include <sys/types.h> /* pid_t */
|
#include <sys/types.h> /* pid_t */
|
||||||
#include "libite/lite.h"
|
#include <lite/lite.h>
|
||||||
|
|
||||||
#include "inetd.h"
|
#include "inetd.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef int svc_cmd_t;
|
||||||
SVC_STOP = 0, /* Disabled */
|
|
||||||
SVC_START, /* Enabled */
|
|
||||||
SVC_RELOAD /* Enabled, needs restart */
|
|
||||||
} svc_cmd_t;
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SVC_TYPE_FREE = 0, /* Free to allocate */
|
SVC_TYPE_FREE = 0, /* Free to allocate */
|
||||||
SVC_TYPE_SERVICE, /* Monitored, will be respawned */
|
SVC_TYPE_SERVICE = 1, /* Monitored, will be respawned */
|
||||||
SVC_TYPE_TASK, /* One-shot, runs in parallell */
|
SVC_TYPE_TASK = 2, /* One-shot, runs in parallell */
|
||||||
SVC_TYPE_RUN, /* Like task, but wait for completion */
|
SVC_TYPE_RUN = 4, /* Like task, but wait for completion */
|
||||||
SVC_TYPE_INETD /* Classic inetd service */
|
SVC_TYPE_INETD = 8, /* Classic inetd service */
|
||||||
|
SVC_TYPE_INETD_CONN = 16, /* Single inetd connection */
|
||||||
} svc_type_t;
|
} svc_type_t;
|
||||||
|
|
||||||
|
#define SVC_TYPE_ANY (-1)
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SVC_HALTED_STATE = 0, /* Not allowed in runlevel, or not enabled. */
|
SVC_HALTED_STATE = 0, /* Not allowed in runlevel, or not enabled. */
|
||||||
SVC_WAITING_STATE, /* Waiting for connection (inetd service) */
|
SVC_DONE_STATE, /* Task/Run job has been run */
|
||||||
SVC_PAUSED_STATE, /* Stopped/Paused by user started on reload */
|
SVC_STOPPING_STATE, /* Waiting to collect the child process */
|
||||||
SVC_CONDHALT_STATE, /* Not allowed to run atm. event/state lost */
|
SVC_WAITING_STATE, /* Condition is in flux, process SIGSTOPed */
|
||||||
SVC_RESTART_STATE, /* Restarting service waiting to be stopped */
|
SVC_READY_STATE, /* Enabled but condition not satisfied */
|
||||||
SVC_RELOAD_STATE, /* Reloading services, after .conf changed */
|
SVC_RUNNING_STATE, /* Process running */
|
||||||
SVC_RUNNING_STATE, /* Currently running service, see svc->pid */
|
|
||||||
} svc_state_t;
|
} svc_state_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SVC_BLOCK_NONE = 0,
|
||||||
|
SVC_BLOCK_MISSING,
|
||||||
|
SVC_BLOCK_CRASHING,
|
||||||
|
SVC_BLOCK_USER,
|
||||||
|
SVC_BLOCK_INETD_BUSY,
|
||||||
|
SVC_BLOCK_RESTARTING,
|
||||||
|
} svc_block_t;
|
||||||
|
|
||||||
#define FINIT_SHM_ID 0x494E4954 /* "INIT", see ascii(7) */
|
#define FINIT_SHM_ID 0x494E4954 /* "INIT", see ascii(7) */
|
||||||
#define MAX_ARG_LEN 64
|
#define MAX_ARG_LEN 64
|
||||||
#define MAX_STR_LEN 64
|
#define MAX_STR_LEN 64
|
||||||
@@ -64,29 +72,38 @@ typedef enum {
|
|||||||
#define MAX_NUM_SVC 64 /* Enough? */
|
#define MAX_NUM_SVC 64 /* Enough? */
|
||||||
#define MAX_NUM_SVC_ARGS 32
|
#define MAX_NUM_SVC_ARGS 32
|
||||||
|
|
||||||
/* Default enable for all services, can be stopped by means
|
/*
|
||||||
|
* Default enable for all services, can be stopped by means
|
||||||
* of issuing an initctl call. E.g.
|
* of issuing an initctl call. E.g.
|
||||||
* initctl <stop|start|restart> service */
|
*
|
||||||
|
* initctl <stop|start|restart> service
|
||||||
|
*/
|
||||||
typedef struct svc {
|
typedef struct svc {
|
||||||
/* Instance specifics */
|
/* Instance specifics */
|
||||||
int job, id; /* JOB:ID */
|
int job, id; /* JOB:ID */
|
||||||
|
|
||||||
/* Service details */
|
/* Service details */
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
svc_state_t state; /* Paused, Reloading, Restart, Running, ... */
|
const svc_state_t state; /* Paused, Reloading, Restart, Running, ... */
|
||||||
svc_type_t type;
|
svc_type_t type;
|
||||||
time_t mtime; /* Modification time for .conf from /etc/finit.d/ */
|
time_t mtime; /* Modification time for .conf from /etc/finit.d/ */
|
||||||
int dirty; /* Set if old mtime != new mtime => reloaded,
|
const int dirty; /* Set if old mtime != new mtime => reloaded,
|
||||||
* or -1 when marked for removal */
|
* or -1 when marked for removal */
|
||||||
|
int starting; /* ... waiting for pidfile to be re-asserted */
|
||||||
int runlevels;
|
int runlevels;
|
||||||
int sighup; /* This service supports SIGHUP :) */
|
int sighup; /* This service supports SIGHUP :) */
|
||||||
char events[MAX_ARG_LEN];
|
svc_block_t block; /* Reason that this service is currently blocked */
|
||||||
|
char cond[MAX_ARG_LEN];
|
||||||
|
|
||||||
/* Incremented for each restart by service monitor. */
|
/* Incremented for each restart by service monitor. */
|
||||||
unsigned int restart_counter;
|
const unsigned int restart_counter;
|
||||||
|
|
||||||
/* For inetd services */
|
/* For inetd services */
|
||||||
inetd_t inetd;
|
inetd_t inetd;
|
||||||
|
int stdin_fd;
|
||||||
|
|
||||||
|
/* Set for services we need to redirect stdout/stderr to syslog */
|
||||||
|
int log;
|
||||||
|
|
||||||
/* Identity */
|
/* Identity */
|
||||||
char username[MAX_USER_LEN];
|
char username[MAX_USER_LEN];
|
||||||
@@ -97,15 +114,10 @@ typedef struct svc {
|
|||||||
char args[MAX_NUM_SVC_ARGS][MAX_ARG_LEN];
|
char args[MAX_NUM_SVC_ARGS][MAX_ARG_LEN];
|
||||||
char desc[MAX_STR_LEN];
|
char desc[MAX_STR_LEN];
|
||||||
|
|
||||||
/* For external plugins. If @cb is set, a plugin is loaded.
|
/* Used to forcefully kill services that won't shutdown on
|
||||||
* @dynamic: Set by plugins that want dynamic events.
|
* termination and to delay restarts of crashing services. */
|
||||||
* @dynamic_stop: Set by plugins that allow dyn. events to stop it as well.
|
uev_t timer;
|
||||||
* @private: Can be used freely by plugin, e.g., to store "states".
|
void (*timer_cb)(struct svc *svc);
|
||||||
*/
|
|
||||||
int dynamic;
|
|
||||||
int dynamic_stop;
|
|
||||||
int private;
|
|
||||||
svc_cmd_t (*cb)(struct svc *svc, int event, void *event_arg);
|
|
||||||
} svc_t;
|
} svc_t;
|
||||||
|
|
||||||
typedef struct svc_map svc_map_t;
|
typedef struct svc_map svc_map_t;
|
||||||
@@ -144,29 +156,44 @@ void svc_foreach_dynamic (void (*cb)(svc_t *));
|
|||||||
|
|
||||||
void svc_mark_dynamic (void);
|
void svc_mark_dynamic (void);
|
||||||
void svc_check_dirty (svc_t *svc, time_t mtime);
|
void svc_check_dirty (svc_t *svc, time_t mtime);
|
||||||
|
void svc_mark_dirty (svc_t *svc);
|
||||||
|
void svc_mark_clean (svc_t *svc);
|
||||||
void svc_clean_dynamic (void (*cb)(svc_t *));
|
void svc_clean_dynamic (void (*cb)(svc_t *));
|
||||||
int svc_clean_bootstrap (svc_t *svc);
|
int svc_clean_bootstrap (svc_t *svc);
|
||||||
|
|
||||||
char *svc_status (svc_t *svc);
|
char *svc_status (svc_t *svc);
|
||||||
int svc_next_id (char *cmd);
|
int svc_next_id (char *cmd);
|
||||||
int svc_is_unique (svc_t *svc);
|
int svc_is_unique (svc_t *svc);
|
||||||
|
|
||||||
static inline int svc_in_runlevel(svc_t *svc, int runlevel) { return svc && ISSET(svc->runlevels, runlevel); }
|
static inline int svc_in_runlevel (svc_t *svc, int runlevel) { return svc && ISSET(svc->runlevels, runlevel); }
|
||||||
static inline int svc_has_sighup(svc_t *svc) { return svc && 0 != svc->sighup; }
|
static inline int svc_has_sighup (svc_t *svc) { return svc && 0 != svc->sighup; }
|
||||||
|
|
||||||
static inline int svc_is_dynamic(svc_t *svc) { return svc && 0 != svc->mtime; }
|
static inline void svc_starting (svc_t *svc) { svc->starting = 1; }
|
||||||
static inline int svc_is_removed(svc_t *svc) { return svc && -1 == svc->dirty; }
|
static inline void svc_started (svc_t *svc) { svc->starting = 0; }
|
||||||
static inline int svc_is_changed(svc_t *svc) { return svc && 0 != svc->dirty; }
|
static inline int svc_is_starting (svc_t *svc) { return 0 != svc->starting; }
|
||||||
static inline int svc_is_updated(svc_t *svc) { return svc && 1 == svc->dirty; }
|
|
||||||
|
|
||||||
static inline int svc_is_inetd (svc_t *svc) { return svc && SVC_TYPE_INETD == svc->type; }
|
static inline int svc_is_dynamic (svc_t *svc) { return svc && 0 != svc->mtime; }
|
||||||
static inline int svc_is_daemon (svc_t *svc) { return svc && SVC_TYPE_SERVICE == svc->type; }
|
static inline int svc_is_removed (svc_t *svc) { return svc && -1 == svc->dirty; }
|
||||||
|
static inline int svc_is_changed (svc_t *svc) { return svc && 0 != svc->dirty; }
|
||||||
|
static inline int svc_is_updated (svc_t *svc) { return svc && 1 == svc->dirty; }
|
||||||
|
const char *svc_dirtystr (svc_t *svc);
|
||||||
|
|
||||||
#endif /* FINIT_SVC_H_ */
|
static inline int svc_is_inetd (svc_t *svc) { return svc && SVC_TYPE_INETD == svc->type; }
|
||||||
|
static inline int svc_is_inetd_conn(svc_t *svc) { return svc && SVC_TYPE_INETD_CONN == svc->type; }
|
||||||
|
static inline int svc_is_daemon (svc_t *svc) { return svc && SVC_TYPE_SERVICE == svc->type; }
|
||||||
|
|
||||||
|
static inline int svc_is_blocked (svc_t *svc) { return svc->block != SVC_BLOCK_NONE; }
|
||||||
|
static inline int svc_is_busy (svc_t *svc) { return svc->block == SVC_BLOCK_INETD_BUSY; }
|
||||||
|
static inline void svc_unblock (svc_t *svc) { svc->block = SVC_BLOCK_NONE; }
|
||||||
|
static inline void svc_block (svc_t *svc) { svc->block = SVC_BLOCK_USER; }
|
||||||
|
static inline void svc_busy (svc_t *svc) { svc->block = SVC_BLOCK_INETD_BUSY; }
|
||||||
|
static inline void svc_missing (svc_t *svc) { svc->block = SVC_BLOCK_MISSING; }
|
||||||
|
static inline void svc_crashing (svc_t *svc) { svc->block = SVC_BLOCK_CRASHING; }
|
||||||
|
|
||||||
|
#endif /* FINIT_SVC_H_ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
@@ -24,13 +24,14 @@
|
|||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
#include <lite/lite.h>
|
||||||
|
|
||||||
#include "config.h" /* Generated by configure script */
|
#include "config.h" /* Generated by configure script */
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "libite/lite.h"
|
|
||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
|
#include "utmp-api.h"
|
||||||
|
|
||||||
LIST_HEAD(, tty_node) tty_list = LIST_HEAD_INITIALIZER();
|
LIST_HEAD(, tty_node) tty_list = LIST_HEAD_INITIALIZER();
|
||||||
|
|
||||||
@@ -39,19 +40,19 @@ LIST_HEAD(, tty_node) tty_list = LIST_HEAD_INITIALIZER();
|
|||||||
int tty_register(char *line)
|
int tty_register(char *line)
|
||||||
{
|
{
|
||||||
tty_node_t *entry;
|
tty_node_t *entry;
|
||||||
int insert = 0, baud = 0;
|
int insert = 0;
|
||||||
char *cmd, *dev;
|
char *cmd, *dev, *baud = NULL;
|
||||||
char *runlevels = NULL, *term = NULL;
|
char *runlevels = NULL, *term = NULL;
|
||||||
|
|
||||||
if (!line) {
|
if (!line) {
|
||||||
_e("Invalid input argument.");
|
_e("Invalid input argument");
|
||||||
return errno = EINVAL;
|
return errno = EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = strtok(line, " ");
|
cmd = strtok(line, " ");
|
||||||
if (!cmd) {
|
if (!cmd) {
|
||||||
incomplete:
|
incomplete:
|
||||||
_e("Incomplete tty, cannot register.");
|
_e("Incomplete tty, cannot register");
|
||||||
return errno = EINVAL;
|
return errno = EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +67,7 @@ int tty_register(char *line)
|
|||||||
|
|
||||||
cmd = strtok(NULL, " ");
|
cmd = strtok(NULL, " ");
|
||||||
if (cmd) {
|
if (cmd) {
|
||||||
baud = strtonum(cmd, 50, 4000000, NULL);
|
baud = strdup(cmd);
|
||||||
term = strtok(NULL, " ");
|
term = strtok(NULL, " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,17 +75,19 @@ int tty_register(char *line)
|
|||||||
if (!entry) {
|
if (!entry) {
|
||||||
insert = 1;
|
insert = 1;
|
||||||
entry = calloc(1, sizeof(*entry));
|
entry = calloc(1, sizeof(*entry));
|
||||||
if (!entry)
|
if (!entry) {
|
||||||
|
if (baud)
|
||||||
|
free(baud);
|
||||||
|
|
||||||
return errno = ENOMEM;
|
return errno = ENOMEM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
entry->data.name = strdup(dev);
|
entry->data.name = strdup(dev);
|
||||||
if (!baud)
|
|
||||||
baud = BAUDRATE;
|
|
||||||
entry->data.baud = baud;
|
entry->data.baud = baud;
|
||||||
entry->data.term = term ? strdup(term) : NULL;
|
entry->data.term = term ? strdup(term) : NULL;
|
||||||
entry->data.runlevels = conf_parse_runlevels(runlevels);
|
entry->data.runlevels = conf_parse_runlevels(runlevels);
|
||||||
_d("Registering tty %s at %d baud with term=%s on runlevels %s", dev, baud, term ?: "N/A", runlevels);
|
_d("Registering tty %s at %s baud with term=%s on runlevels %s", dev, baud ?: "NULL", term ?: "N/A", runlevels);
|
||||||
|
|
||||||
if (insert)
|
if (insert)
|
||||||
LIST_INSERT_HEAD(&tty_list, entry, link);
|
LIST_INSERT_HEAD(&tty_list, entry, link);
|
||||||
@@ -127,40 +130,43 @@ tty_node_t *tty_find_by_pid(pid_t pid)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tty_start(finit_tty_t *tty)
|
static char *canonicalize(char *tty)
|
||||||
{
|
{
|
||||||
int i = 0, is_console = 0;
|
struct stat st;
|
||||||
char *cmd, *arg;
|
static char path[80];
|
||||||
char line[FILENAME_MAX];
|
|
||||||
char *args[42];
|
|
||||||
|
|
||||||
if (tty->pid)
|
if (!tty)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
strlcpy(path, tty, sizeof(path));
|
||||||
|
if (stat(path, &st)) {
|
||||||
|
snprintf(path, sizeof(path), "%s%s", _PATH_DEV, tty);
|
||||||
|
if (stat(path, &st))
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!S_ISCHR(st.st_mode))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tty_start(finit_tty_t *fitty)
|
||||||
|
{
|
||||||
|
int is_console = 0;
|
||||||
|
char *tty;
|
||||||
|
|
||||||
|
if (fitty->pid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (console && !strcmp(tty->name, console))
|
tty = canonicalize(fitty->name);
|
||||||
|
if (!tty)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (console && !strcmp(tty, console))
|
||||||
is_console = 1;
|
is_console = 1;
|
||||||
|
|
||||||
if (!strncmp(tty->name, _PATH_DEV, strlen(_PATH_DEV))) {
|
fitty->pid = run_getty(tty, fitty->baud, fitty->term, is_console);
|
||||||
#if defined(GETTY_AGETTY)
|
|
||||||
snprintf(line, sizeof(line), "%s %s %d %s", GETTY, tty->name, tty->baud, tty->term ?: "");
|
|
||||||
#elif defined(GETTY_BUSYBOX)
|
|
||||||
snprintf(line, sizeof(line), "%s %d %s %s", GETTY, tty->baud, tty->name, tty->term ?: "");
|
|
||||||
#else
|
|
||||||
strlcpy(line, FALLBACK_SHELL, sizeof(line));
|
|
||||||
is_console = 1;
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
strlcpy(line, tty->name, sizeof(line));
|
|
||||||
is_console = 1;
|
|
||||||
}
|
|
||||||
cmd = strtok(line, " ");
|
|
||||||
args[i++] = basename(cmd);
|
|
||||||
while ((arg = strtok(NULL, " ")))
|
|
||||||
args[i++] = arg;
|
|
||||||
args[i] = NULL;
|
|
||||||
|
|
||||||
_d("Starting %s: %s on %s", is_console ? "console" : "TTY", cmd, tty->name);
|
|
||||||
tty->pid = run_getty(cmd, args, is_console);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void tty_stop(finit_tty_t *tty)
|
void tty_stop(finit_tty_t *tty)
|
||||||
@@ -197,6 +203,9 @@ int tty_respawn(pid_t pid)
|
|||||||
if (!entry)
|
if (!entry)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/* Set DEAD_PROCESS UTMP entry */
|
||||||
|
utmp_set_dead(pid);
|
||||||
|
|
||||||
/* Clear PID to be able to respawn it. */
|
/* Clear PID to be able to respawn it. */
|
||||||
entry->data.pid = 0;
|
entry->data.pid = 0;
|
||||||
|
|
||||||
@@ -223,7 +232,6 @@ void tty_runlevel(int runlevel)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
@@ -26,13 +26,13 @@
|
|||||||
#define FINIT_TTY_H_
|
#define FINIT_TTY_H_
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include "queue.h" /* BSD sys/queue.h API */
|
#include <lite/queue.h> /* BSD sys/queue.h API */
|
||||||
|
|
||||||
#define EVENT_SIZE ((sizeof(struct inotify_event) + NAME_MAX + 1))
|
#define EVENT_SIZE ((sizeof(struct inotify_event) + NAME_MAX + 1))
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *name;
|
char *name;
|
||||||
int baud;
|
char *baud;
|
||||||
char *term;
|
char *term;
|
||||||
int runlevels;
|
int runlevels;
|
||||||
|
|
||||||
@@ -60,7 +60,6 @@ void tty_runlevel (int runlevel);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
|
|||||||
+184
@@ -0,0 +1,184 @@
|
|||||||
|
/* UTMP API
|
||||||
|
*
|
||||||
|
* 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 <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <utmp.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
#include <lite/lite.h>
|
||||||
|
|
||||||
|
|
||||||
|
static void utmp_strncpy(char *dst, const char *src, size_t dlen)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < dlen && src[i]; i++)
|
||||||
|
dst[i] = src[i];
|
||||||
|
|
||||||
|
if (i < dlen)
|
||||||
|
dst[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int utmp_set(int type, int pid, char *line, char *id, char *user)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
struct utmp ut;
|
||||||
|
struct utsname uts;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case RUN_LVL:
|
||||||
|
case BOOT_TIME:
|
||||||
|
line = "~";
|
||||||
|
id = "~~";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&ut, 0, sizeof(ut));
|
||||||
|
ut.ut_type = type;
|
||||||
|
ut.ut_pid = pid;
|
||||||
|
if (user)
|
||||||
|
utmp_strncpy(ut.ut_user, user, sizeof(ut.ut_user));
|
||||||
|
if (line)
|
||||||
|
utmp_strncpy(ut.ut_line, line, sizeof(ut.ut_line));
|
||||||
|
if (id)
|
||||||
|
utmp_strncpy(ut.ut_id, id, sizeof(ut.ut_id));
|
||||||
|
if (!uname(&uts))
|
||||||
|
utmp_strncpy(ut.ut_host, uts.release, sizeof(ut.ut_host));
|
||||||
|
ut.ut_tv.tv_sec = time(NULL);
|
||||||
|
|
||||||
|
if (type != DEAD_PROCESS) {
|
||||||
|
setutent();
|
||||||
|
result += pututline(&ut) ? 0 : 1;
|
||||||
|
endutent();
|
||||||
|
}
|
||||||
|
updwtmp(_PATH_WTMP, &ut);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int utmp_set_boot(void)
|
||||||
|
{
|
||||||
|
return utmp_set(BOOT_TIME, 0, NULL, NULL, "reboot");
|
||||||
|
}
|
||||||
|
|
||||||
|
int utmp_set_halt(void)
|
||||||
|
{
|
||||||
|
return utmp_set(RUN_LVL, 0, NULL, NULL, "shutdown");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int set_getty(int type, char *tty, char *id, char *user)
|
||||||
|
{
|
||||||
|
char *line;
|
||||||
|
|
||||||
|
if (!tty)
|
||||||
|
line = "";
|
||||||
|
else if (!strncmp(tty, "/dev/", 5))
|
||||||
|
line = tty + 5;
|
||||||
|
else
|
||||||
|
line = tty;
|
||||||
|
|
||||||
|
if (!id) {
|
||||||
|
id = line;
|
||||||
|
if (!strncmp(id, "pts/", 4))
|
||||||
|
id += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return utmp_set(type, getpid(), line, id, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
int utmp_set_init(char *tty, char *id)
|
||||||
|
{
|
||||||
|
return set_getty(INIT_PROCESS, tty, id, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int utmp_set_login(char *tty, char *id)
|
||||||
|
{
|
||||||
|
return set_getty(LOGIN_PROCESS, tty, id, "LOGIN");
|
||||||
|
}
|
||||||
|
|
||||||
|
int utmp_set_dead(int pid)
|
||||||
|
{
|
||||||
|
return utmp_set(DEAD_PROCESS, pid, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int encode(int lvl)
|
||||||
|
{
|
||||||
|
if (!lvl) return 0;
|
||||||
|
return lvl + '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
int utmp_set_runlevel(int pre, int now)
|
||||||
|
{
|
||||||
|
return utmp_set(RUN_LVL, (encode(pre) << 8) | (encode(now) & 0xFF), NULL, NULL, "runlevel");
|
||||||
|
}
|
||||||
|
|
||||||
|
int utmp_show(char *file)
|
||||||
|
{
|
||||||
|
time_t sec;
|
||||||
|
struct utmp *ut;
|
||||||
|
struct tm *sectm;
|
||||||
|
|
||||||
|
int pid;
|
||||||
|
char id[sizeof(ut->ut_id) + 1], user[sizeof(ut->ut_user) + 1], when[80];
|
||||||
|
|
||||||
|
printf("%s =============================================================================================\n", file);
|
||||||
|
utmpname(file);
|
||||||
|
|
||||||
|
setutent();
|
||||||
|
while ((ut = getutent())) {
|
||||||
|
char addr[64];
|
||||||
|
|
||||||
|
memset(id, 0, sizeof(id));
|
||||||
|
strlcpy(id, ut->ut_id, sizeof(id));
|
||||||
|
|
||||||
|
memset(user, 0, sizeof(user));
|
||||||
|
strlcpy(user, ut->ut_user, sizeof(user));
|
||||||
|
|
||||||
|
sec = ut->ut_tv.tv_sec;
|
||||||
|
sectm = localtime(&sec);
|
||||||
|
strftime(when, sizeof(when), "%F %T", sectm);
|
||||||
|
|
||||||
|
pid = ut->ut_pid;
|
||||||
|
if (ut->ut_addr_v6[1] || ut->ut_addr_v6[2] || ut->ut_addr_v6[3])
|
||||||
|
inet_ntop(AF_INET6, ut->ut_addr_v6, addr, sizeof(addr));
|
||||||
|
else
|
||||||
|
inet_ntop(AF_INET, &ut->ut_addr, addr, sizeof(addr));
|
||||||
|
|
||||||
|
printf("[%d] [%05d] [%-4.4s] [%-8.8s] [%-12.12s] [%-20.20s] [%-15.15s] [%-19.19s]\n",
|
||||||
|
ut->ut_type, pid, id, user, ut->ut_line, ut->ut_host, addr, when);
|
||||||
|
}
|
||||||
|
endutent();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Variables:
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
+10
-12
@@ -1,6 +1,6 @@
|
|||||||
/* Event aggregator, also serves as event cache, remembering GW and IFUP states
|
/* UTMP API
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015 Joachim Nilsson <troglobit@gmail.com>
|
* Copyright (c) 2016 Joachim Nilsson <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -21,19 +21,17 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FINIT_EVENT_H_
|
int utmp_set (int type, int pid, char *line, char *id, char *user);
|
||||||
#define FINIT_EVENT_H_
|
int utmp_set_boot (void);
|
||||||
|
int utmp_set_halt (void);
|
||||||
int event_cache_gw (void);
|
int utmp_set_init (char *tty, char *id);
|
||||||
int event_cache_if (char *ifname);
|
int utmp_set_login (char *tty, char *id);
|
||||||
int event_service_cond (char *events);
|
int utmp_set_dead (int pid);
|
||||||
void event_dispatch (char *msg);
|
int utmp_set_runlevel(int pre, int now);
|
||||||
|
int utmp_show (char *file);
|
||||||
#endif /* FINIT_EVENT_H_ */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
* c-file-style: "linux"
|
* c-file-style: "linux"
|
||||||
* End:
|
* End:
|
||||||
Reference in New Issue
Block a user