Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9d9b6b5201 | ||
|
|
c0b74c5e53 | ||
|
|
88a6864fd4 | ||
|
|
2b2c6aaf4e | ||
|
|
8ed37f5fa0 | ||
|
|
8fe4aad53e | ||
|
|
54e5fd2a78 | ||
|
|
1d6737eac1 | ||
|
|
fa0c2f7050 | ||
|
|
70c0a38307 | ||
|
|
217df432d6 | ||
|
|
cfa97253be | ||
|
|
6462bac249 | ||
|
|
b0a1d6bd61 | ||
|
|
ee4768ba53 | ||
|
|
c7c0c723d6 | ||
|
|
b7c1a2a198 | ||
|
|
af45166814 | ||
|
|
1a881389b2 | ||
|
|
6306c757a2 | ||
|
|
3865ce765e | ||
|
|
aa08221666 | ||
|
|
7c8b0df720 | ||
|
|
cb802cd54e | ||
|
|
8379b4927b | ||
|
|
6a7f48970c | ||
|
|
d797754ca8 | ||
|
|
770a79fa89 | ||
|
|
ff24ee3553 | ||
|
|
25c194ef93 | ||
|
|
91a9c83928 | ||
|
|
9b022ed7a4 | ||
|
|
ca3fc057f2 | ||
|
|
bf6e599584 | ||
|
|
89c7171223 | ||
|
|
c41f3f4a06 | ||
|
|
0a54a9624a | ||
|
|
1e238eec61 | ||
|
|
4163527006 | ||
|
|
f06e17ccc6 | ||
|
|
fe41b9c4b8 | ||
|
|
7cf3ef80db | ||
|
|
69016bb8f5 | ||
|
|
f7d5b588c9 | ||
|
|
0ad99ce054 | ||
|
|
1176961e7b | ||
|
|
27c839bc92 | ||
|
|
6149e93aca | ||
|
|
4e7baa807e | ||
|
|
54cfa74042 | ||
|
|
97ce0aa519 | ||
|
|
e72b61c9c9 | ||
|
|
b66069278f | ||
|
|
1192506d43 | ||
|
|
decdc1560a | ||
|
|
f6372de6a9 | ||
|
|
9052248127 | ||
|
|
6ab9c8fad6 | ||
|
|
619bd03551 | ||
|
|
e301877b16 | ||
|
|
3b67afe480 | ||
|
|
9a9a9f4bfe | ||
|
|
f38299bfca | ||
|
|
99901782ff | ||
|
|
912a336997 | ||
|
|
c3eca9fe8f | ||
|
|
225510a270 | ||
|
|
4389fbd8bc | ||
|
|
920382518f | ||
|
|
997a699b7e | ||
|
|
21db27ee75 | ||
|
|
fa0c63070c | ||
|
|
9bfc9092b8 | ||
|
|
1c6464a7a8 | ||
|
|
51adba4387 | ||
|
|
bb1aed1010 | ||
|
|
cf4a1332f9 | ||
|
|
d70fb85aaf | ||
|
|
fc37b854ae | ||
|
|
ca210f5431 | ||
|
|
a19a3c774e | ||
|
|
a4f1330eae | ||
|
|
38d768ac9e | ||
|
|
36b14f9ff7 | ||
|
|
bdbd2afc40 | ||
|
|
33bb6ed5ac | ||
|
|
212083b922 | ||
|
|
55c49a0bf0 | ||
|
|
b369e1cfa2 | ||
|
|
cfefe23275 | ||
|
|
338c358a75 | ||
|
|
fe017642de | ||
|
|
8d271ac5b8 | ||
|
|
744719219e | ||
|
|
7bf2fcb6e3 | ||
|
|
ae9ed20d94 | ||
|
|
a5c9d0a3f4 | ||
|
|
a8c071c5ef | ||
|
|
238f63c0d3 | ||
|
|
41647a814c | ||
|
|
765ef63274 | ||
|
|
6a5f4398a2 | ||
|
|
7fc515678f | ||
|
|
e410a24d13 | ||
|
|
397f67d03a | ||
|
|
b4b9111b33 | ||
|
|
c19489d6c3 | ||
|
|
00a2840853 | ||
|
|
d1718d338e | ||
|
|
58ade5d74e | ||
|
|
c391e04983 | ||
|
|
85fe613b30 | ||
|
|
880ad98dbe | ||
|
|
b1a88df9fc | ||
|
|
aaf7888411 | ||
|
|
6edb01a72b | ||
|
|
636f6678ed | ||
|
|
3b62f46599 | ||
|
|
49f0d94b95 | ||
|
|
abccb26a83 | ||
|
|
0848b9b07a | ||
|
|
c64188bfc5 | ||
|
|
5e789401d4 | ||
|
|
744fdd654f | ||
|
|
f51fde4d46 | ||
|
|
85261c9acd | ||
|
|
6a1082a947 | ||
|
|
2094d2a53a | ||
|
|
d7da177742 | ||
|
|
170e5aa3fd | ||
|
|
f8ef8a1616 | ||
|
|
f5f1a55747 | ||
|
|
a36aade7f4 | ||
|
|
76fc72770e | ||
|
|
b64dbbf8d0 | ||
|
|
d371b85c47 | ||
|
|
053304012f | ||
|
|
12d14aae84 | ||
|
|
6a7f115781 | ||
|
|
423c8d41a7 | ||
|
|
f2cab53e55 | ||
|
|
33fd6f0049 | ||
|
|
e83dcafb02 | ||
|
|
9a98bff23f | ||
|
|
1a2f7d162b | ||
|
|
5579ba16b1 | ||
|
|
510b36645b | ||
|
|
67cd88cd23 | ||
|
|
a04a6eda12 | ||
|
|
94525d6aae | ||
|
|
1d14806fd8 | ||
|
|
5e6f64eec9 | ||
|
|
df22628183 | ||
|
|
4870cab898 | ||
|
|
859c216347 | ||
|
|
931565c425 | ||
|
|
3006caf670 | ||
|
|
1269f082de | ||
|
|
7d444e07a5 | ||
|
|
6ec4dce5f9 | ||
|
|
8a0edbe801 | ||
|
|
46683f8eb8 | ||
|
|
fb16abd855 | ||
|
|
060de93b5b | ||
|
|
231b887b2a | ||
|
|
dddd45e3b5 | ||
|
|
cb9f6213dc | ||
|
|
f33ed869e4 | ||
|
|
4790344fbe | ||
|
|
a40858f162 | ||
|
|
682e80fed5 | ||
|
|
cd91e2c66c | ||
|
|
470549badb | ||
|
|
a85c3628b8 | ||
|
|
53ac0ffdfb | ||
|
|
eee6ffe95c | ||
|
|
a5491b3ded | ||
|
|
a1ea8ff564 | ||
|
|
0dffa731d2 | ||
|
|
9516c28a8a | ||
|
|
fa0a4e8579 | ||
|
|
a487a30814 | ||
|
|
40db4f4f58 | ||
|
|
3a1ad67e92 | ||
|
|
43942ab513 | ||
|
|
3b2f2690e7 | ||
|
|
5684b761da | ||
|
|
59f22c7d27 | ||
|
|
f522a26125 | ||
|
|
efb1d40ffd | ||
|
|
ea591c7580 | ||
|
|
af9a06466c | ||
|
|
7ed9f2ad05 | ||
|
|
65ccc407fa | ||
|
|
7fe9f3c4b6 | ||
|
|
24299ab5d9 | ||
|
|
e9670b87b3 | ||
|
|
406339e755 | ||
|
|
dc7039b8d8 | ||
|
|
90249e50ef | ||
|
|
b8e6954c46 | ||
|
|
4585aa0fb4 | ||
|
|
f2655d14c8 | ||
|
|
6d1d51b28c | ||
|
|
b9d233d19e | ||
|
|
2ec132c75a | ||
|
|
3092d55ec5 | ||
|
|
cd791afea5 | ||
|
|
829405f966 | ||
|
|
72526d9e88 | ||
|
|
f704eab6d7 | ||
|
|
a50bfc016e | ||
|
|
396c1b491f | ||
|
|
df89cc79b9 | ||
|
|
3429901d83 | ||
|
|
dedf885b92 | ||
|
|
93a21197ab | ||
|
|
8a0fffb00d | ||
|
|
7fdb280712 | ||
|
|
0a643953c0 | ||
|
|
fd837a4242 | ||
|
|
2759992dd2 | ||
|
|
d880cd75ae | ||
|
|
29fe8cc73d | ||
|
|
2b6f00f126 | ||
|
|
86e534095d | ||
|
|
865a3a7a4a | ||
|
|
2dc7de3aa2 | ||
|
|
06a5b43005 | ||
|
|
38939cc57e | ||
|
|
a3eadb72a7 |
@@ -66,9 +66,6 @@ how `git commit -s` is used to automatically add a `Signed-off-by`:
|
|||||||
Signed-off-by: Jane Doe <jane.doe@example.com>
|
Signed-off-by: Jane Doe <jane.doe@example.com>
|
||||||
|
|
||||||
|
|
||||||
Another good *counter* example [is this][rambling] ...
|
|
||||||
|
|
||||||
|
|
||||||
Code of Conduct
|
Code of Conduct
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
@@ -79,11 +76,4 @@ Bill & Ted; [be excellent to each other][conduct].
|
|||||||
[github]: https://github.com/troglobit/finit/
|
[github]: https://github.com/troglobit/finit/
|
||||||
[KNF]: https://en.wikipedia.org/wiki/Kernel_Normal_Form
|
[KNF]: https://en.wikipedia.org/wiki/Kernel_Normal_Form
|
||||||
[gitbook]: https://git-scm.com/book/ch5-2.html
|
[gitbook]: https://git-scm.com/book/ch5-2.html
|
||||||
[rambling]: http://stopwritingramblingcommitmessages.com/
|
[conduct]: CODE-OF-CONDUCT.md
|
||||||
[conduct]: https://github.com/troglobit/finit/blob/master/CODE-OF-CONDUCT.md
|
|
||||||
|
|
||||||
<!--
|
|
||||||
-- Local Variables:
|
|
||||||
-- mode: markdown
|
|
||||||
-- End:
|
|
||||||
-->
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: [troglobit]
|
||||||
@@ -13,10 +13,12 @@ compiler:
|
|||||||
- gcc
|
- gcc
|
||||||
- clang
|
- clang
|
||||||
|
|
||||||
|
# The secure: declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||||
|
# via the "travis encrypt" command using the project repo's public key
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
- PKG_CONFIG_PATH=/tmp/lib/pkgconfig
|
||||||
# via the "travis encrypt" command using the project repo's public key
|
- CFLAGS="-W -Wall -Wextra"
|
||||||
- secure: "eOiuHs02lG2Uv146K9dMqucGTWUJFEhpz1oAtwe+kPrRXsXWc20hYMO+DSpMgD05vSvNeQA6p7h7LdRFQ+/g/Obj27TsOE+RKkUvRAtdwzxnKVyii9C/nmML8cFw7rIA0VS8O9mAkVYeyDxNDupBp3e9DPCibhKPvqCvioTnyy4="
|
- secure: "eOiuHs02lG2Uv146K9dMqucGTWUJFEhpz1oAtwe+kPrRXsXWc20hYMO+DSpMgD05vSvNeQA6p7h7LdRFQ+/g/Obj27TsOE+RKkUvRAtdwzxnKVyii9C/nmML8cFw7rIA0VS8O9mAkVYeyDxNDupBp3e9DPCibhKPvqCvioTnyy4="
|
||||||
|
|
||||||
addons:
|
addons:
|
||||||
@@ -28,25 +30,28 @@ addons:
|
|||||||
name: "troglobit/finit"
|
name: "troglobit/finit"
|
||||||
description: "finit | Fast & Extensible init for Linux"
|
description: "finit | Fast & Extensible init for Linux"
|
||||||
notification_email: troglobit@gmail.com
|
notification_email: troglobit@gmail.com
|
||||||
build_command_prepend: "./autogen.sh && PKG_CONFIG_PATH=/tmp/lib/pkgconfig ./configure --prefix=/tmp"
|
build_command_prepend: "./autogen.sh && ./configure --prefix=/tmp"
|
||||||
build_command: "make"
|
build_command: "make"
|
||||||
branch_pattern: dev
|
branch_pattern: dev
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- wget https://github.com/troglobit/libuev/releases/download/v2.1.0/libuev-2.1.0.tar.xz
|
- wget https://github.com/troglobit/libuev/releases/download/v2.2.0/libuev-2.2.0.tar.xz
|
||||||
- wget https://github.com/troglobit/libite/releases/download/v2.0.1/libite-2.0.1.tar.xz
|
- wget https://github.com/troglobit/libite/releases/download/v2.0.1/libite-2.0.1.tar.xz
|
||||||
- tar xf libuev-2.1.0.tar.xz
|
- tar xf libuev-2.2.0.tar.xz
|
||||||
- tar xf libite-2.0.1.tar.xz
|
- tar xf libite-2.0.1.tar.xz
|
||||||
- (cd libuev-2.1.0 && ./configure --prefix=/tmp && make && make install-strip)
|
- (cd libuev-2.2.0 && ./configure --prefix=/tmp && make && make install-strip)
|
||||||
- (cd libite-2.0.1 && ./configure --prefix=/tmp && make && make install-strip)
|
- (cd libite-2.0.1 && ./configure --prefix=/tmp && make && make install-strip)
|
||||||
|
|
||||||
# Custom build script for the time being, no "make test" yet
|
# Custom build script for the time being, no "make test" yet
|
||||||
script:
|
script:
|
||||||
- ./autogen.sh
|
- ./autogen.sh
|
||||||
- PKG_CONFIG_PATH=/tmp/lib/pkgconfig ./configure --prefix=/tmp
|
- ./configure --prefix=/tmp --disable-inetd --enable-static
|
||||||
|
- make clean
|
||||||
|
- make V=1 -j5
|
||||||
|
- ./configure --prefix=/tmp --enable-inetd-echo-plugin --enable-inetd-time-plugin --enable-x11-common-plugin --enable-inetd-chargen-plugin --enable-fallback-shell --enable-watchdog --enable-logit
|
||||||
- cat config.log
|
- cat config.log
|
||||||
- make clean
|
- make clean
|
||||||
- make -j5 V=1
|
- make V=1 -j5
|
||||||
- make install-strip
|
- make install-strip
|
||||||
- tree /tmp
|
- tree /tmp
|
||||||
- ldd /tmp/sbin/finit
|
- ldd /tmp/sbin/finit
|
||||||
|
|||||||
@@ -4,6 +4,128 @@ Change Log
|
|||||||
All relevant changes are documented in this file.
|
All relevant changes are documented in this file.
|
||||||
|
|
||||||
|
|
||||||
|
[3.2][UNRELEASED] - 2020-04-xx
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
Bug fix release, but also cgroups and a new progress!
|
||||||
|
|
||||||
|
https://twitter.com/b0rk/status/1214341831049252870?s=20
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
* Introducing Finit progress 𝓜𝓸𝓭𝓮𝓻𝓷
|
||||||
|
* Support for `sysv` start/stop scripts as well as monitoring forking
|
||||||
|
services, stared using `sysv` or `service` stanza
|
||||||
|
* Support for custom `kill:DELAY`, default 3 sec.
|
||||||
|
* Support for custom `halt:SIGNAL`, default SIGTERM
|
||||||
|
* Support for tracking custom PID files, using `pid:!/path/to/foo.pid`,
|
||||||
|
useful with new `sysv` or `service` which fork to background
|
||||||
|
* Support starting run/task/services without absolute path, trust `$PATH`
|
||||||
|
* Add support for `--disable-doc` and `--disable-contrib` to speed up
|
||||||
|
builds and work around issue with massively parallel builds
|
||||||
|
* Add support for `@console` also for external getty
|
||||||
|
* Add `-b`, batch mode, for non-interactive use to `initctl`
|
||||||
|
* Prefer udev to handle `/dev/` if mdev is also available
|
||||||
|
* Redirect dbus daemon output to syslog
|
||||||
|
* Set `$SHELL`, like `$PATH`, to a sane default value, needed by BusyBox
|
||||||
|
* Finit no longer automatically reloads its `*.conf` files after running
|
||||||
|
`/etc/rc.local` or run-parts. Use `initctl reload` instead.
|
||||||
|
* `initctl` without an argument or option now defaults to list services
|
||||||
|
* Convert built-in watchdog daemon to standalone mini watchdogd, issue #102
|
||||||
|
* Improved watchdog hand-over, now based on `svc_t` and not PID
|
||||||
|
* Extended bootstrap, runlevel S, timeout: 10 --> 120 sec. before services
|
||||||
|
not allowed in the runtime runlevel are unconditionally stopped
|
||||||
|
* Removed `HOOK_SVC_START` and `HOOK_SVC_LOST`, caused more problems
|
||||||
|
than they were worth. Users are encouraged to use accounting instead
|
||||||
|
* Skip displaying "Restarting ..." progress for bootstrap processes
|
||||||
|
* Added a simple work queue mechanism to queue up work at boot + runtime
|
||||||
|
- Postpone deletion of `svc_t` until any `SIGKILL` timer has elapsed
|
||||||
|
- As long as a stepped service changes state we queue another step all
|
||||||
|
event, because services may depend on each other
|
||||||
|
* Require new libuEv API: `uev_init1()` to reduce event cache so that
|
||||||
|
the kernel can invalidate deleted events before enqueing to userspace
|
||||||
|
* Rename `hwclock.so` plugin to `rtc.so` since it now is stand-alone
|
||||||
|
from the `hwclock` tool. Note: the kernel can also be set to load
|
||||||
|
and store RTC to/from system clock at boot/halt as well, issue #110
|
||||||
|
* New plugin to support cold plugging devices, auto-loading of modules
|
||||||
|
at boot. Detects required modules by reading `/sys/devices/*`
|
||||||
|
* New plugin for `/etc/modules-load.d/` by Robert Andersson, Atlas Copco
|
||||||
|
* New `name:foo` support for services, by Robert Andersson, Atlas Copco
|
||||||
|
* New `manual:yes` support for services, by Robert Andersson, Atlas Copco
|
||||||
|
* New `log:console` support for services, by Robert Andersson, Atlas Copco
|
||||||
|
* Support for `:ID` as a string, by Jonas Johansson, Westermo
|
||||||
|
* Support for auto-reload, instead of having to do `initctl reload`,
|
||||||
|
when a service configuration has changed. Disabled by default, but
|
||||||
|
can be enabled with `./configure --enable-auto-reload`
|
||||||
|
* Support for logging security related events, e.g., runlevel change,
|
||||||
|
star/stop or failure to start services, by Jonas Holmberg, Westermo
|
||||||
|
* Mount devtpts with recommended `ptxmode=0666`
|
||||||
|
* Mount /run tmpfs with nosuid,nodev,noexec for added security
|
||||||
|
* Support for `console` as alias for `@console` in tty stanzas
|
||||||
|
* Drop `--enable-rw-roots` configure option, use `rw` for your `/`
|
||||||
|
partition in `/etc/fstab` instead to trigger remount at boot
|
||||||
|
* Drop default tty speed (38400) and use 0 (kernel default) instead
|
||||||
|
* Make `:ID` optional for real, use NULL/zero internally and only
|
||||||
|
force :ID (numbered) for inetd services, this allows ...
|
||||||
|
* Handle use-cases where multiple services share the same PID filem
|
||||||
|
and thus the same condition path, e.g. different instances for
|
||||||
|
different runlevels. Allow custom condition path with `name:foo`
|
||||||
|
syntax, creates conditions w/o a path, and ...
|
||||||
|
* Always append `:ID` qualifier to conditions if set for a service
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
* Fix #96: Start udevd as a proper service
|
||||||
|
* Ensure we track run commands as well as task/service, once per runlevel
|
||||||
|
* Fix #98: FTBFS with `--disable-inetd`
|
||||||
|
* Make sure to unblock UDP inetd services when connection terminates.
|
||||||
|
Regression introduced in v3.1
|
||||||
|
* Ensure run/tasks also go to stopping state on exit, like services,
|
||||||
|
otherwise it is unnecessarily hard to restart them
|
||||||
|
* Fix #99: Do not try to `SIGKILL` inetd services, they are not backed
|
||||||
|
by a PID. This caused a use after free issue crashing finit. Found
|
||||||
|
and fixed by Tobias Waldekranz, Westermo
|
||||||
|
* Fix missing OS/Finit title bug, adds leading newline before banner
|
||||||
|
* Remove "Failed connecting to watchdog ..." error message on systems
|
||||||
|
that do not have a watchdog
|
||||||
|
* Fix #100: Early condition handling may not work if `/var/run` does
|
||||||
|
not yet exist (symlink to `/run`). Added compat layer for access
|
||||||
|
* Fix #103: Register multiple getty if `@console` resolves to >1 TTY,
|
||||||
|
* Fix #105: Only remove /etc/nologin when moving from runlevel 0, 1, 6
|
||||||
|
* Fix #106: Don't mark inetd connections for deletion at .conf reload.
|
||||||
|
Fixed by Jonas Johansson, Westermo
|
||||||
|
* Fix #107: Stop spawned inetd conncections when stopping inetd service.
|
||||||
|
Fixed by Jonas Johansson, Westermo
|
||||||
|
* Fix #109: Support for PID files in sub-directories to `/var/run`
|
||||||
|
* Handle rename of PID files, by Robert Andersson, Atlas Copco
|
||||||
|
* Fix #111: Only restart inetd services when necessary. E.g., if the
|
||||||
|
listening interface is changed. Only stop established connections
|
||||||
|
which are no longer allowed, i.e. do not touch already allowed
|
||||||
|
established connections. Fixed by Jonas Johansson, Westermo
|
||||||
|
* Fix #120: Redirect `stdin` to `/dev/null` for services by default
|
||||||
|
* Fix #122: Switch to `nanosleep()` to achieve "signal safe" sleep,
|
||||||
|
fixed by Jacques de Laval, Westermo
|
||||||
|
* Fix #124: Lingering processes in process group when session leader
|
||||||
|
exits. E.g., lingering `logit` processes when parent dies
|
||||||
|
* Fix: update inetd service args on config change. Found and fixed by
|
||||||
|
Petrus Hellgren, Westermo
|
||||||
|
* Fix service name matching, e.g. for condition handling, may match with
|
||||||
|
wrong service, by Jonas Holmberg, Westermo
|
||||||
|
* Run all run-parts scripts using `/bin/sh -c foo` just like the standard
|
||||||
|
run-parts tool. Found by Magnus Malm, Westermo
|
||||||
|
* Fix `initctl [start | restart]`, should behave the same for services
|
||||||
|
that have crashed. Found by Mattias Walström, Westermo
|
||||||
|
* Wait for bootstrap phase to complete before cleaning out any bootstrap
|
||||||
|
processes that have stopped, they may be restarted again
|
||||||
|
* Reassert condition when an unmodified run/task/service goes from
|
||||||
|
WAITING back to RUNNING again after a reconfiguration event.
|
||||||
|
Found and fixed by Jonas Johansson, Westermo
|
||||||
|
* Restore Ctrl-D and Ctrl-U support in built-in getty
|
||||||
|
* Remove service condition when service is deleted
|
||||||
|
* Fix C++ compilation issues, by Robert Andersson, Atlas Copco
|
||||||
|
* Build fixes for uClibc
|
||||||
|
* Provide service description for built-in watchdog daemon
|
||||||
|
|
||||||
|
|
||||||
[3.1][] - 2018-01-23
|
[3.1][] - 2018-01-23
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
@@ -76,7 +198,7 @@ This version requires at least libuEv v2.1.0 and libite v2.0.1
|
|||||||
possibility of running a second stage mount command before files in
|
possibility of running a second stage mount command before files in
|
||||||
`/run` and similar are created
|
`/run` and similar are created
|
||||||
* Skip `gdbserver` when unleashing the grim reaper at shutdown
|
* Skip `gdbserver` when unleashing the grim reaper at shutdown
|
||||||
* Distribute and install `docs/` and `contrib/` directories
|
* Distribute and install `doc/` and `contrib/` directories
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
|
||||||
@@ -139,7 +261,7 @@ distributions.
|
|||||||
* Ensure plugins always have a default name, file name
|
* Ensure plugins always have a default name, file name
|
||||||
* Reorganization, move all source files to a `src/` sub-directory
|
* Reorganization, move all source files to a `src/` sub-directory
|
||||||
* Add support for `initctl <list|enable|disable> <SVC>`, much needed by
|
* Add support for `initctl <list|enable|disable> <SVC>`, much needed by
|
||||||
distributions. See [docs/distro.md](docs/distro.md) for details
|
distributions. See [doc/distro.md](doc/distro.md) for details
|
||||||
* Remove `UNUSED()` macro, mentioned here because it may have been used
|
* Remove `UNUSED()` macro, mentioned here because it may have been used
|
||||||
by external plugin developers. Set `-Wno-unused-parameter` instead
|
by external plugin developers. Set `-Wno-unused-parameter` instead
|
||||||
* New table headings in `initctl`, using `top` style inverted text
|
* New table headings in `initctl`, using `top` style inverted text
|
||||||
@@ -710,6 +832,7 @@ Major bug fix release.
|
|||||||
* Initial release
|
* Initial release
|
||||||
|
|
||||||
[UNRELEASED]: https://github.com/troglobit/finit/compare/3.1...HEAD
|
[UNRELEASED]: https://github.com/troglobit/finit/compare/3.1...HEAD
|
||||||
|
[3.2]: https://github.com/troglobit/finit/compare/3.1...3.2
|
||||||
[3.1]: https://github.com/troglobit/finit/compare/3.0...3.1
|
[3.1]: https://github.com/troglobit/finit/compare/3.0...3.1
|
||||||
[3.0]: https://github.com/troglobit/finit/compare/2.4...3.0
|
[3.0]: https://github.com/troglobit/finit/compare/2.4...3.0
|
||||||
[2.4]: https://github.com/troglobit/finit/compare/2.3...2.4
|
[2.4]: https://github.com/troglobit/finit/compare/2.3...2.4
|
||||||
|
|||||||
@@ -1,8 +1,15 @@
|
|||||||
ACLOCAL_AMFLAGS = -I m4
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
SUBDIRS = contrib docs plugins src
|
SUBDIRS = plugins src
|
||||||
doc_DATA = README.md LICENSE contrib/finit.conf
|
doc_DATA = README.md LICENSE contrib/finit.conf
|
||||||
EXTRA_DIST = README.md LICENSE ChangeLog.md contrib/finit.conf
|
EXTRA_DIST = README.md LICENSE ChangeLog.md contrib/finit.conf
|
||||||
|
|
||||||
|
if CONTRIB
|
||||||
|
SUBDIRS += contrib
|
||||||
|
endif
|
||||||
|
if DOC
|
||||||
|
SUBDIRS += doc
|
||||||
|
endif
|
||||||
|
|
||||||
# Compat hook
|
# Compat hook
|
||||||
install-dev:
|
install-dev:
|
||||||
@make -C src install-pkgincludeHEADERS
|
@make -C src install-pkgincludeHEADERS
|
||||||
|
|||||||
@@ -1,41 +1,41 @@
|
|||||||
<img align="right" src="images/finit3.png" alt="Finit: Fast Init">
|
[![License Badge][]][License] [![Travis Status]][Travis] [![Coverity Status]][Coverity Scan]
|
||||||
|
<img align="right" src="img/finit3.png" alt="Finit: Fast Init">
|
||||||
|
|
||||||
* [Introduction](#introduction)
|
* [Introduction](#introduction)
|
||||||
* [Features](#features)
|
* [Features](#features)
|
||||||
* [Bootstrap](docs/bootstrap.md#bootstrap)
|
* [Bootstrap](doc/bootstrap.md#bootstrap)
|
||||||
* [Runlevels](#runlevels)
|
* [Runlevels](#runlevels)
|
||||||
* [Syntax](docs/config.md#syntax)
|
* [Syntax](doc/config.md#syntax)
|
||||||
* [Inetd](docs/inetd.md#inetd)
|
* [Inetd](doc/inetd.md#inetd)
|
||||||
* [Runparts & /etc/rc.local](#runparts--etcrclocal)
|
* [Runparts & /etc/rc.local](#runparts--etcrclocal)
|
||||||
* [Hooks, Callbacks & Plugins](docs/plugins.md#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)
|
||||||
* [Tips & Tricks with the kernel cmdline](docs/cmdline.md)
|
* [Tips & Tricks with the kernel cmdline](doc/cmdline.md)
|
||||||
* [Building](docs/build.md#building)
|
* [Building](doc/build.md#building)
|
||||||
* [Running](docs/build.md#running)
|
* [Running](doc/build.md#running)
|
||||||
* [Recovery](docs/build.md#recovery)
|
* [Recovery](doc/build.md#recovery)
|
||||||
* [Debugging](docs/build.md#debugging)
|
* [Debugging](doc/build.md#debugging)
|
||||||
* [Requirements](#requirements)
|
* [Requirements](#requirements)
|
||||||
* [Origin & References](#origin--references)
|
* [Origin & References](#origin--references)
|
||||||
|
|
||||||
|
|
||||||
Introduction
|
Introduction
|
||||||
------------
|
------------
|
||||||
[![License Badge][]][License] [![Travis Status]][Travis] [![Coverity Status]][Coverity Scan]
|
|
||||||
|
|
||||||
Finit is a simple alternative to [SysV init][4] and [systemd][6]. It
|
Finit is a simple alternative to [SysV init][4] and [systemd][6]. It
|
||||||
was reverse engineered from the [EeePC fastinit][] ten years ago by
|
was reverse engineered from the [EeePC fastinit][] over ten years ago
|
||||||
[Claudio Matsuoka][] — "gaps filled with frog DNA …"
|
by [Claudio Matsuoka][] — "gaps filled with frog DNA …"
|
||||||
|
|
||||||
Focus is on small and embedded systems, although Finit is fully usable
|
Focus is on small and embedded systems, although Finit is fully usable
|
||||||
on server and desktop systems as well. For working examples, see the
|
on server and desktop systems as well. For working examples, see the
|
||||||
[contrib/](contrib/) section with tutorials for:
|
[contrib/](contrib/) section with tutorials for:
|
||||||
|
|
||||||
* [Alpine Linux](contrib/alpine/),
|
* [Void Linux](contrib/void/),
|
||||||
* [Debian GNU/Linux](contrib/debian/), and
|
* [Alpine Linux](contrib/alpine/), and
|
||||||
* [Void Linux](contrib/void/)
|
* [Debian GNU/Linux](contrib/debian/)
|
||||||
|
|
||||||

|

|
||||||
The screenshot shows [Alpine Linux](https://www.alpinelinux.org/).
|
The screenshot shows [Alpine Linux](https://www.alpinelinux.org/).
|
||||||
|
|
||||||
|
|
||||||
@@ -95,21 +95,21 @@ inetd ssh/tcp@*,!eth0 nowait [2345] /sbin/dropbear -i -R -F -- SSH service
|
|||||||
# Run start scripts from this directory
|
# Run start scripts from this directory
|
||||||
# runparts /etc/start.d
|
# runparts /etc/start.d
|
||||||
|
|
||||||
# Virtual consoles run BusyBox getty
|
# Virtual consoles run BusyBox getty, keep kernel default speed
|
||||||
tty [12345] /sbin/getty -L 115200 /dev/tty1 linux
|
tty [12345] /sbin/getty -L 0 /dev/tty1 linux
|
||||||
tty [12345] /sbin/getty -L 115200 /dev/tty2 linux
|
tty [12345] /sbin/getty -L 0 /dev/tty2 linux
|
||||||
tty [12345] /sbin/getty -L 115200 /dev/tty3 linux
|
tty [12345] /sbin/getty -L 0 /dev/tty3 linux
|
||||||
|
|
||||||
# Use built-in getty for serial port and USB serial
|
# Use built-in getty for serial port and USB serial
|
||||||
tty [12345] /dev/ttyAMA0 115200 noclear nowait
|
tty [12345] /dev/ttyAMA0 noclear nowait
|
||||||
tty [12345] /dev/ttyUSB0 115200 noclear
|
tty [12345] /dev/ttyUSB0 noclear
|
||||||
|
|
||||||
# Just give me a shell, I need to debug this embedded system!
|
# Just give me a shell, I need to debug this embedded system!
|
||||||
tty [12345] @console noclear nologin
|
tty [12345] @console noclear nologin
|
||||||
```
|
```
|
||||||
|
|
||||||
The `service` stanza, as well as `task`, `run`, `inetd` and others are
|
The `service` stanza, as well as `task`, `run`, `inetd` and others are
|
||||||
described in full in [docs/config.md](docs/config.md). Here's a quick
|
described in full in [doc/config.md](doc/config.md). Here's a quick
|
||||||
overview of some of the most common components needed to start a UNIX
|
overview of some of the most common components needed to start a UNIX
|
||||||
daemon:
|
daemon:
|
||||||
|
|
||||||
@@ -130,7 +130,7 @@ advanced uses as well:
|
|||||||
|
|
||||||
service /usr/sbin/sshd -D
|
service /usr/sbin/sshd -D
|
||||||
|
|
||||||
Dependencies are handled using [conditions](docs/conditions.md). One of
|
Dependencies are handled using [conditions](doc/conditions.md). One of
|
||||||
the most common conditions is to wait for basic networking to become
|
the most common conditions is to wait for basic networking to become
|
||||||
available:
|
available:
|
||||||
|
|
||||||
@@ -171,7 +171,7 @@ Start, monitor and restart services should they fail.
|
|||||||
|
|
||||||
**Inetd**
|
**Inetd**
|
||||||
|
|
||||||
Finit comes with a built-in [inetd server](docs/inetd.md). No need to
|
Finit comes with a built-in [inetd server](doc/inetd.md). No need to
|
||||||
maintain a separate config file for services that you want to start on
|
maintain a separate config file for services that you want to start on
|
||||||
demand.
|
demand.
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ Built-in optional inetd services:
|
|||||||
- discard [RFC863][]
|
- discard [RFC863][]
|
||||||
- time (rdate) [RFC868][]
|
- time (rdate) [RFC868][]
|
||||||
|
|
||||||
For more information, see [docs/inetd.md](docs/inetd.md).
|
For more information, see [doc/inetd.md](doc/inetd.md).
|
||||||
|
|
||||||
|
|
||||||
**Getty**
|
**Getty**
|
||||||
@@ -197,9 +197,9 @@ waits for user input before handing over to `/bin/login`, which is
|
|||||||
responsible for handling the actual authentication.
|
responsible for handling the actual authentication.
|
||||||
|
|
||||||
```conf
|
```conf
|
||||||
tty [12345] /dev/tty1 38400 nowait linux
|
tty [12345] /dev/tty1 nowait linux
|
||||||
tty [12345] /dev/ttyAMA0 115200 noclear vt100
|
tty [12345] /dev/ttyAMA0 noclear vt100
|
||||||
tty [12345] /sbin/getty -L 115200 /dev/ttyAMA0 vt100
|
tty [12345] /sbin/getty -L /dev/ttyAMA0 vt100
|
||||||
```
|
```
|
||||||
|
|
||||||
Users of embedded systems may want to enable automatic serial console
|
Users of embedded systems may want to enable automatic serial console
|
||||||
@@ -208,12 +208,12 @@ system uses `ttyS0`, `ttyAMA0`, `ttyMXC0`, or anything else. Finit
|
|||||||
figures it out by querying sysfs: `/sys/class/tty/console/active`.
|
figures it out by querying sysfs: `/sys/class/tty/console/active`.
|
||||||
|
|
||||||
```conf
|
```conf
|
||||||
tty [12345] @console 115200 linux noclear
|
tty [12345] @console linux noclear
|
||||||
```
|
```
|
||||||
|
|
||||||
Notice the optional `noclear`, `nowait`, and `nologin` flags. The
|
Notice the optional `noclear`, `nowait`, and `nologin` flags. The
|
||||||
latter is for skipping the login process entirely. For more information,
|
latter is for skipping the login process entirely. For more information,
|
||||||
see [docs/config.md](docs/config.md#syntax).
|
see [doc/config.md](doc/config.md#syntax).
|
||||||
|
|
||||||
|
|
||||||
**Runlevels**
|
**Runlevels**
|
||||||
@@ -258,7 +258,7 @@ 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 [docs/plugins.md](docs/plugins.md).
|
For more information, see [doc/plugins.md](doc/plugins.md).
|
||||||
|
|
||||||
|
|
||||||
**Progress**
|
**Progress**
|
||||||
@@ -277,7 +277,21 @@ append="init=/sbin/finit splash"
|
|||||||
|
|
||||||
For a really nice boot, add `quiet` as well. This silences the output
|
For a really nice boot, add `quiet` as well. This silences the output
|
||||||
from the kernel, leaving only warnings and errors. For other kernel
|
from the kernel, leaving only warnings and errors. For other kernel
|
||||||
command line parameters, see [docs/build.md](docs/build.md#recovery).
|
command line parameters, see [doc/build.md](doc/build.md#recovery).
|
||||||
|
|
||||||
|
|
||||||
|
**Automatic Reload**
|
||||||
|
|
||||||
|
By default, Finit monitors `/etc/finit.d/` and `/etc/finit.d/enabled/`
|
||||||
|
registering any changes to `.conf` files. To activate a change the user
|
||||||
|
must call `initctl reload`, which reloads all modified files, stops any
|
||||||
|
removed services, starts new ones, and restarts any modified ones, with
|
||||||
|
SIGHUP if the process supports it.
|
||||||
|
|
||||||
|
For some use-cases the extra step of calling `initctl reload` creates an
|
||||||
|
unnecessary overhead, which can be removed at build-time using:
|
||||||
|
|
||||||
|
configure --enable-auto-reload
|
||||||
|
|
||||||
|
|
||||||
Runparts & /etc/rc.local
|
Runparts & /etc/rc.local
|
||||||
@@ -299,8 +313,8 @@ Right after the runlevel change when all services have started properly,
|
|||||||
No configuration stanza in `/etc/finit.conf` is required for `rc.local`.
|
No configuration stanza in `/etc/finit.conf` is required for `rc.local`.
|
||||||
If it exists and is an executable shell script Finit calls it at the very
|
If it exists and is an executable shell script Finit calls it at the very
|
||||||
end of the boot, before calling the `HOOK_SYSTEM_UP`. See more on hooks
|
end of the boot, before calling the `HOOK_SYSTEM_UP`. See more on hooks
|
||||||
in [docs/plugins.md](docs/plugins.md#hooks), and about the system bootstrap
|
in [doc/plugins.md](doc/plugins.md#hooks), and about the system bootstrap
|
||||||
in [docs/bootstrap.md](docs/bootstrap.md).
|
in [doc/bootstrap.md](doc/bootstrap.md).
|
||||||
|
|
||||||
|
|
||||||
Runlevels
|
Runlevels
|
||||||
@@ -378,7 +392,7 @@ section.
|
|||||||
For compatibility reasons Finit listens to the same set of signals as
|
For compatibility reasons Finit listens to the same set of signals as
|
||||||
BusyBox init. This is not 100% compatible with SysV init, but clearly
|
BusyBox init. This is not 100% compatible with SysV init, but clearly
|
||||||
the more common combination for Finit. For more details, see
|
the more common combination for Finit. For more details, see
|
||||||
[docs/signals.md](docs/signals.md).
|
[doc/signals.md](doc/signals.md).
|
||||||
|
|
||||||
Finit also listens to the classic SysV init FIFO, used by `telinit`.
|
Finit also listens to the classic SysV init FIFO, used by `telinit`.
|
||||||
Support for this is implemented by the `initctl.so` plugin. Hence,
|
Support for this is implemented by the `initctl.so` plugin. Hence,
|
||||||
@@ -429,8 +443,6 @@ Commands:
|
|||||||
touch <CONF> Mark .conf in /etc/finit.d/ for reload
|
touch <CONF> Mark .conf in /etc/finit.d/ for reload
|
||||||
reload Reload *.conf in /etc/finit.d/ (activates changes)
|
reload Reload *.conf in /etc/finit.d/ (activates changes)
|
||||||
|
|
||||||
cond set <COND> Set (assert) condition => +COND
|
|
||||||
cond clear <COND> Clear (deassert) condition => -COND
|
|
||||||
cond show Show condition status
|
cond show Show condition status
|
||||||
cond dump Dump all conditions and their status
|
cond dump Dump all conditions and their status
|
||||||
|
|
||||||
@@ -451,7 +463,7 @@ Commands:
|
|||||||
|
|
||||||
For services *not* supporting `SIGHUP` the `<!>` notation in the .conf
|
For services *not* supporting `SIGHUP` the `<!>` notation in the .conf
|
||||||
file must be used to tell Finit to stop and start it on `reload` and
|
file must be used to tell Finit to stop and start it on `reload` and
|
||||||
`runlevel` changes. If `<>` holds more [conditions](docs/conditions.md),
|
`runlevel` changes. If `<>` holds more [conditions](doc/conditions.md),
|
||||||
these will also affect how a service is maintained.
|
these will also affect how a service is maintained.
|
||||||
|
|
||||||
**Note:** even though it is possible to start services not belonging in
|
**Note:** even though it is possible to start services not belonging in
|
||||||
@@ -533,12 +545,12 @@ and proposed extensions.
|
|||||||
[openrc]: http://www.gentoo.org/proj/en/base/openrc/
|
[openrc]: http://www.gentoo.org/proj/en/base/openrc/
|
||||||
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
[run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts
|
||||||
[original finit]: http://helllabs.org/finit/
|
[original finit]: http://helllabs.org/finit/
|
||||||
[EeePC fastinit]: http://wiki.eeeuser.com/boot_process:the_boot_process
|
[EeePC fastinit]: https://web.archive.org/web/20071208212450/http://wiki.eeeuser.com/boot_process:the_boot_process
|
||||||
[Claudio Matsuoka]: https://github.com/cmatsuoka
|
[Claudio Matsuoka]: https://github.com/cmatsuoka
|
||||||
[Joachim Nilsson]: http://troglobit.com
|
[Joachim Nilsson]: http://troglobit.com
|
||||||
[GitHub]: https://github.com/troglobit/finit
|
[GitHub]: https://github.com/troglobit/finit
|
||||||
[License]: https://en.wikipedia.org/wiki/MIT_License
|
[License]: https://en.wikipedia.org/wiki/MIT_License
|
||||||
[License Badge]: https://img.shields.io/badge/License-MIT-yellow.svg
|
[License Badge]: https://img.shields.io/badge/License-MIT-teal.svg
|
||||||
[Travis]: https://travis-ci.org/troglobit/finit
|
[Travis]: https://travis-ci.org/troglobit/finit
|
||||||
[Travis Status]: https://travis-ci.org/troglobit/finit.png?branch=master
|
[Travis Status]: https://travis-ci.org/troglobit/finit.png?branch=master
|
||||||
[Coverity Scan]: https://scan.coverity.com/projects/3545
|
[Coverity Scan]: https://scan.coverity.com/projects/3545
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
AC_INIT(Finit, 3.1, https://github.com/troglobit/finit/issues, finit, http://troglobit.com/finit.html)
|
AC_INIT(Finit, 3.2-rc3, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/finit.html)
|
||||||
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz subdir-objects])
|
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz subdir-objects])
|
||||||
AM_SILENT_RULES([yes])
|
AM_SILENT_RULES([yes])
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@ AC_CONFIG_FILES([Makefile
|
|||||||
contrib/alpine/Makefile contrib/alpine/finit.d/Makefile contrib/alpine/finit.d/available/Makefile
|
contrib/alpine/Makefile contrib/alpine/finit.d/Makefile contrib/alpine/finit.d/available/Makefile
|
||||||
contrib/debian/Makefile contrib/debian/finit.d/Makefile contrib/debian/finit.d/available/Makefile contrib/debian/grub.d/Makefile
|
contrib/debian/Makefile contrib/debian/finit.d/Makefile contrib/debian/finit.d/available/Makefile contrib/debian/grub.d/Makefile
|
||||||
contrib/void/Makefile contrib/void/finit.d/Makefile contrib/void/finit.d/available/Makefile
|
contrib/void/Makefile contrib/void/finit.d/Makefile contrib/void/finit.d/available/Makefile
|
||||||
docs/Makefile
|
doc/Makefile
|
||||||
plugins/Makefile
|
plugins/Makefile
|
||||||
src/Makefile])
|
src/Makefile])
|
||||||
|
|
||||||
@@ -40,8 +40,11 @@ AC_TYPE_UINT8_T
|
|||||||
AC_TYPE_UINT16_T
|
AC_TYPE_UINT16_T
|
||||||
AC_TYPE_UINT32_T
|
AC_TYPE_UINT32_T
|
||||||
|
|
||||||
|
# Check for pkg-config first, warn if it's not installed
|
||||||
|
PKG_PROG_PKG_CONFIG
|
||||||
|
|
||||||
# Check for required libraries
|
# Check for required libraries
|
||||||
PKG_CHECK_MODULES([uev], [libuev >= 2.1.0])
|
PKG_CHECK_MODULES([uev], [libuev >= 2.2.0])
|
||||||
PKG_CHECK_MODULES([lite], [libite >= 2.0.1])
|
PKG_CHECK_MODULES([lite], [libite >= 2.0.1])
|
||||||
|
|
||||||
# Check for configured Finit features
|
# Check for configured Finit features
|
||||||
@@ -54,14 +57,18 @@ AC_ARG_ENABLE(fallback_shell,
|
|||||||
AS_HELP_STRING([--enable-fallback-shell], [Start a shell if no TTYs can start]),,[
|
AS_HELP_STRING([--enable-fallback-shell], [Start a shell if no TTYs can start]),,[
|
||||||
enable_fallback_shell=no])
|
enable_fallback_shell=no])
|
||||||
|
|
||||||
AC_ARG_ENABLE(rw-rootfs,
|
AC_ARG_ENABLE(auto_reload,
|
||||||
AS_HELP_STRING([--enable-rw-rootfs], [Remount / R/W at boot, usually not for embedded]),,[
|
AS_HELP_STRING([--enable-auto-reload], [Automatic reload on any .conf change]),,[
|
||||||
enable_rw_rootfs=no])
|
enable_auto_reload=no])
|
||||||
|
|
||||||
AC_ARG_ENABLE(progress,
|
AC_ARG_ENABLE(progress,
|
||||||
AS_HELP_STRING([--enable-progress], [Pre Finit v3 bootup progress and heading]),,[
|
AS_HELP_STRING([--enable-progress], [Modern progress display at bootup]),,[
|
||||||
enable_progress=no])
|
enable_progress=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(progress-classic,
|
||||||
|
AS_HELP_STRING([--enable-progress-classic], [Pre Finit v3 bootup progress and heading]),,[
|
||||||
|
enable_progress_classic=no])
|
||||||
|
|
||||||
AC_ARG_ENABLE(watchdog,
|
AC_ARG_ENABLE(watchdog,
|
||||||
AS_HELP_STRING([--enable-watchdog], [Enable built-in watchdog, uses /dev/watchdog]),,[
|
AS_HELP_STRING([--enable-watchdog], [Enable built-in watchdog, uses /dev/watchdog]),,[
|
||||||
enable_watchdog=no])
|
enable_watchdog=no])
|
||||||
@@ -74,10 +81,22 @@ AC_ARG_ENABLE(inetd,
|
|||||||
AS_HELP_STRING([--disable-inetd], [Disable built-in inetd super server, default enabled]),,[
|
AS_HELP_STRING([--disable-inetd], [Disable built-in inetd super server, default enabled]),,[
|
||||||
enable_inetd=yes])
|
enable_inetd=yes])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(logit,
|
||||||
|
AS_HELP_STRING([--disable-logit], [Disable logit, used for log redirection, default: enable]),,[
|
||||||
|
enable_logit=yes])
|
||||||
|
|
||||||
AC_ARG_ENABLE(logrotate,
|
AC_ARG_ENABLE(logrotate,
|
||||||
AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp, default enabled]),,[
|
AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp, default enabled]),,[
|
||||||
enable_logrotate=yes])
|
enable_logrotate=yes])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(doc,
|
||||||
|
AS_HELP_STRING([--disable-doc], [Disable build and install of doc/ section]),,[
|
||||||
|
enable_doc=yes])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(contrib,
|
||||||
|
AS_HELP_STRING([--disable-contrib], [Disable build and install of contrib section]),,[
|
||||||
|
enable_contrib=yes])
|
||||||
|
|
||||||
# Check for extra plugins to enable
|
# Check for extra plugins to enable
|
||||||
enable_all_plugins=auto
|
enable_all_plugins=auto
|
||||||
AC_PLUGIN([alsa-utils], [no], [Save and restore ALSA sound settings using alsactl])
|
AC_PLUGIN([alsa-utils], [no], [Save and restore ALSA sound settings using alsactl])
|
||||||
@@ -87,7 +106,7 @@ AC_PLUGIN([inetd-chargen], [no], [Inetd plugin: character generator, RFC864])
|
|||||||
AC_PLUGIN([inetd-daytime], [no], [Inetd plugin: daytime server, RFC867])
|
AC_PLUGIN([inetd-daytime], [no], [Inetd plugin: daytime server, RFC867])
|
||||||
AC_PLUGIN([inetd-discard], [no], [Inetd plugin: discard server, RFC863])
|
AC_PLUGIN([inetd-discard], [no], [Inetd plugin: discard server, RFC863])
|
||||||
AC_PLUGIN([inetd-time], [no], [Inetd plugin: time (rdate) server, RFC868])
|
AC_PLUGIN([inetd-time], [no], [Inetd plugin: time (rdate) server, RFC868])
|
||||||
AC_PLUGIN([lost], [no], [Example HOOK_SVC_LOST plugin, very noisy as-is!])
|
AC_PLUGIN([modules-load], [no], [Scans /etc/modules-load.d for modules to load])
|
||||||
AC_PLUGIN([resolvconf], [no], [Setup necessary files for resolvconf])
|
AC_PLUGIN([resolvconf], [no], [Setup necessary files for resolvconf])
|
||||||
AC_PLUGIN([x11-common], [no], [Console setup (for X)])
|
AC_PLUGIN([x11-common], [no], [Console setup (for X)])
|
||||||
AC_PLUGIN([netlink], [yes], [Basic netlink plugin for IFUP/IFDN and GW events. Can be replaced with externally built plugin that links with libnl or similar.])
|
AC_PLUGIN([netlink], [yes], [Basic netlink plugin for IFUP/IFDN and GW events. Can be replaced with externally built plugin that links with libnl or similar.])
|
||||||
@@ -129,7 +148,6 @@ AC_ARG_WITH(random-seed,
|
|||||||
AS_HELP_STRING([--with-random-seed=FILE], [Save a random seed for /dev/urandom across reboots, default /var/lib/misc/random-seed]),
|
AS_HELP_STRING([--with-random-seed=FILE], [Save a random seed for /dev/urandom across reboots, default /var/lib/misc/random-seed]),
|
||||||
[random_seed=$withval], [random_seed=/var/lib/misc/random-seed])
|
[random_seed=$withval], [random_seed=/var/lib/misc/random-seed])
|
||||||
|
|
||||||
|
|
||||||
### Enable features ###########################################################################
|
### Enable features ###########################################################################
|
||||||
|
|
||||||
# Create config.h from selected features and fallback defautls
|
# Create config.h from selected features and fallback defautls
|
||||||
@@ -139,13 +157,21 @@ AS_IF([test "x$enable_emergency_shell" = "xyes"], [
|
|||||||
AS_IF([test "x$enable_fallback_shell" = "xyes"], [
|
AS_IF([test "x$enable_fallback_shell" = "xyes"], [
|
||||||
AC_DEFINE(FALLBACK_SHELL, 1, [Start /bin/sh on console if no TTYs.])])
|
AC_DEFINE(FALLBACK_SHELL, 1, [Start /bin/sh on console if no TTYs.])])
|
||||||
|
|
||||||
AS_IF([test "x$enable_rw_rootfs" = "xyes"], [
|
AS_IF([test "x$enable_auto_reload" = "xyes"], [
|
||||||
AC_DEFINE(REMOUNT_ROOTFS, 1, [Remount / as rw at boot])])
|
AC_DEFINE(AUTO_RELOAD, 1, [Finit automatically does `initctl reload` on any .conf change])])
|
||||||
|
|
||||||
AS_IF([test "x$enable_progress" = "xyes"], [
|
AS_IF([test "x$enable_progress" = "xyes"], [
|
||||||
AC_DEFINE(SILENT_MODE, 0, [Pre Finit v3 bootup messages and heading])
|
AC_DEFINE(PROGRESS_STYLE, 2, [Modern bootup messages, systemd inspired])])
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_progress_classic" = "xyes"], [
|
||||||
|
enable_progress=no
|
||||||
|
AC_DEFINE(PROGRESS_STYLE, 1, [Pre Finit v3 bootup messages and heading])])
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_progress_classic" = "xyes" -o "x$enable_progress" = "xyes"], [
|
||||||
|
AC_DEFINE(SILENT_MODE, 0, [Display bootup progress, see above for style])
|
||||||
], [
|
], [
|
||||||
AC_DEFINE(SILENT_MODE, 1, [Completely silent until login prompt])])
|
AC_DEFINE(PROGRESS_STYLE, 0, [Default progress style])
|
||||||
|
AC_DEFINE(SILENT_MODE, 1, [Completely silent until login prompt (default)])])
|
||||||
|
|
||||||
AS_IF([test "x$enable_watchdog" = "xyes"], [
|
AS_IF([test "x$enable_watchdog" = "xyes"], [
|
||||||
AC_DEFINE(BUILTIN_WATCHDOG, 1, [Enable built-in watchdog, kicks on /dev/watchdog])])
|
AC_DEFINE(BUILTIN_WATCHDOG, 1, [Enable built-in watchdog, kicks on /dev/watchdog])])
|
||||||
@@ -158,6 +184,9 @@ AS_IF([test "x$enable_inetd" != "xno"], [
|
|||||||
enable_inetd="yes"
|
enable_inetd="yes"
|
||||||
AC_DEFINE(INETD_ENABLED, 1, [Enable built-in inetd])])
|
AC_DEFINE(INETD_ENABLED, 1, [Enable built-in inetd])])
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_logit" != "xno"], [
|
||||||
|
AC_DEFINE(LOGIT_ENABLED, 1, [Enable logit tool, used for log redirection by Finit])])
|
||||||
|
|
||||||
AS_IF([test "x$enable_logrotate" != "xno"], [
|
AS_IF([test "x$enable_logrotate" != "xno"], [
|
||||||
AC_DEFINE(LOGROTATE_ENABLED, 1, [Enable built-in rotation of /var/log/wtmp et al.])])
|
AC_DEFINE(LOGROTATE_ENABLED, 1, [Enable built-in rotation of /var/log/wtmp et al.])])
|
||||||
|
|
||||||
@@ -216,11 +245,16 @@ AS_IF([test "x$with_random_seed" != "xno"], [
|
|||||||
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
||||||
AM_CONDITIONAL(INETD, [test "x$enable_inetd" = "xyes"])
|
AM_CONDITIONAL(INETD, [test "x$enable_inetd" = "xyes"])
|
||||||
AM_CONDITIONAL(WATCHDOGD, [test "x$enable_watchdog" = "xyes"])
|
AM_CONDITIONAL(WATCHDOGD, [test "x$enable_watchdog" = "xyes"])
|
||||||
|
AM_CONDITIONAL(LOGIT, [test "x$enable_logit" = "xyes"])
|
||||||
|
AM_CONDITIONAL(DOC, [test "x$enable_doc" = "xyes"])
|
||||||
|
AM_CONDITIONAL(CONTRIB, [test "x$enable_contrib" = "xyes"])
|
||||||
|
|
||||||
# Override default libdir, used for plugins and rescue.conf
|
# Override default libdir, used for plugins and rescue.conf
|
||||||
#pkglibdir=$libdir/finit
|
pkglibdir=$libdir/finit
|
||||||
#AC_SUBST(pkglibdir)
|
AC_SUBST(pkglibexecdir)
|
||||||
#AC_EXPAND_DIR(pkglibdir, "$libdir/finit")
|
AC_EXPAND_DIR(pkglibexecdir, "$libexecdir/finit")
|
||||||
|
AC_DEFINE_UNQUOTED(FINIT_LIBPATH_, "$pkglibexecdir", [Finit libexec path])
|
||||||
|
|
||||||
AC_EXPAND_DIR(plugin_path, "$libdir/finit/plugins")
|
AC_EXPAND_DIR(plugin_path, "$libdir/finit/plugins")
|
||||||
AC_SUBST(plugin_path)
|
AC_SUBST(plugin_path)
|
||||||
AC_DEFINE_UNQUOTED(PLUGIN_PATH, "$plugin_path", [Finit plugin path])
|
AC_DEFINE_UNQUOTED(PLUGIN_PATH, "$plugin_path", [Finit plugin path])
|
||||||
@@ -252,13 +286,16 @@ Behavior:
|
|||||||
Plugins...............: $plugins
|
Plugins...............: $plugins
|
||||||
|
|
||||||
Optional features:
|
Optional features:
|
||||||
|
Install doc/..........: $enable_doc
|
||||||
|
Install contrib/......: $enable_contrib
|
||||||
Built-in inetd........: $enable_inetd
|
Built-in inetd........: $enable_inetd
|
||||||
Built-in watchdogd....: $enable_watchdog
|
Built-in watchdogd....: $enable_watchdog
|
||||||
Built-in logrotate....: $enable_logrotate
|
Built-in logrotate....: $enable_logrotate
|
||||||
|
Scripting tool logit..: $enable_logit
|
||||||
Emergency shell.......: $enable_emergency_shell
|
Emergency shell.......: $enable_emergency_shell
|
||||||
Fallback shell........: $enable_fallback_shell
|
Fallback shell........: $enable_fallback_shell
|
||||||
Remount / RW at boot..: $enable_rw_rootfs
|
Modern progress.......: $enable_progress
|
||||||
Traditional progress..: $enable_progress
|
Classic progress......: $enable_progress_classic
|
||||||
Default console dev...: $console
|
Default console dev...: $console
|
||||||
Default hostname......: $hostname
|
Default hostname......: $hostname
|
||||||
Default runlevel......: $runlevel
|
Default runlevel......: $runlevel
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ fi
|
|||||||
# The plugins are optional, but you may need D-Bus and X11 if you want
|
# The plugins are optional, but you may need D-Bus and X11 if you want
|
||||||
# to run X-Window, the other configure flags are however required.
|
# to run X-Window, the other configure flags are however required.
|
||||||
PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig ./configure \
|
PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig ./configure \
|
||||||
--enable-rw-rootfs --enable-progress \
|
--enable-progress \
|
||||||
--enable-dbus-plugin --enable-x11-common-plugin \
|
--enable-dbus-plugin --enable-x11-common-plugin \
|
||||||
--enable-alsa-utils-plugin --enable-inetd-echo-plugin \
|
--enable-alsa-utils-plugin --enable-inetd-echo-plugin \
|
||||||
--enable-inetd-chargen-plugin --enable-inetd-daytime-plugin \
|
--enable-inetd-chargen-plugin --enable-inetd-daytime-plugin \
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ d_LINKS = dropbear.conf getty.conf keymap.conf modules.conf klogd.conf \
|
|||||||
syslogd.conf
|
syslogd.conf
|
||||||
|
|
||||||
install-exec-hook:
|
install-exec-hook:
|
||||||
@$(MKDIR_P) $(DESTDIR)$(docsdir)
|
@$(MKDIR_P) $(DESTDIR)$(docsdir)/available
|
||||||
@for file in $(d_LINKS); do \
|
@for file in $(d_LINKS); do \
|
||||||
lnk=$(DESTDIR)$(docsdir)/$$file; \
|
lnk=$(DESTDIR)$(docsdir)/$$file; \
|
||||||
src=available/$$file; \
|
src=available/$$file; \
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Consoles to start getty on when system is up
|
# Consoles to start getty on when system is up
|
||||||
tty /dev/tty1 noclear nowait
|
tty [12345] /dev/tty1 noclear nowait
|
||||||
tty /dev/tty2 noclear nowait
|
tty [2345] /dev/tty2 noclear nowait
|
||||||
tty /dev/tty3 noclear nowait
|
tty [2345] /dev/tty3 noclear nowait
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ echo
|
|||||||
# The plugins are optional, but you may need D-Bus and X11 if you want
|
# The plugins are optional, but you may need D-Bus and X11 if you want
|
||||||
# to run X-Window, the other configure flags are however required.
|
# to run X-Window, the other configure flags are however required.
|
||||||
./configure \
|
./configure \
|
||||||
--enable-rw-rootfs --enable-progress \
|
--enable-progress \
|
||||||
--enable-dbus-plugin --enable-x11-common-plugin \
|
--enable-dbus-plugin --enable-x11-common-plugin \
|
||||||
--enable-alsa-utils-plugin --enable-inetd-echo-plugin \
|
--enable-alsa-utils-plugin --enable-inetd-echo-plugin \
|
||||||
--enable-inetd-chargen-plugin --enable-inetd-daytime-plugin \
|
--enable-inetd-chargen-plugin --enable-inetd-daytime-plugin \
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ d_LINKS = console-setup.conf getty.conf keyboard-setup.conf \
|
|||||||
modules.conf rsyslogd.conf sshd.conf
|
modules.conf rsyslogd.conf sshd.conf
|
||||||
|
|
||||||
install-exec-hook:
|
install-exec-hook:
|
||||||
@$(MKDIR_P) $(DESTDIR)$(docsdir)
|
@$(MKDIR_P) $(DESTDIR)$(docsdir)/available
|
||||||
@for file in $(d_LINKS); do \
|
@for file in $(d_LINKS); do \
|
||||||
lnk=$(DESTDIR)$(docsdir)/$$file; \
|
lnk=$(DESTDIR)$(docsdir)/$$file; \
|
||||||
src=available/$$file; \
|
src=available/$$file; \
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Consoles to start getty on when system is up
|
# Consoles to start getty on when system is up
|
||||||
tty [12345] /dev/tty1 115200 vt100 noclear nowait
|
tty [12345] /dev/tty1 linux noclear nowait
|
||||||
tty [2345] /dev/tty2 38400 linux noclear nowait
|
tty [2345] /dev/tty2 linux noclear nowait
|
||||||
tty [2345] /dev/tty3 38400 linux noclear nowait
|
tty [2345] /dev/tty3 linux noclear nowait
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ fi
|
|||||||
# The plugins are optional, but you may need D-Bus and X11 if you want
|
# The plugins are optional, but you may need D-Bus and X11 if you want
|
||||||
# to run X-Window, the other configure flags are however required.
|
# to run X-Window, the other configure flags are however required.
|
||||||
PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig ./configure \
|
PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig ./configure \
|
||||||
--enable-rw-rootfs --enable-progress \
|
--enable-progress \
|
||||||
--enable-dbus-plugin --enable-x11-common-plugin \
|
--enable-dbus-plugin --enable-x11-common-plugin \
|
||||||
--enable-alsa-utils-plugin --enable-inetd-echo-plugin \
|
--enable-alsa-utils-plugin --enable-inetd-echo-plugin \
|
||||||
--enable-inetd-chargen-plugin --enable-inetd-daytime-plugin \
|
--enable-inetd-chargen-plugin --enable-inetd-daytime-plugin \
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ docsdir := @docdir@/contrib/void/finit.d
|
|||||||
d_LINKS = acpid.conf dhcpcd.conf getty.conf sshd.conf uuidd.conf
|
d_LINKS = acpid.conf dhcpcd.conf getty.conf sshd.conf uuidd.conf
|
||||||
|
|
||||||
install-exec-hook:
|
install-exec-hook:
|
||||||
@$(MKDIR_P) $(DESTDIR)$(docsdir)
|
@$(MKDIR_P) $(DESTDIR)$(docsdir)/available
|
||||||
@for file in $(d_LINKS); do \
|
@for file in $(d_LINKS); do \
|
||||||
lnk=$(DESTDIR)$(docsdir)/$$file; \
|
lnk=$(DESTDIR)$(docsdir)/$$file; \
|
||||||
src=available/$$file; \
|
src=available/$$file; \
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Consoles to start Finit built-in getty on when system is up
|
# Consoles to start Finit built-in getty on when system is up
|
||||||
tty /dev/tty1 noclear nowait
|
tty [12345] /dev/tty1 noclear nowait
|
||||||
tty /dev/tty2 noclear nowait
|
tty [2345] /dev/tty2 noclear nowait
|
||||||
tty /dev/tty3 noclear nowait
|
tty [2345] /dev/tty3 noclear nowait
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
docsdir := @docdir@/docs
|
docsdir := @docdir@/doc
|
||||||
docs_DATA = config.md conditions.md distro.md inetd.md plugins.md \
|
docs_DATA = config.md conditions.md distro.md inetd.md plugins.md \
|
||||||
service.md signals.md svc-machine.png cmdline.md
|
service.md signals.md svc-machine.png cmdline.md
|
||||||
EXTRA_DIST = $(docs_DATA)
|
EXTRA_DIST = $(docs_DATA)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
config.md
|
||||||
@@ -18,16 +18,28 @@ after a reconfiguration (`initctl reload`), the Finit dependency system
|
|||||||
can also be used.
|
can also be used.
|
||||||
|
|
||||||
|
|
||||||
General
|
Near Future
|
||||||
-------
|
-----------
|
||||||
|
|
||||||
* Add support for timed shutdown in Finit, including cancelled shutdown,
|
* When a process dies, and Finit does not restart it, we should collect
|
||||||
possibly using an at-job, see [crond section](#Crond) below
|
a `siginfo_t` from the SIGCHLD signal and supply to the user in case
|
||||||
|
`initctl status <process>` is called to debug the issue.
|
||||||
|
* Merge UDP redirect service uredir as an UDP inetd variant
|
||||||
* Add `finit.conf` support for UPS notification (SIGPWR) to start a task
|
* Add `finit.conf` support for UPS notification (SIGPWR) to start a task
|
||||||
using, e.g. <sys/power/{ok,fail,low}> conditions. More info in sig.c
|
using, e.g. <sys/power/{ok,fail,low}> conditions. More info in sig.c
|
||||||
* Add `finit.conf` support for ctrl-alt-delete (SIGINT) and kbrequest,
|
* Add `finit.conf` support for ctrl-alt-delete (SIGINT) and kbrequest,
|
||||||
i.e. KeyboardSignal, (SIGWINCH) behavior. Using conditions to a task,
|
i.e. KeyboardSignal, (SIGWINCH) behavior. Using conditions to a task,
|
||||||
e.g, <sys/key/ctrlaltdel> and <sys/key/signal> like SIGPWR handling.
|
e.g, <sys/key/ctrlaltdel> and <sys/key/signal> like SIGPWR handling.
|
||||||
|
* Cron/At support, see below
|
||||||
|
* Write man pages for finit and `finit.conf`, steal from the excellent
|
||||||
|
`pimd` man pages ...
|
||||||
|
|
||||||
|
|
||||||
|
General
|
||||||
|
-------
|
||||||
|
|
||||||
|
* Add support for timed shutdown in Finit, including cancelled shutdown,
|
||||||
|
possibly using an at-job, see [crond section](#Crond) below
|
||||||
* Add support for JSON output, or similar, from `initctl show`, e.g.
|
* Add support for JSON output, or similar, from `initctl show`, e.g.
|
||||||
`initctl show --json`
|
`initctl show --json`
|
||||||
* [Solaris SMF][] (Service Management Facility) has some interesting
|
* [Solaris SMF][] (Service Management Facility) has some interesting
|
||||||
@@ -48,6 +60,8 @@ General
|
|||||||
now inotify listeners should be automatically created (and removed)
|
now inotify listeners should be automatically created (and removed)
|
||||||
when a subdirectory is added (or removed).
|
when a subdirectory is added (or removed).
|
||||||
|
|
||||||
|
[Solaris SMF]: http://www.oracle.com/technetwork/articles/servers-storage-admin/intro-smf-basics-s11-1729181.html
|
||||||
|
|
||||||
|
|
||||||
Init
|
Init
|
||||||
----
|
----
|
||||||
@@ -103,22 +117,3 @@ could support the basic functionality of the `at` command directly from
|
|||||||
the shell -- that way setting up one-time jobs would not entail
|
the shell -- that way setting up one-time jobs would not entail
|
||||||
re-reading `/etc/finit.conf`
|
re-reading `/etc/finit.conf`
|
||||||
|
|
||||||
|
|
||||||
Documentation
|
|
||||||
-------------
|
|
||||||
|
|
||||||
* Write man pages for finit and `finit.conf`, steal from the excellent
|
|
||||||
`pimd` man pages ...
|
|
||||||
* Add simple, *very* simple, `finit-simple.conf` example. To illustrate
|
|
||||||
how close Finit3 still is to the original easy-to-use Finit0 :)
|
|
||||||
|
|
||||||
|
|
||||||
[libwdt]: http://www.wehavemorefun.de/fritzbox/Libwdt.so
|
|
||||||
[Fritz!Box source dump]: ftp://ftp.avm.de/fritz.box/fritzbox.fon_wlan_7170/x_misc/opensrc/
|
|
||||||
[Solaris SMF]: http://www.oracle.com/technetwork/articles/servers-storage-admin/intro-smf-basics-s11-1729181.html
|
|
||||||
|
|
||||||
<!--
|
|
||||||
-- Local Variables:
|
|
||||||
-- mode: markdown
|
|
||||||
-- End:
|
|
||||||
-->
|
|
||||||
@@ -12,7 +12,7 @@ Bootstrap
|
|||||||
9. Parse `/etc/finit.conf` and all `/etc/finit.d/*.conf` files
|
9. Parse `/etc/finit.conf` and all `/etc/finit.d/*.conf` files
|
||||||
10. Start built-in watchdog, if enabled
|
10. Start built-in watchdog, if enabled
|
||||||
11. Set hostname
|
11. Set hostname
|
||||||
12. Pivot root, or remount `/` read-write, depending on system type
|
12. Remount `/` read-write if `/` is listed in `/etc/fstab` without `ro`
|
||||||
13. Call 1st level hooks, `HOOK_ROOTFS_UP`
|
13. Call 1st level hooks, `HOOK_ROOTFS_UP`
|
||||||
14. Mount all file systems listed in `/etc/fstab` and swap, if available
|
14. Mount all file systems listed in `/etc/fstab` and swap, if available
|
||||||
15. Enable SysV init signals
|
15. Enable SysV init signals
|
||||||
@@ -40,11 +40,6 @@ Below are a few of the main switches to configure:
|
|||||||
|
|
||||||
* `--disable-inetd`: Disable the built-in inetd server.
|
* `--disable-inetd`: Disable the built-in inetd server.
|
||||||
|
|
||||||
* `--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
|
* `--enable-static`: Build Finit statically. The plugins will be
|
||||||
built-ins (.o files) and all external libraries, except the C library
|
built-ins (.o files) and all external libraries, except the C library
|
||||||
will be linked statically.
|
will be linked statically.
|
||||||
@@ -53,8 +48,6 @@ Below are a few of the main switches to configure:
|
|||||||
|
|
||||||
* `--enable-dbus-plugin`: Enable the optional D-Bus `dbus.so` plugin.
|
* `--enable-dbus-plugin`: Enable the optional D-Bus `dbus.so` plugin.
|
||||||
|
|
||||||
* `--enable-lost-plugin`: Enable noisy example plugin for `HOOK_SVC_LOST`.
|
|
||||||
|
|
||||||
* `--enable-resolvconf-plugin`: Enable the `resolvconf.so` optional plugin.
|
* `--enable-resolvconf-plugin`: Enable the `resolvconf.so` optional plugin.
|
||||||
|
|
||||||
* `--enable-x11-common-plugin`: Enable the optional X Window `x11-common.so` plugin.
|
* `--enable-x11-common-plugin`: Enable the optional X Window `x11-common.so` plugin.
|
||||||
@@ -75,7 +68,7 @@ First, unpack the archive:
|
|||||||
Then configure, build and install:
|
Then configure, build and install:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ ./configure --enable-rw-rootfs --enable-inetd-echo-plugin \
|
$ ./configure --enable-inetd-echo-plugin \
|
||||||
--enable-inetd-chargen-plugin --enable-inetd-daytime-plugin \
|
--enable-inetd-chargen-plugin --enable-inetd-daytime-plugin \
|
||||||
--enable-inetd-discard-plugin --enable-inetd-time-plugin \
|
--enable-inetd-discard-plugin --enable-inetd-time-plugin \
|
||||||
--with-heading="Alpine Linux 3.4" --with-hostname=alpine
|
--with-heading="Alpine Linux 3.4" --with-hostname=alpine
|
||||||
@@ -47,17 +47,7 @@ service's PID file being created.
|
|||||||
Triggering
|
Triggering
|
||||||
----------
|
----------
|
||||||
|
|
||||||
Conditions are triggered by built-in plugins, but can for debugging
|
Conditions can only be triggered by built-in plugins.
|
||||||
purposes also be controlled using the `cond set` and `cond clear`
|
|
||||||
sub-commands to the `initctl` control tool:
|
|
||||||
|
|
||||||
* `initctl cond set your/cond/here`
|
|
||||||
|
|
||||||
To set a condition
|
|
||||||
|
|
||||||
* `initctl cond clear your/cond/here`
|
|
||||||
|
|
||||||
To clear a condition
|
|
||||||
|
|
||||||
Conditions retain their current state until the next reconfiguration or
|
Conditions retain their current state until the next reconfiguration or
|
||||||
runlevel change. At that point all set conditions transition into the
|
runlevel change. At that point all set conditions transition into the
|
||||||
@@ -102,6 +92,25 @@ Built-in conditions:
|
|||||||
difference is that `running` tells if the NIC has link.
|
difference is that `running` tells if the NIC has link.
|
||||||
|
|
||||||
|
|
||||||
|
Composition
|
||||||
|
-----------
|
||||||
|
|
||||||
|
The `svc/` conditions can be quite tricky to understand. They are
|
||||||
|
generated by the Finit `pidfile.so` plugin and are composed from the
|
||||||
|
daemon's path and the pidfile name (and path).
|
||||||
|
|
||||||
|
| **service** | **pid:** | **pidfile path** | **svc condition** |
|
||||||
|
|--------------------------------------|-----------------|------------------|-------------------|
|
||||||
|
| /sbin/foo | | /run/foo.pid | svc/sbin/foo |
|
||||||
|
| /sbin/bar -p /run/baz.pid | pid:baz | /run/bas.pid | svc/sbin/baz |
|
||||||
|
| lxc-start -n foo -p /run/lxc/foo.pid | pid:lxc/foo.pid | /run/lxc/foo.pid | svc/lxc/foo |
|
||||||
|
| /usr/bin/dbus-daemon | pid:dbus/pid | /run/dbus/pid | svc/usr/bin/dbus |
|
||||||
|
|
||||||
|
Omitting the `pid:` to run/task/service/sysv stanza means Finit will
|
||||||
|
guess the pidfile path based on `/run/` and the basename(1) of the
|
||||||
|
program.
|
||||||
|
|
||||||
|
|
||||||
Debugging
|
Debugging
|
||||||
---------
|
---------
|
||||||
|
|
||||||
@@ -133,12 +142,13 @@ To fake interface `vlan1` suddenly appearing, and test what happens to
|
|||||||
|
|
||||||
```shell
|
```shell
|
||||||
~ # initctl debug
|
~ # initctl debug
|
||||||
~ # initctl cond set net/vlan1/exist
|
~ # mkdir -p /var/run/finit/cond/net/vlan1
|
||||||
|
~ # cp /var/run/finit/cond /var/run/finit/cond/net/vlan1/exist
|
||||||
```
|
```
|
||||||
|
|
||||||
Then watch the console for the debug messages and then check the output
|
Then watch the console for the debug messages and then check the output
|
||||||
from `initctl cond show` again. (The client will likely have failed to
|
from `initctl cond show` again. The client will likely have failed to
|
||||||
start, but at least the condition is now satisfied.)
|
start, but at least the condition is now satisfied.
|
||||||
|
|
||||||
There is also the `initctl cond dump` command, which dumps all known
|
There is also the `initctl cond dump` command, which dumps all known
|
||||||
conditions and their current status.
|
conditions and their current status.
|
||||||
@@ -147,9 +157,10 @@ conditions and their current status.
|
|||||||
Internals
|
Internals
|
||||||
---------
|
---------
|
||||||
|
|
||||||
Conditions are implemented as simple files in the file system, in the
|
As shown previously, conditions are implemented as simple files in the
|
||||||
`/var/run/finit/cond/` sub-directory. Use the `initctl cond set/clear`
|
file system, in the `/var/run/finit/cond/` sub-directory. The files
|
||||||
commands to add/remove files in this hierarchy.
|
are created, updated, and removed by condition plugins. To debug them,
|
||||||
|
see the previous section.
|
||||||
|
|
||||||
A condition is always in one of three states:
|
A condition is always in one of three states:
|
||||||
|
|
||||||
@@ -93,7 +93,16 @@ Syntax
|
|||||||
case the contents of that file is used.
|
case the contents of that file is used.
|
||||||
|
|
||||||
* `module <MODULE> [ARGS]`
|
* `module <MODULE> [ARGS]`
|
||||||
Load a kernel module, with optional arguments
|
Load a kernel module, with optional arguments. Similar to `insmod`
|
||||||
|
command line tool.
|
||||||
|
|
||||||
|
Note, there is both a `modules-load.so` and a `modprobe.so` plugin
|
||||||
|
that can handle module loading better. The former supports loading
|
||||||
|
from `/etc/modules-load.d/`, and the latter uses kernel modinfo to
|
||||||
|
automatically load (or coldplug) every required module. For hotplug
|
||||||
|
we recommend the BusyBox mdev tool, add to `/etc/mdev.conf`:
|
||||||
|
|
||||||
|
$MODALIAS=.* root:root 0660 @modprobe -b "$MODALIAS"
|
||||||
|
|
||||||
* `network <PATH>`
|
* `network <PATH>`
|
||||||
Script or program to bring up networking, with optional arguments
|
Script or program to bring up networking, with optional arguments
|
||||||
@@ -143,11 +152,36 @@ Syntax
|
|||||||
task [s] echo "foo" | cat >/tmp/bar
|
task [s] echo "foo" | cat >/tmp/bar
|
||||||
```
|
```
|
||||||
|
|
||||||
|
* `sysv [LVLS] <COND> /path/to/init-script -- Optional description`__
|
||||||
|
Similar to `task` is the `sysv` stanza, which can be used to call SysV
|
||||||
|
style scripts. The primary intention for this command is to be able to
|
||||||
|
re-use much of existing setup and init scripts in Linux distributions.
|
||||||
|
|
||||||
|
When entering an allowed runlevel, Finit calls `init-script start`,
|
||||||
|
when entering a disallowed runlevel, Finit calls `init-script stop`,
|
||||||
|
and if the Finit .conf, where `sysv` stanza is declared, is modified,
|
||||||
|
Finit calls `init-script restart` on `initctl reload`. Similar to
|
||||||
|
how `service` stanzas work.
|
||||||
|
|
||||||
|
Forking services started with `sysv` scripts can be monitored by Finit
|
||||||
|
by declaring the PID file to look for: `pid:!/path/to/pidfile.pid`.
|
||||||
|
|
||||||
* `service [LVLS] <COND> /path/to/daemon ARGS -- Optional description`
|
* `service [LVLS] <COND> /path/to/daemon ARGS -- Optional description`
|
||||||
Service, or daemon, to be monitored and automatically restarted if it
|
Service, or daemon, to be monitored and automatically restarted if it
|
||||||
exits prematurely. Please note that you often need to provide a
|
exits prematurely.
|
||||||
`--foreground` or `--no-background` argument to most daemons to
|
|
||||||
prevent them from forking off a sub-process in the background.
|
For daemons that support it, we recommend appending `--foreground`, or
|
||||||
|
`--no-background`, argument to prevent them from forking off a
|
||||||
|
sub-process in the background. This is the most reliable way to
|
||||||
|
monitor a service.
|
||||||
|
|
||||||
|
However, not all daemons support running in the foreground, or they
|
||||||
|
may start logging to the foreground as well, these are called forking
|
||||||
|
services and are supported using the same syntax as forking `sysv`
|
||||||
|
services, using the `pid:!/path/to/pidfile.pid` syntax.
|
||||||
|
|
||||||
|
In the case of `ospfd` (below), we omit the `-d` flag to prevent it
|
||||||
|
from forking (daemonizing):
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
service [2345] <svc/sbin/zebra> /sbin/ospfd -- OSPF daemon
|
service [2345] <svc/sbin/zebra> /sbin/ospfd -- OSPF daemon
|
||||||
@@ -169,21 +203,42 @@ Syntax
|
|||||||
|
|
||||||
pid[:[/path/to/]filename[.pid]]
|
pid[:[/path/to/]filename[.pid]]
|
||||||
|
|
||||||
For example, by adding `pid:/run/foo.pid` to the service `bar` that
|
For example, by adding `pid:/run/foo.pid` to the service `/sbin/bar`
|
||||||
PID file will, not only be created and removed automatically, but also
|
that PID file will, not only be created and removed automatically, but
|
||||||
be used by the Finit condition subsystem. So another service/run/task
|
also be used by the Finit condition subsystem. So a service/run/task
|
||||||
can depend on `<svc/foo>`.
|
can depend on `<svc/sbin/foo>`, notice the composition of conditions.
|
||||||
|
|
||||||
If a service `bar` *does* maintain a PID file, but using `foo.pid`, we
|
However, if a service `bar` *does* create a PID file, using `foo.pid`,
|
||||||
can inform Finit of this by simplly prepending an `!` to the argument.
|
we can inform Finit of this by prepending an `!`:
|
||||||
|
|
||||||
pid:!/run/foo.pid
|
pid:!/run/foo.pid
|
||||||
|
|
||||||
Here Finit will *not* create/remove/touch the PID file, only use it
|
Here Finit will *not* create/remove/touch the PID file, only use it
|
||||||
for the condition handling instead of the default PID file name.
|
for the condition handling instead of the default PID file name.
|
||||||
|
|
||||||
For a detailed description of conditions, and how to debug them, see
|
> For a detailed description of conditions, and how to debug them, see
|
||||||
the [Finit Conditions](conditions.md) document.
|
> the [Finit Conditions](conditions.md) document.
|
||||||
|
|
||||||
|
If a service should not be automatically started, it can be configured
|
||||||
|
as manual with the optional `manual` argument. The service can then be
|
||||||
|
started at any time by running `initctl start <service>`.
|
||||||
|
|
||||||
|
manual:yes
|
||||||
|
|
||||||
|
The name of a service, shown by the `initctl` tool, defaults to the
|
||||||
|
basename of the service executable. It can be changed with the
|
||||||
|
optional `name` argument:
|
||||||
|
|
||||||
|
name:<service-name>
|
||||||
|
|
||||||
|
When stopping a service (run/task/sysv/service), either manually or
|
||||||
|
when moving to another runlevel, Finit starts by sending `SIGTERM`, to
|
||||||
|
allow the process to shut down gracefully. If the process has not
|
||||||
|
been collected within 3 seconds, Finit sends `SIGKILL`. To halt the
|
||||||
|
process using a different signal, use the option `halt:SIGNAL`, e.g.,
|
||||||
|
`halt:SIGPWR`. To change the delay between your halt signal and KILL,
|
||||||
|
use the option `kill:SEC`, e.g., `kill:10` to wait 10 seconds before
|
||||||
|
sending `SIGKILL`.
|
||||||
|
|
||||||
* `inetd service/proto[@iflist] <wait|nowait> [LVLS] /path/to/daemon args`
|
* `inetd service/proto[@iflist] <wait|nowait> [LVLS] /path/to/daemon args`
|
||||||
Launch a daemon when a client initiates a connection on an Internet
|
Launch a daemon when a client initiates a connection on an Internet
|
||||||
@@ -246,8 +301,9 @@ Syntax
|
|||||||
`tty [LVLS] <CMD> <ARGS> [noclear] [nowait]`
|
`tty [LVLS] <CMD> <ARGS> [noclear] [nowait]`
|
||||||
The first variant of this option uses the built-in getty on the given
|
The first variant of this option uses the built-in getty on the given
|
||||||
TTY device DEV, in the given runlevels. The DEV may be the special
|
TTY device DEV, in the given runlevels. The DEV may be the special
|
||||||
keyword `@console`, which is very useful on embedded systems. Default
|
keyword `@console`, or `console`, useful on embedded systems.
|
||||||
baud rate is `38400`.
|
|
||||||
|
The default baud rate is 0, i.e., keep kernel default.
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
```conf
|
```conf
|
||||||
@@ -285,11 +341,12 @@ Syntax
|
|||||||
Embedded systems may want to enable automatic `DEV` by supplying the
|
Embedded systems may want to enable automatic `DEV` by supplying the
|
||||||
special `@console` device. This works regardless weather the system
|
special `@console` device. This works regardless weather the system
|
||||||
uses `ttyS0`, `ttyAMA0`, `ttyMXC0`, or anything else. Finit figures
|
uses `ttyS0`, `ttyAMA0`, `ttyMXC0`, or anything else. Finit figures
|
||||||
it out by querying sysfs: `/sys/class/tty/console/active`.
|
it out by querying sysfs: `/sys/class/tty/console/active`. The speed
|
||||||
|
can be omitted to keep the kernel default.
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
```conf
|
```conf
|
||||||
tty [12345] @console 115200 noclear vt220
|
tty [12345] @console noclear vt220
|
||||||
```
|
```
|
||||||
|
|
||||||
On really bare bones systems Finit offers a fallback shell, which
|
On really bare bones systems Finit offers a fallback shell, which
|
||||||
@@ -338,14 +395,18 @@ syslog using the native `logit` tool. The full syntax is:
|
|||||||
|
|
||||||
log:/path/to/file
|
log:/path/to/file
|
||||||
log:prio:facility.level,tag:ident
|
log:prio:facility.level,tag:ident
|
||||||
|
log:console
|
||||||
log:null
|
log:null
|
||||||
log
|
log
|
||||||
|
|
||||||
|
Default `prio` is `daemon.info` and default `tag` is the basename of the
|
||||||
|
service or run/task command.
|
||||||
|
|
||||||
Log rotation is controlled using the global `log` setting.
|
Log rotation is controlled using the global `log` setting.
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
|
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
|
||||||
|
|
||||||
Worth noting is that conditions is allowed for all these stanzas. For a
|
Worth noting is that conditions is allowed for all these stanzas. For a
|
||||||
detailed description, see the [Conditions](conditions.md) document.
|
detailed description, see the [Conditions](conditions.md) document.
|
||||||
@@ -42,13 +42,11 @@ For your convenience a set of *optional* plugins are available:
|
|||||||
|
|
||||||
* *discard.so*: RFC 863 plugin. Start as inetd service, like time below.
|
* *discard.so*: RFC 863 plugin. Start as inetd service, like time below.
|
||||||
|
|
||||||
* *hwclock.so*: Restore and save system clock from/to RTC on
|
* *rtc.so*: Restore and save system clock from/to RTC on boot/halt.
|
||||||
startup/shutdown.
|
|
||||||
|
|
||||||
* *initctl.so*: Extends finit with a traditional `initctl` functionality.
|
* *initctl.so*: Extends finit with a traditional `initctl` functionality.
|
||||||
|
|
||||||
* *lost.so*: Very simple `HOOK_SVC_LOST` example. Logs process ID and
|
* *modules-load.so*: Scans /etc/modules-load.d for modules to modprobe.
|
||||||
name to syslog. _Optional plugin._
|
|
||||||
|
|
||||||
* *netlink.so*: Listens to Linux kernel Netlink events for gateway and
|
* *netlink.so*: Listens to Linux kernel Netlink events for gateway and
|
||||||
interfaces. These events are then sent to the Finit service monitor
|
interfaces. These events are then sent to the Finit service monitor
|
||||||
@@ -102,19 +100,6 @@ Hooks
|
|||||||
all modified/removed services have been stopped. When the hook has
|
all modified/removed services have been stopped. When the hook has
|
||||||
completed, Finit continues to start all modified and new services.
|
completed, Finit continues to start all modified and new services.
|
||||||
|
|
||||||
* `HOOK_SVC_LOST`: Called when a process is lost. When reconfiguring
|
|
||||||
services at runtime this hook may be called a lot. However, it may be
|
|
||||||
a quite useful hook to monitor a system post bootstrap when no, or
|
|
||||||
few, services are expected to exit. A default plugin `lost.so` is
|
|
||||||
available in the `plugins/` subdirectory as an example.
|
|
||||||
|
|
||||||
**NOTE:** This hook callback gets the lost PID as argument.
|
|
||||||
|
|
||||||
* `HOOK_SVC_START`: Like `HOOK_SVC_LOST`, but called when a process is
|
|
||||||
started. Same caveats apply.
|
|
||||||
|
|
||||||
**NOTE:** This hook callback gets the new PID as argument.
|
|
||||||
|
|
||||||
* `HOOK_RUNLEVEL_CHANGE`: Called when the user has issued a runlevel
|
* `HOOK_RUNLEVEL_CHANGE`: Called when the user has issued a runlevel
|
||||||
change. The hook is called when services not matching the new
|
change. The hook is called when services not matching the new
|
||||||
runlevel have been been stopped. When the hook has completed, Finit
|
runlevel have been been stopped. When the hook has completed, Finit
|
||||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
@@ -7,7 +7,7 @@ AM_CPPFLAGS += $(lite_CFLAGS)
|
|||||||
|
|
||||||
if STATIC
|
if STATIC
|
||||||
noinst_LTLIBRARIES = libplug.la
|
noinst_LTLIBRARIES = libplug.la
|
||||||
libplug_la_SOURCES = bootmisc.c hwclock.c initctl.c pidfile.c procps.c tty.c urandom.c
|
libplug_la_SOURCES = bootmisc.c modprobe.c rtc.c initctl.c pidfile.c procps.c tty.c urandom.c
|
||||||
|
|
||||||
if BUILD_ALSA_UTILS_PLUGIN
|
if BUILD_ALSA_UTILS_PLUGIN
|
||||||
libplug_la_SOURCES += alsa-utils.c
|
libplug_la_SOURCES += alsa-utils.c
|
||||||
@@ -39,8 +39,8 @@ libplug_la_SOURCES += time.c
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if BUILD_LOST_PLUGIN
|
if BUILD_MODULES_LOAD_PLUGIN
|
||||||
libplug_la_SOURCES += lost.c
|
libplug_la_SOURCES += modules-load.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if BUILD_NETLINK_PLUGIN
|
if BUILD_NETLINK_PLUGIN
|
||||||
@@ -52,7 +52,7 @@ libplug_la_SOURCES += resolvconf.c
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
else
|
else
|
||||||
pkglib_LTLIBRARIES = bootmisc.la hwclock.la initctl.la pidfile.la procps.la tty.la urandom.la
|
pkglib_LTLIBRARIES = bootmisc.la modprobe.la rtc.la initctl.la pidfile.la procps.la tty.la urandom.la
|
||||||
|
|
||||||
if BUILD_ALSA_UTILS_PLUGIN
|
if BUILD_ALSA_UTILS_PLUGIN
|
||||||
pkglib_LTLIBRARIES += alsa-utils.la
|
pkglib_LTLIBRARIES += alsa-utils.la
|
||||||
@@ -84,8 +84,8 @@ pkglib_LTLIBRARIES += time.la
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if BUILD_LOST_PLUGIN
|
if BUILD_MODULES_LOAD_PLUGIN
|
||||||
pkglib_LTLIBRARIES += lost.la
|
pkglib_LTLIBRARIES += modules-load.la
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if BUILD_NETLINK_PLUGIN
|
if BUILD_NETLINK_PLUGIN
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
{
|
{
|
||||||
char *cmd;
|
char *cmd;
|
||||||
char line[80];
|
char line[256];
|
||||||
|
|
||||||
cmd = which(DAEMON);
|
cmd = which(DAEMON);
|
||||||
if (!cmd) {
|
if (!cmd) {
|
||||||
@@ -58,7 +58,7 @@ static void setup(void *arg)
|
|||||||
erase("/var/run/dbus/pid");
|
erase("/var/run/dbus/pid");
|
||||||
|
|
||||||
/* Register service with Finit */
|
/* Register service with Finit */
|
||||||
snprintf(line, sizeof(line), "[S12345] %s %s -- %s", cmd, ARGS, DESC);
|
snprintf(line, sizeof(line), "[S12345] pid:!/run/dbus/pid log:prio:daemon.info,tag:dbus %s %s -- %s", cmd, ARGS, DESC);
|
||||||
if (service_register(SVC_TYPE_SERVICE, line, global_rlimit, NULL))
|
if (service_register(SVC_TYPE_SERVICE, line, global_rlimit, NULL))
|
||||||
_pe("Failed registering %s", DAEMON);
|
_pe("Failed registering %s", DAEMON);
|
||||||
free(cmd);
|
free(cmd);
|
||||||
|
|||||||
@@ -0,0 +1,176 @@
|
|||||||
|
/* Coldplug modules using modalias magic
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Joachim Nilsson <troglobit@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cold plug magic taken from Buildroot
|
||||||
|
* https://github.com/buildroot/buildroot/commit/b4fc5a180c81689a982d5c595844331684c14f51
|
||||||
|
*
|
||||||
|
* The plugin basically does this, only in C:
|
||||||
|
*
|
||||||
|
* system("find /sys/devices -name modalias -print0"
|
||||||
|
* " | xargs -0 sort -u -z"
|
||||||
|
* " | xargs -0 modprobe -abq");
|
||||||
|
*
|
||||||
|
* Note: BusyBox must *not* be built with CONFIG_MODPROBE_SMALL
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fnmatch.h>
|
||||||
|
#include <ftw.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/time.h> /* gettimeofday() */
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <lite/lite.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "finit.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
#include "plugin.h"
|
||||||
|
|
||||||
|
struct module {
|
||||||
|
TAILQ_ENTRY(module) link;
|
||||||
|
char *alias;
|
||||||
|
};
|
||||||
|
|
||||||
|
static TAILQ_HEAD(, module) modules = TAILQ_HEAD_INITIALIZER(modules);
|
||||||
|
|
||||||
|
static int modprobe(char *alias)
|
||||||
|
{
|
||||||
|
char *args[] = {
|
||||||
|
"modprobe",
|
||||||
|
"-abq",
|
||||||
|
alias,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
pid = fork();
|
||||||
|
switch (pid) {
|
||||||
|
case -1:
|
||||||
|
_pe("Failed forking modprobe child");
|
||||||
|
return 1;
|
||||||
|
case 0:
|
||||||
|
execvp(args[0], args);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (!complete(args[0], pid))
|
||||||
|
_d("Successful modprobe of %s", alias);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void alias_add(char *alias)
|
||||||
|
{
|
||||||
|
struct module *m;
|
||||||
|
|
||||||
|
m = malloc(sizeof(*m));
|
||||||
|
if (!m)
|
||||||
|
return;
|
||||||
|
m->alias = strdup(alias);
|
||||||
|
if (!m->alias) {
|
||||||
|
free(m);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TAILQ_INSERT_TAIL(&modules, m, link);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void alias_remove(struct module *m)
|
||||||
|
{
|
||||||
|
TAILQ_REMOVE(&modules, m, link);
|
||||||
|
free(m->alias);
|
||||||
|
free(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int alias_exist(char *alias)
|
||||||
|
{
|
||||||
|
struct module *m;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(m, &modules, link) {
|
||||||
|
if (!strcmp(m->alias, alias))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int scan_alias(const char *path, const struct stat *st, int flag, struct FTW *unused)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
char buf[256];
|
||||||
|
|
||||||
|
if (fnmatch("*/modalias", path, 0))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fp = fopen(path, "r");
|
||||||
|
if (!fp)
|
||||||
|
return 0;
|
||||||
|
if (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
chomp(buf);
|
||||||
|
if (!alias_exist(buf))
|
||||||
|
alias_add(buf);
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void coldplug(void *arg)
|
||||||
|
{
|
||||||
|
struct module *m, *tmp;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
print_desc("Cold plugging system", NULL);
|
||||||
|
nftw("/sys/devices", scan_alias, 200, FTW_DEPTH);
|
||||||
|
TAILQ_FOREACH_SAFE(m, &modules, link, tmp) {
|
||||||
|
rc += modprobe(m->alias);
|
||||||
|
alias_remove(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
print_result(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static plugin_t plugin = {
|
||||||
|
.name = __FILE__,
|
||||||
|
.hook[HOOK_BASEFS_UP] = { .cb = coldplug },
|
||||||
|
.depends = { "bootmisc", }
|
||||||
|
};
|
||||||
|
|
||||||
|
PLUGIN_INIT(plugin_init)
|
||||||
|
{
|
||||||
|
plugin_register(&plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
PLUGIN_EXIT(plugin_exit)
|
||||||
|
{
|
||||||
|
plugin_unregister(&plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Variables:
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
/* Scans /etc/modules-load.d for modules to load.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Robert Andersson <robert.m.andersson@se.atlascopco.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <lite/lite.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
|
#include "finit.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
#include "plugin.h"
|
||||||
|
#include "service.h"
|
||||||
|
#include "conf.h"
|
||||||
|
|
||||||
|
#define MODULES_LOAD_PATH "/etc/modules-load.d"
|
||||||
|
#define SERVICE_LINE \
|
||||||
|
":%d name:modprobe.%s [2345] /sbin/modprobe %s %s -- Kernel module: %s"
|
||||||
|
|
||||||
|
static void load(void *arg)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
DIR *dirp;
|
||||||
|
struct dirent *direntp;
|
||||||
|
char line[256];
|
||||||
|
int index = 1;
|
||||||
|
|
||||||
|
_d("Scanning " MODULES_LOAD_PATH " for config files ...");
|
||||||
|
|
||||||
|
dirp = opendir(MODULES_LOAD_PATH);
|
||||||
|
if (!dirp) return;
|
||||||
|
|
||||||
|
while ((direntp = readdir(dirp)))
|
||||||
|
{
|
||||||
|
char module_path[PATH_MAX];
|
||||||
|
strlcpy(module_path, MODULES_LOAD_PATH "/", sizeof(module_path));
|
||||||
|
strlcat(module_path, direntp->d_name, sizeof(module_path));
|
||||||
|
|
||||||
|
fp = fopen(module_path, "r");
|
||||||
|
if (!fp) continue;
|
||||||
|
|
||||||
|
while (fgets(line, sizeof(line), fp)) {
|
||||||
|
char cmd[CMD_SIZE], *mod, *args;
|
||||||
|
|
||||||
|
mod = strip_line(line);
|
||||||
|
if (!*mod) continue;
|
||||||
|
|
||||||
|
mod = chomp(mod);
|
||||||
|
if (!mod || !*mod) continue;
|
||||||
|
|
||||||
|
mod = strtok_r(mod, " ", &args);
|
||||||
|
|
||||||
|
snprintf(cmd, sizeof(cmd), SERVICE_LINE,
|
||||||
|
index, mod, mod, args, mod);
|
||||||
|
service_register(SVC_TYPE_TASK, cmd, global_rlimit, NULL);
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dirp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static plugin_t plugin = {
|
||||||
|
.name = __FILE__,
|
||||||
|
.hook[HOOK_BASEFS_UP] = {
|
||||||
|
.cb = load
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
PLUGIN_INIT(plugin_init)
|
||||||
|
{
|
||||||
|
plugin_register(&plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
PLUGIN_EXIT(plugin_exit)
|
||||||
|
{
|
||||||
|
plugin_unregister(&plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Variables:
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
/* Simple pidfile event monitor for the Finit condition engine
|
/* Simple pidfile event monitor for the Finit condition engine
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
|
* Copyright (c) 2015-2016 Tobias Waldekranz <tobias@waldekranz.com>
|
||||||
|
* Copyright (c) 2016-2020 Joachim Nilsson <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -21,99 +22,277 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <glob.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
|
#include <lite/queue.h>
|
||||||
#include <sys/inotify.h>
|
#include <sys/inotify.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
#include "pid.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
|
|
||||||
struct context {
|
struct wd_entry {
|
||||||
|
TAILQ_ENTRY(wd_entry) link;
|
||||||
|
char *path;
|
||||||
int fd;
|
int fd;
|
||||||
int wd;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static char *mkcond(char *buf, size_t len, char *nm)
|
struct context {
|
||||||
|
int fd;
|
||||||
|
TAILQ_HEAD(, wd_entry) wd_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct context pidfile_ctx;
|
||||||
|
|
||||||
|
static int watcher_add(struct context *ctx, char *path)
|
||||||
{
|
{
|
||||||
snprintf(buf, len, "svc%s%s", nm[0] != '/' ? "/" : "", nm);
|
struct wd_entry *wd;
|
||||||
return buf;
|
uint32_t mask = IN_ONLYDIR | IN_CREATE | IN_ATTRIB | IN_DELETE | IN_MODIFY | IN_MOVED_TO;
|
||||||
|
char *ptr;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
_d("pidfile: Adding new watcher for path %s", path);
|
||||||
|
ptr = strstr(path, "run/");
|
||||||
|
if (ptr) {
|
||||||
|
char *slash;
|
||||||
|
|
||||||
|
ptr += 4;
|
||||||
|
slash = strchr(ptr, '/');
|
||||||
|
if (slash) {
|
||||||
|
ptr = slash++;
|
||||||
|
slash = strchr(ptr, '/');
|
||||||
|
if (slash) {
|
||||||
|
_d("pidfile: Path too deep, skipping.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = inotify_add_watch(ctx->fd, path, mask);
|
||||||
|
if (fd < 0) {
|
||||||
|
_pe("inotify_add_watch()");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
wd = malloc(sizeof(struct wd_entry));
|
||||||
|
if (!wd) {
|
||||||
|
_pe("Failed allocating new `struct wd_entry`");
|
||||||
|
inotify_rm_watch(ctx->fd, fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
wd->path = path;
|
||||||
|
wd->fd = fd;
|
||||||
|
TAILQ_INSERT_HEAD(&ctx->wd_list, wd, link);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int watcher_del(struct context *ctx, struct wd_entry *wde)
|
||||||
|
{
|
||||||
|
_d("pidfile: Removing watcher for removed path %s", wde->path);
|
||||||
|
TAILQ_REMOVE(&ctx->wd_list, wde, link);
|
||||||
|
inotify_rm_watch(ctx->fd, wde->fd);
|
||||||
|
free(wde->path);
|
||||||
|
free(wde);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_conds(char *dir, char *name, uint32_t mask)
|
||||||
|
{
|
||||||
|
char cond[MAX_COND_LEN];
|
||||||
|
char fn[PATH_MAX];
|
||||||
|
svc_t *svc;
|
||||||
|
|
||||||
|
_d("Got dir: %s, name: %s, mask: %08x", dir, name, mask);
|
||||||
|
snprintf(fn, sizeof(fn), "%s/%s", dir, name);
|
||||||
|
|
||||||
|
svc = svc_find_by_pidfile(fn);
|
||||||
|
if (!svc) {
|
||||||
|
_d("pidfile: No matching svc for %s", fn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_d("pidfile: Found svc %s for %s with pid %d", svc->name, fn, svc->pid);
|
||||||
|
|
||||||
|
mkcond(svc, cond, sizeof(cond));
|
||||||
|
if (mask & (IN_CREATE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO)) {
|
||||||
|
svc_started(svc);
|
||||||
|
if (svc_is_forking(svc)) {
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
pid = pid_file_read(pid_file(svc));
|
||||||
|
_d("Forking service %s changed PID from %d to %d",
|
||||||
|
svc->cmd, svc->pid, pid);
|
||||||
|
svc->pid = pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
cond_set(cond);
|
||||||
|
} else if (mask & IN_DELETE)
|
||||||
|
cond_clear(cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* synthesize events in case of new run dirs */
|
||||||
|
static void scan_for_pidfiles(struct context *ctx, char *dir, int len)
|
||||||
|
{
|
||||||
|
glob_t gl;
|
||||||
|
size_t i;
|
||||||
|
char path[len + 6];
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "%s/*.pid", dir);
|
||||||
|
rc = glob(path, GLOB_NOSORT, NULL, &gl);
|
||||||
|
if (rc && rc != GLOB_NOMATCH)
|
||||||
|
return;
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "%s/pid", dir);
|
||||||
|
rc = glob(path, GLOB_NOSORT | GLOB_APPEND, NULL, &gl);
|
||||||
|
if (rc && rc != GLOB_NOMATCH)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < gl.gl_pathc; i++) {
|
||||||
|
_d("scan found %s", gl.gl_pathv[i]);
|
||||||
|
update_conds(dir, gl.gl_pathv[i], IN_CREATE);
|
||||||
|
}
|
||||||
|
globfree(&gl);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_dir(struct context *ctx, struct wd_entry *wde, char *name, int mask)
|
||||||
|
{
|
||||||
|
char *path;
|
||||||
|
int plen;
|
||||||
|
int exist = 0;
|
||||||
|
|
||||||
|
plen = snprintf(NULL, 0, "%s/%s", wde->path, name) + 1;
|
||||||
|
path = malloc(plen);
|
||||||
|
if (!path) {
|
||||||
|
_pe("Failed allocating path buffer for watcher");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
snprintf(path, plen, "%s/%s", wde->path, name);
|
||||||
|
_d("pidfile: path is %s", path);
|
||||||
|
|
||||||
|
TAILQ_FOREACH(wde, &ctx->wd_list, link) {
|
||||||
|
if (!strcmp(wde->path, path)) {
|
||||||
|
exist = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mask & IN_CREATE) {
|
||||||
|
if (!exist) {
|
||||||
|
int rc = watcher_add(ctx, path);
|
||||||
|
|
||||||
|
scan_for_pidfiles(ctx, path, plen);
|
||||||
|
if (!rc)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (mask & IN_DELETE) {
|
||||||
|
if (exist)
|
||||||
|
watcher_del(&pidfile_ctx, wde);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pidfile_callback(void *arg, int fd, int events)
|
static void pidfile_callback(void *arg, int fd, int events)
|
||||||
{
|
{
|
||||||
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
|
||||||
static char cond[MAX_COND_LEN];
|
|
||||||
|
|
||||||
struct inotify_event *ev;
|
struct inotify_event *ev;
|
||||||
ssize_t sz, len;
|
ssize_t sz, off;
|
||||||
svc_t *svc;
|
size_t buflen = 8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
sz = read(fd, ev_buf, sizeof(ev_buf) - 1);
|
buf= malloc(buflen);
|
||||||
if (sz <= 0) {
|
if (!buf) {
|
||||||
_pe("invalid inotify event");
|
_pe("Failed allocating buffer for inotify events");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ev_buf[sz] = 0;
|
|
||||||
|
|
||||||
for (ev = (void *)ev_buf;
|
_d("pidfile: Entering ... reading %zu bytes into ev_buf[]", buflen - 1);
|
||||||
sz > (ssize_t)sizeof(*ev);
|
sz = read(fd, buf, buflen - 1);
|
||||||
len = sizeof(*ev) + ev->len, ev = (void *)ev + len, sz -= len) {
|
if (sz <= 0) {
|
||||||
if (!ev->mask || !strstr(ev->name, ".pid"))
|
_pe("invalid inotify event");
|
||||||
continue;
|
goto done;
|
||||||
|
|
||||||
svc = svc_find_by_pidfile(ev->name);
|
|
||||||
if (!svc)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
mkcond(cond, sizeof(cond), svc->cmd);
|
|
||||||
if (ev->mask & (IN_CREATE | IN_ATTRIB | IN_MODIFY)) {
|
|
||||||
svc_started(svc);
|
|
||||||
cond_set(cond);
|
|
||||||
} else if (ev->mask & IN_DELETE)
|
|
||||||
cond_clear(cond);
|
|
||||||
}
|
}
|
||||||
|
buf[sz] = 0;
|
||||||
|
_d("pidfile: Read %zd bytes, processing ...", sz);
|
||||||
|
|
||||||
|
off = 0;
|
||||||
|
for (off = 0; off < sz; off += sizeof(*ev) + ev->len) {
|
||||||
|
struct wd_entry *wde;
|
||||||
|
|
||||||
|
ev = (struct inotify_event *)&buf[off];
|
||||||
|
|
||||||
|
_d("pidfile: path %s, event: 0x%08x", ev->name, ev->mask);
|
||||||
|
if (!ev->mask)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Find base path for this event */
|
||||||
|
TAILQ_FOREACH(wde, &pidfile_ctx.wd_list, link) {
|
||||||
|
if (wde->fd == ev->wd)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ev->mask & IN_ISDIR) {
|
||||||
|
handle_dir(&pidfile_ctx, wde, ev->name, ev->mask);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ev->mask & IN_DELETE) {
|
||||||
|
_d("pidfile %s/%s removed ...", wde->path, ev->name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ev->mask & (IN_CREATE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO))
|
||||||
|
update_conds(wde->path, ev->name, ev->mask);
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Assert condition only if the service is running, but not if it's
|
* This function is called after `initctl reload` to reassert conditions
|
||||||
* recently been changed or while it's starting up.
|
* for services that have not been changed.
|
||||||
*
|
*
|
||||||
* We must wait for the service to create/touch its pidfile.
|
* We reassert the run/task/service's condition only if it is running,
|
||||||
|
* but not if it's recently been changed or while it's starting up.
|
||||||
*/
|
*/
|
||||||
static void pidfile_reconf(void *arg)
|
static void pidfile_reconf(void *arg)
|
||||||
{
|
{
|
||||||
static char cond[MAX_COND_LEN];
|
static char cond[MAX_COND_LEN];
|
||||||
svc_t *svc, *iter = NULL;
|
svc_t *svc, *iter = NULL;
|
||||||
int restart = 0;
|
|
||||||
|
|
||||||
do {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
restart = 0;
|
if (svc->state != SVC_RUNNING_STATE)
|
||||||
|
continue;
|
||||||
|
|
||||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
if (svc_is_changed(svc) || svc_is_starting(svc))
|
||||||
mkcond(cond, sizeof(cond), svc->cmd);
|
continue;
|
||||||
if (svc->state == SVC_RUNNING_STATE &&
|
|
||||||
!svc_is_changed(svc) &&
|
|
||||||
!svc_is_starting(svc) &&
|
|
||||||
cond_get(cond) != COND_ON) {
|
|
||||||
cond_set_path(cond_path(cond), COND_ON);
|
|
||||||
restart = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (restart)
|
mkcond(svc, cond, sizeof(cond));
|
||||||
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_RUNTASK | SVC_TYPE_INETD);
|
if (cond_get(cond) == COND_ON)
|
||||||
|
continue;
|
||||||
|
|
||||||
} while (restart);
|
cond_set_path(cond_path(cond), COND_ON);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This will call service_step(), which in turn will schedule itself
|
||||||
|
* as long as stepped services change state. Services going from
|
||||||
|
* WAITING to RUNNING will reassert their conditions in that loop,
|
||||||
|
* which in turn may unlock other services, and so on.
|
||||||
|
*/
|
||||||
|
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_RUNTASK | SVC_TYPE_INETD);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pidfile_init(void *arg)
|
static void pidfile_init(void *arg)
|
||||||
{
|
{
|
||||||
char *path;
|
char *path;
|
||||||
struct context *ctx = arg;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The bootmisc plugin is responsible for setting up /var/run.
|
* The bootmisc plugin is responsible for setting up /var/run.
|
||||||
@@ -126,15 +305,9 @@ static void pidfile_init(void *arg)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->wd = inotify_add_watch(ctx->fd, path, IN_CREATE | IN_ATTRIB | IN_DELETE | IN_MODIFY);
|
TAILQ_INIT(&pidfile_ctx.wd_list);
|
||||||
free(path);
|
if (watcher_add(&pidfile_ctx, path))
|
||||||
|
close(pidfile_ctx.fd);
|
||||||
if (ctx->wd < 0) {
|
|
||||||
_pe("inotify_add_watch()");
|
|
||||||
close(ctx->fd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_d("pidfile monitor active");
|
_d("pidfile monitor active");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,7 +319,7 @@ static struct context pidfile_ctx;
|
|||||||
*/
|
*/
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
.name = __FILE__,
|
.name = __FILE__,
|
||||||
.hook[HOOK_BASEFS_UP] = { .arg = &pidfile_ctx, .cb = pidfile_init },
|
.hook[HOOK_BASEFS_UP] = { .cb = pidfile_init },
|
||||||
.hook[HOOK_SVC_RECONF] = { .cb = pidfile_reconf },
|
.hook[HOOK_SVC_RECONF] = { .cb = pidfile_reconf },
|
||||||
.io = {
|
.io = {
|
||||||
.cb = pidfile_callback,
|
.cb = pidfile_callback,
|
||||||
@@ -169,7 +342,13 @@ PLUGIN_INIT(plugin_init)
|
|||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(plugin_exit)
|
||||||
{
|
{
|
||||||
inotify_rm_watch(pidfile_ctx.fd, pidfile_ctx.wd);
|
struct wd_entry *wde, *tmp;
|
||||||
|
|
||||||
|
TAILQ_FOREACH_SAFE(wde, &pidfile_ctx.wd_list, link, tmp) {
|
||||||
|
inotify_rm_watch(pidfile_ctx.fd, wde->fd);
|
||||||
|
free(wde->path);
|
||||||
|
free(wde);
|
||||||
|
}
|
||||||
close(pidfile_ctx.fd);
|
close(pidfile_ctx.fd);
|
||||||
|
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
|
|||||||
@@ -0,0 +1,160 @@
|
|||||||
|
/* Save and restore RTC using hwclock
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012-2019 Joachim Nilsson <troglobit@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <linux/rtc.h>
|
||||||
|
#include <lite/lite.h>
|
||||||
|
|
||||||
|
#include "finit.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
#include "plugin.h"
|
||||||
|
|
||||||
|
/* Kernel RTC driver validates against this date for sanity check */
|
||||||
|
#define RTC_TIMESTAMP_BEGIN_2000 946684800LL /* 2000-01-01 00:00:00 */
|
||||||
|
|
||||||
|
static int rtc_open(void)
|
||||||
|
{
|
||||||
|
char *alt[] = {
|
||||||
|
"/dev/rtc",
|
||||||
|
"/dev/rtc0",
|
||||||
|
"/dev/misc/rtc"
|
||||||
|
};
|
||||||
|
size_t i;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
for (i = 0; i < NELEMS(alt); i++) {
|
||||||
|
fd = open(alt[i], O_RDONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rtc_save(void *arg)
|
||||||
|
{
|
||||||
|
struct timeval tv = { 0 };
|
||||||
|
struct tm tm = { 0 };
|
||||||
|
int fd, rc = 0;
|
||||||
|
|
||||||
|
fd = rtc_open();
|
||||||
|
if (fd < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
rc = gettimeofday(&tv, NULL);
|
||||||
|
if (rc < 0 || tv.tv_sec < RTC_TIMESTAMP_BEGIN_2000) {
|
||||||
|
print_desc(NULL, "System clock invalid, not saving to RTC");
|
||||||
|
invalid:
|
||||||
|
logit(LOG_ERR, "System clock invalid, before 2000-01-01 00:00, not saving to RTC");
|
||||||
|
rc = 2;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_desc(NULL, "Saving system time (UTC) to RTC");
|
||||||
|
gmtime_r(&tv.tv_sec, &tm);
|
||||||
|
if (ioctl(fd, RTC_SET_TIME, &tm) < 0) {
|
||||||
|
if (EINVAL == errno)
|
||||||
|
goto invalid;
|
||||||
|
rc = 1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
print(rc, NULL);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rtc_restore(void *arg)
|
||||||
|
{
|
||||||
|
struct timeval tv = { 0 };
|
||||||
|
struct tm tm = { 0 };
|
||||||
|
int fd, rc = 0;
|
||||||
|
|
||||||
|
fd = rtc_open();
|
||||||
|
if (fd < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ioctl(fd, RTC_RD_TIME, &tm) < 0) {
|
||||||
|
char msg[120];
|
||||||
|
|
||||||
|
snprintf(msg, sizeof(msg), "Failed restoring system clock, %s",
|
||||||
|
EINVAL == errno ? "RTC time is too old" :
|
||||||
|
ENOENT == errno ? "RTC has no saved time" : "see log for details");
|
||||||
|
print_desc(NULL, msg);
|
||||||
|
|
||||||
|
invalid:
|
||||||
|
logit(LOG_ERR, "Failed restoring system clock from RTC.");
|
||||||
|
if (EINVAL == errno)
|
||||||
|
logit(LOG_ERR, "RTC time is too old (before 2000-01-01 00:00)");
|
||||||
|
else if (ENOENT == errno)
|
||||||
|
logit(LOG_ERR, "RTC has no previously saved (valid) time.");
|
||||||
|
else
|
||||||
|
logit(LOG_ERR, "RTC error code %d: %m", errno);
|
||||||
|
rc = 2;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_desc(NULL, "Restoring system clock (UTC) from RTC");
|
||||||
|
tv.tv_sec = mktime(&tm);
|
||||||
|
if (tv.tv_sec < RTC_TIMESTAMP_BEGIN_2000) {
|
||||||
|
errno = EINVAL;
|
||||||
|
goto invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settimeofday(&tv, NULL) == -1)
|
||||||
|
rc = 1;
|
||||||
|
|
||||||
|
out:
|
||||||
|
print(rc, NULL);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static plugin_t plugin = {
|
||||||
|
.name = __FILE__,
|
||||||
|
.hook[HOOK_BASEFS_UP] = {
|
||||||
|
.cb = rtc_restore
|
||||||
|
},
|
||||||
|
.hook[HOOK_SHUTDOWN] = {
|
||||||
|
.cb = rtc_save
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
PLUGIN_INIT(plugin_init)
|
||||||
|
{
|
||||||
|
plugin_register(&plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
PLUGIN_EXIT(plugin_exit)
|
||||||
|
{
|
||||||
|
plugin_unregister(&plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Variables:
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
@@ -57,7 +57,7 @@ static void watcher(void *arg, int fd, int events)
|
|||||||
{
|
{
|
||||||
int len = 0;
|
int len = 0;
|
||||||
char buf[EVENT_SIZE], name[42];
|
char buf[EVENT_SIZE], name[42];
|
||||||
tty_node_t *entry;
|
struct tty *entry;
|
||||||
struct inotify_event *notified = (struct inotify_event *)buf;
|
struct inotify_event *notified = (struct inotify_event *)buf;
|
||||||
|
|
||||||
while ((len = read(fd, buf, sizeof(buf)))) {
|
while ((len = read(fd, buf, sizeof(buf)))) {
|
||||||
@@ -72,11 +72,11 @@ static void watcher(void *arg, int fd, int events)
|
|||||||
|
|
||||||
snprintf(name, sizeof(name), "/dev/%s", notified->name);
|
snprintf(name, sizeof(name), "/dev/%s", notified->name);
|
||||||
entry = tty_find(name);
|
entry = tty_find(name);
|
||||||
if (entry && tty_enabled(&entry->data)) {
|
if (entry && tty_enabled(entry)) {
|
||||||
if (notified->mask & IN_CREATE)
|
if (notified->mask & IN_CREATE)
|
||||||
tty_start(&entry->data);
|
tty_start(entry);
|
||||||
else if (entry->data.pid)
|
else if (entry->pid)
|
||||||
tty_stop(&entry->data);
|
tty_stop(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,5 +3,6 @@ finit
|
|||||||
initctl
|
initctl
|
||||||
logit
|
logit
|
||||||
reboot
|
reboot
|
||||||
|
watchdogd
|
||||||
Makefile
|
Makefile
|
||||||
Makefile.in
|
Makefile.in
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
EXTRA_DIST = rescue.conf
|
EXTRA_DIST = rescue.conf cgreaper.sh
|
||||||
AM_CPPFLAGS = -U_FORTIFY_SOURCE
|
AM_CPPFLAGS = -U_FORTIFY_SOURCE
|
||||||
AM_CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
|
AM_CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
|
||||||
if STATIC
|
if STATIC
|
||||||
@@ -8,13 +8,19 @@ else
|
|||||||
AM_LDFLAGS = -export-dynamic
|
AM_LDFLAGS = -export-dynamic
|
||||||
endif
|
endif
|
||||||
|
|
||||||
bin_PROGRAMS = logit
|
|
||||||
sbin_PROGRAMS = finit initctl reboot
|
sbin_PROGRAMS = finit initctl reboot
|
||||||
|
pkglibexec_SCRIPTS = cgreaper.sh
|
||||||
|
if WATCHDOGD
|
||||||
|
pkglibexec_PROGRAMS = watchdogd
|
||||||
|
endif
|
||||||
|
|
||||||
|
if LOGIT
|
||||||
|
bin_PROGRAMS = logit
|
||||||
logit_SOURCES = logit.c
|
logit_SOURCES = logit.c
|
||||||
logit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
logit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||||
|
endif
|
||||||
|
|
||||||
finit_SOURCES = api.c \
|
finit_SOURCES = api.c cgroup.c cgroup.h \
|
||||||
cond.c cond-w.c cond.h \
|
cond.c cond-w.c cond.h \
|
||||||
telinit.c \
|
telinit.c \
|
||||||
conf.c conf.h \
|
conf.c conf.h \
|
||||||
@@ -25,6 +31,7 @@ finit_SOURCES = api.c \
|
|||||||
mdadm.c mount.c \
|
mdadm.c mount.c \
|
||||||
pid.c pid.h \
|
pid.c pid.h \
|
||||||
plugin.c plugin.h private.h \
|
plugin.c plugin.h private.h \
|
||||||
|
schedule.c schedule.h \
|
||||||
service.c service.h \
|
service.c service.h \
|
||||||
sig.c sig.h \
|
sig.c sig.h \
|
||||||
sm.c sm.h \
|
sm.c sm.h \
|
||||||
@@ -36,9 +43,6 @@ pkginclude_HEADERS = cond.h finit.h helpers.h inetd.h log.h plugin.h svc.h
|
|||||||
if INETD
|
if INETD
|
||||||
finit_SOURCES += inetd.c inetd.h
|
finit_SOURCES += inetd.c inetd.h
|
||||||
endif
|
endif
|
||||||
if WATCHDOGD
|
|
||||||
finit_SOURCES += watchdog.c watchdog.h
|
|
||||||
endif
|
|
||||||
|
|
||||||
finit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
finit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||||
finit_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
|
finit_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
|
||||||
@@ -63,6 +67,12 @@ reboot_LDADD = $(lite_LIBS)
|
|||||||
INIT_LNKS = telinit init
|
INIT_LNKS = telinit init
|
||||||
REBOOT_LNKS = shutdown halt poweroff suspend
|
REBOOT_LNKS = shutdown halt poweroff suspend
|
||||||
|
|
||||||
|
if WATCHDOGD
|
||||||
|
watchdogd_SOURCES = watchdog.c watchdog.h
|
||||||
|
watchdogd_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||||
|
#log.c log.h
|
||||||
|
endif
|
||||||
|
|
||||||
# Hook in install to add finit and reboot symlink(s)
|
# Hook in install to add finit and reboot symlink(s)
|
||||||
install-exec-hook:
|
install-exec-hook:
|
||||||
@$(INSTALL_DATA) $(srcdir)/rescue.conf $(DESTDIR)$(pkglibdir)
|
@$(INSTALL_DATA) $(srcdir)/rescue.conf $(DESTDIR)$(pkglibdir)
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
#include "service.h"
|
#include "service.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
extern svc_t *wdog;
|
||||||
static uev_t api_watcher;
|
static uev_t api_watcher;
|
||||||
|
|
||||||
static int call(int (*action)(svc_t *), char *buf, size_t len)
|
static int call(int (*action)(svc_t *), char *buf, size_t len)
|
||||||
@@ -51,7 +52,7 @@ static int call(int (*action)(svc_t *), char *buf, size_t len)
|
|||||||
return svc_parse_jobstr(buf, len, action, NULL);
|
return svc_parse_jobstr(buf, len, action, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int service_stop(svc_t *svc)
|
static int stop(svc_t *svc)
|
||||||
{
|
{
|
||||||
if (!svc)
|
if (!svc)
|
||||||
return 1;
|
return 1;
|
||||||
@@ -62,7 +63,7 @@ static int service_stop(svc_t *svc)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int service_start(svc_t *svc)
|
static int start(svc_t *svc)
|
||||||
{
|
{
|
||||||
if (!svc)
|
if (!svc)
|
||||||
return 1;
|
return 1;
|
||||||
@@ -73,43 +74,45 @@ static int service_start(svc_t *svc)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int service_restart(svc_t *svc)
|
static int restart(svc_t *svc)
|
||||||
{
|
{
|
||||||
if (!svc)
|
if (!svc)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
if (svc_is_blocked(svc))
|
||||||
|
svc_start(svc);
|
||||||
|
|
||||||
svc_mark_dirty(svc);
|
svc_mark_dirty(svc);
|
||||||
service_step(svc);
|
service_step(svc);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_start (char *buf, size_t len) { return call(service_start, buf, len); }
|
static int do_start (char *buf, size_t len) { return call(start, buf, len); }
|
||||||
static int do_stop (char *buf, size_t len) { return call(service_stop, buf, len); }
|
static int do_stop (char *buf, size_t len) { return call(stop, buf, len); }
|
||||||
static int do_restart(char *buf, size_t len) { return call(service_restart, buf, len); }
|
static int do_restart(char *buf, size_t len) { return call(restart, buf, len); }
|
||||||
|
|
||||||
static char query_buf[368];
|
static char query_buf[368];
|
||||||
static int missing(char *job, int id)
|
static int missing(char *job, char *id)
|
||||||
{
|
{
|
||||||
char buf[20];
|
char buf[20];
|
||||||
char idstr[10] = "";
|
|
||||||
|
|
||||||
if (!job)
|
if (!job)
|
||||||
job = "";
|
job = "";
|
||||||
if (id > 1)
|
if (!id)
|
||||||
snprintf(idstr, sizeof(idstr), ":%d", id);
|
id = "";
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "%s%s ", job, idstr);
|
snprintf(buf, sizeof(buf), "%s:%s ", job, id);
|
||||||
strlcat(query_buf, buf, sizeof(query_buf));
|
strlcat(query_buf, buf, sizeof(query_buf));
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_query(struct init_request *rq, size_t len)
|
static int do_query(char *buf, size_t len)
|
||||||
{
|
{
|
||||||
memset(query_buf, 0, sizeof(query_buf));
|
memset(query_buf, 0, sizeof(query_buf));
|
||||||
if (svc_parse_jobstr(rq->data, strlen(rq->data) + 1, NULL, missing)) {
|
if (svc_parse_jobstr(buf, len, NULL, missing)) {
|
||||||
memcpy(rq->data, query_buf, sizeof(rq->data));
|
memcpy(buf, query_buf, len);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,8 +121,9 @@ static int do_query(struct init_request *rq, size_t len)
|
|||||||
|
|
||||||
static svc_t *do_find(char *buf, size_t len)
|
static svc_t *do_find(char *buf, size_t len)
|
||||||
{
|
{
|
||||||
int id = 1;
|
char *id = NULL;
|
||||||
char *ptr, *input;
|
char *ptr, *input;
|
||||||
|
svc_t *iter = NULL;
|
||||||
|
|
||||||
input = sanitize(buf, len);
|
input = sanitize(buf, len);
|
||||||
if (!input)
|
if (!input)
|
||||||
@@ -128,11 +132,28 @@ static svc_t *do_find(char *buf, size_t len)
|
|||||||
ptr = strchr(input, ':');
|
ptr = strchr(input, ':');
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
*ptr++ = 0;
|
*ptr++ = 0;
|
||||||
id = atonum(ptr);
|
id = ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isdigit(input[0]))
|
if (isdigit(input[0])) {
|
||||||
return svc_find_by_jobid(atonum(input), id);
|
char *ep;
|
||||||
|
long job = 0;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
job = strtol(input, &ep, 10);
|
||||||
|
if ((errno == ERANGE && (job == LONG_MAX || job == LONG_MIN)) ||
|
||||||
|
(errno != 0 && job == 0) ||
|
||||||
|
(input == ep))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!id)
|
||||||
|
return svc_job_iterator(&iter, 1, job);
|
||||||
|
|
||||||
|
return svc_find_by_jobid(job, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!id)
|
||||||
|
return svc_named_iterator(&iter, 1, input);
|
||||||
|
|
||||||
return svc_find_by_nameid(input, id);
|
return svc_find_by_nameid(input, id);
|
||||||
}
|
}
|
||||||
@@ -160,47 +181,6 @@ ev_t ev_list[] = {
|
|||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static int do_handle_event(char *event)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; ev_list[i].event; i++) {
|
|
||||||
ev_t *e = &ev_list[i];
|
|
||||||
size_t len = MAX(strlen(e->event), strlen(event));
|
|
||||||
|
|
||||||
if (!strncasecmp(e->event, event, len)) {
|
|
||||||
e->cb();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event[0] == '-')
|
|
||||||
cond_clear(&event[1]);
|
|
||||||
else if (event[0] == '+')
|
|
||||||
cond_set(&event[1]);
|
|
||||||
else
|
|
||||||
cond_set(event);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int do_handle_emit(char *buf, size_t len)
|
|
||||||
{
|
|
||||||
int result = 0;
|
|
||||||
char *input, *event, *pos;
|
|
||||||
|
|
||||||
input = sanitize(buf, len);
|
|
||||||
if (!input)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
event = strtok_r(input, " ", &pos);
|
|
||||||
while (event) {
|
|
||||||
result += do_handle_event(event);
|
|
||||||
event = strtok_r(NULL, " ", &pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void send_svc(int sd, svc_t *svc)
|
static void send_svc(int sd, svc_t *svc)
|
||||||
{
|
{
|
||||||
svc_t empty;
|
svc_t empty;
|
||||||
@@ -295,31 +275,30 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
|
|
||||||
case INIT_CMD_START_SVC:
|
case INIT_CMD_START_SVC:
|
||||||
_d("start %s", rq.data);
|
_d("start %s", rq.data);
|
||||||
|
strterm(rq.data, sizeof(rq.data));
|
||||||
result = do_start(rq.data, sizeof(rq.data));
|
result = do_start(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_STOP_SVC:
|
case INIT_CMD_STOP_SVC:
|
||||||
_d("stop %s", rq.data);
|
_d("stop %s", rq.data);
|
||||||
|
strterm(rq.data, sizeof(rq.data));
|
||||||
result = do_stop(rq.data, sizeof(rq.data));
|
result = do_stop(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_RESTART_SVC:
|
case INIT_CMD_RESTART_SVC:
|
||||||
_d("restart %s", rq.data);
|
_d("restart %s", rq.data);
|
||||||
|
strterm(rq.data, sizeof(rq.data));
|
||||||
result = do_restart(rq.data, sizeof(rq.data));
|
result = do_restart(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef INETD_ENABLED
|
#ifdef INETD_ENABLED
|
||||||
case INIT_CMD_QUERY_INETD:
|
case INIT_CMD_QUERY_INETD:
|
||||||
_d("query inetd");
|
_d("query inetd");
|
||||||
|
strterm(rq.data, sizeof(rq.data));
|
||||||
result = do_query_inetd(rq.data, sizeof(rq.data));
|
result = do_query_inetd(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case INIT_CMD_EMIT:
|
|
||||||
_d("emit %s", rq.data);
|
|
||||||
result = do_handle_emit(rq.data, sizeof(rq.data));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case INIT_CMD_GET_RUNLEVEL:
|
case INIT_CMD_GET_RUNLEVEL:
|
||||||
_d("get runlevel");
|
_d("get runlevel");
|
||||||
rq.runlevel = runlevel;
|
rq.runlevel = runlevel;
|
||||||
@@ -337,13 +316,23 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wdogpid > 0 && wdogpid != rq.runlevel) {
|
_e("Request to hand-over wdog ... to PID %d", rq.runlevel);
|
||||||
_d("Sending SIGTERM to %d", wdogpid);
|
svc = svc_find_by_pid(rq.runlevel);
|
||||||
kill(wdogpid, SIGTERM);
|
if (!svc) {
|
||||||
do_sleep(1);
|
logit(LOG_ERR, "Cannot find PID %d, not registered.", rq.runlevel);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
_d("wdog was %d, now %d is in charge", wdogpid, rq.runlevel);
|
|
||||||
wdogpid = rq.runlevel;
|
/* Disable and allow Finit to collect bundled watchdog */
|
||||||
|
if (wdog) {
|
||||||
|
logit(LOG_NOTICE, "Stopping and removing %s (PID:%d)", wdog->cmd, wdog->pid);
|
||||||
|
stop(wdog);
|
||||||
|
if (wdog->protect) {
|
||||||
|
wdog->protect = 0;
|
||||||
|
wdog->runlevels = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wdog = svc;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_SVC_ITER:
|
case INIT_CMD_SVC_ITER:
|
||||||
@@ -359,11 +348,13 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
|
|
||||||
case INIT_CMD_SVC_QUERY:
|
case INIT_CMD_SVC_QUERY:
|
||||||
_d("svc query: %s", rq.data);
|
_d("svc query: %s", rq.data);
|
||||||
result = do_query(&rq, len);
|
strterm(rq.data, sizeof(rq.data));
|
||||||
|
result = do_query(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_SVC_FIND:
|
case INIT_CMD_SVC_FIND:
|
||||||
_d("svc find: %s", rq.data);
|
_d("svc find: %s", rq.data);
|
||||||
|
strterm(rq.data, sizeof(rq.data));
|
||||||
send_svc(sd, do_find(rq.data, sizeof(rq.data)));
|
send_svc(sd, do_find(rq.data, sizeof(rq.data)));
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Called by kernel when last child in cgroup exists
|
||||||
|
|
||||||
|
BASE=/sys/fs/cgroup/finit
|
||||||
|
PROC=`basename $1`
|
||||||
|
DIR="$BASE$1"
|
||||||
|
|
||||||
|
logit -p daemon.info -t finit "$PROC stopped, cleaning up control group $DIR"
|
||||||
|
rmdir $DIR
|
||||||
|
|
||||||
|
exit 0
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
/* Finit control group support functions
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Joachim Nilsson <troglobit@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <lite/lite.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static int cg_init = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called by Finit at early boot to mount initial cgroups
|
||||||
|
*/
|
||||||
|
void cgroup_init(void)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
char buf[80];
|
||||||
|
int opts = MS_NODEV | MS_NOEXEC | MS_NOSUID;
|
||||||
|
|
||||||
|
fp = fopen("/proc/cgroups", "r");
|
||||||
|
if (!fp) {
|
||||||
|
_d("No cgroup support");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mount("none", "/sys/fs/cgroup", "tmpfs", opts, NULL)) {
|
||||||
|
_d("Failed mounting cgroups");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip first line, header */
|
||||||
|
fgets(buf, sizeof(buf), fp);
|
||||||
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
char *cgroup;
|
||||||
|
char rc[80];
|
||||||
|
|
||||||
|
cgroup = strtok(buf, "\t ");
|
||||||
|
if (!cgroup)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
snprintf(rc, sizeof(rc), "/sys/fs/cgroup/%s", cgroup);
|
||||||
|
if (mkdir(rc, 0755) && EEXIST != errno)
|
||||||
|
continue;
|
||||||
|
if (mount("cgroup", rc, "cgroup", opts, cgroup))
|
||||||
|
_d("Failed mounting %s cgroup on %s", cgroup, rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Default cgroups for process monitoring */
|
||||||
|
if (mkdir("/sys/fs/cgroup/finit", 0755) && EEXIST != errno)
|
||||||
|
goto fail;
|
||||||
|
if (mount("none", "/sys/fs/cgroup/finit", "cgroup", opts, "none,name=finit")) {
|
||||||
|
_pe("Failed mounting Finit cgroup hierarchy");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set up reaper and enable callbacks */
|
||||||
|
echo("/sys/fs/cgroup/finit/release_agent", 0, FINIT_LIBPATH_ "/cgreaper.sh");
|
||||||
|
echo("/sys/fs/cgroup/finit/notify_on_release", 0, "1");
|
||||||
|
|
||||||
|
/* Default groups, PID 1, services, and user/login processes */
|
||||||
|
if (mkdir("/sys/fs/cgroup/finit/init", 0755) && EEXIST != errno)
|
||||||
|
goto fail;
|
||||||
|
if (mkdir("/sys/fs/cgroup/finit/system", 0755) && EEXIST != errno)
|
||||||
|
goto fail;
|
||||||
|
if (mkdir("/sys/fs/cgroup/finit/user", 0755) && EEXIST != errno)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* Move ourselves to init */
|
||||||
|
echo("/sys/fs/cgroup/finit/init/cgroup.procs", 0, "1");
|
||||||
|
|
||||||
|
/* We have signal, main screen turn on! */
|
||||||
|
cg_init = 1;
|
||||||
|
fail:
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int move_pid(char *group, char *name, char *id, int pid)
|
||||||
|
{
|
||||||
|
char path[256];
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "/sys/fs/cgroup/%s/%s:%s", group, name, id);
|
||||||
|
if (mkdir(path, 0755) && errno != EEXIST)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
strlcat(path, "/cgroup.procs", sizeof(path));
|
||||||
|
|
||||||
|
return echo(path, 0, "%d", pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cgroup_user(char *name)
|
||||||
|
{
|
||||||
|
if (!cg_init)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return move_pid("finit/user", name, "0", getpid());
|
||||||
|
}
|
||||||
|
|
||||||
|
int cgroup_service(char *nm, char *id, int pid)
|
||||||
|
{
|
||||||
|
if (!cg_init)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (pid <= 0) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return move_pid("finit/system", nm, id, pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Variables:
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/* Finit control group support functions
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Joachim Nilsson <troglobit@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FINIT_CGROUP_H_
|
||||||
|
#define FINIT_CGROUP_H_
|
||||||
|
|
||||||
|
void cgroup_init (void);
|
||||||
|
|
||||||
|
int cgroup_user (char *name);
|
||||||
|
int cgroup_service (char *cmd, char *id, int pid);
|
||||||
|
|
||||||
|
#endif /* FINIT_CGROUP_H_ */
|
||||||
@@ -125,7 +125,7 @@ error:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
svc_t *client_svc_find(char *arg)
|
svc_t *client_svc_find(const char *arg)
|
||||||
{
|
{
|
||||||
int sd = -1;
|
int sd = -1;
|
||||||
struct init_request rq = {
|
struct init_request rq = {
|
||||||
|
|||||||
@@ -32,6 +32,6 @@ int client_disconnect (void);
|
|||||||
|
|
||||||
int client_send (struct init_request *rq, ssize_t len);
|
int client_send (struct init_request *rq, ssize_t len);
|
||||||
svc_t *client_svc_iterator (int first);
|
svc_t *client_svc_iterator (int first);
|
||||||
svc_t *client_svc_find (char *arg);
|
svc_t *client_svc_find (const char *arg);
|
||||||
|
|
||||||
#endif /* FINIT_CLIENT_H_ */
|
#endif /* FINIT_CLIENT_H_ */
|
||||||
|
|||||||
@@ -31,12 +31,96 @@
|
|||||||
#include "pid.h"
|
#include "pid.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
|
|
||||||
static int cond_set_gen(const char *path, unsigned int gen)
|
/*
|
||||||
|
* The service condition name is constructed from the 'svc/' prefix, the
|
||||||
|
* dirname of the svc->cmd, e.g., '/usr/bin/teamd' => 'usr/bin', and the
|
||||||
|
* service's pid:filename, including an optional subdirectory, without
|
||||||
|
* the .pid extension.
|
||||||
|
*
|
||||||
|
* The following example uses the team (aggregate) service:
|
||||||
|
*
|
||||||
|
* service pid:!/run/teamd/a1.pid /usr/bin/teamd -f /etc/teamd/a1.conf
|
||||||
|
*
|
||||||
|
* => 'svc/' + 'usr/bin' + 'teamd/a1' => svc/usr/bin/teamd/a1
|
||||||
|
*
|
||||||
|
* The next example uses the dbus-daemon:
|
||||||
|
*
|
||||||
|
* service pid:!/run/dbus/pid /usr/bin/dbus-daemon
|
||||||
|
*
|
||||||
|
* => 'svc/' + 'usr/bin' + 'dbus' => svc/usr/bin/dbus
|
||||||
|
*
|
||||||
|
* The last example uses lxc-start to start container foo:
|
||||||
|
*
|
||||||
|
* service pid:!/run/lxc/foo.pid lxc-start -n foo -F -p /run/lxc/foo.pid -- Container foo
|
||||||
|
*
|
||||||
|
* => 'svc/' + '' + 'lxc/foo' => svc/lxc/foo
|
||||||
|
*/
|
||||||
|
char *mkcond(svc_t *svc, char *buf, size_t len)
|
||||||
{
|
{
|
||||||
|
char path[256];
|
||||||
|
char *pidfile;
|
||||||
|
char *ptr, *nm;
|
||||||
|
|
||||||
|
strlcpy(path, svc->cmd, sizeof(path));
|
||||||
|
ptr = rindex(path, '/');
|
||||||
|
if (ptr)
|
||||||
|
*ptr++ = 0;
|
||||||
|
else
|
||||||
|
path[0] = 0;
|
||||||
|
|
||||||
|
/* Figure out default name used when registering service */
|
||||||
|
if (ptr)
|
||||||
|
nm = ptr;
|
||||||
|
else
|
||||||
|
nm = svc->cmd;
|
||||||
|
|
||||||
|
pidfile = pid_file(svc);
|
||||||
|
ptr = strstr(pidfile, "run");
|
||||||
|
if (ptr)
|
||||||
|
ptr += 3;
|
||||||
|
else
|
||||||
|
ptr = rindex(pidfile, '/');
|
||||||
|
|
||||||
|
/* Custom name:foo declaration found => svc/foo instead of /svc/bin/path/pidfile-.pid */
|
||||||
|
if (strcmp(nm, svc->name)) {
|
||||||
|
snprintf(buf, len, "svc/%s", svc->name);
|
||||||
|
_d("Composed condition from svc->name %s => %s", svc->name, buf);
|
||||||
|
} else {
|
||||||
|
snprintf(buf, len, "svc%s%s%s", path[0] != 0 && path[0] != '/' ? "/" : "", path, ptr);
|
||||||
|
_d("Composed condition from cmd %s (path %s) and pidfile %s => %s", svc->cmd, path, ptr, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Case: /var/run/dbus/pid */
|
||||||
|
ptr = strstr(buf, "/pid");
|
||||||
|
if (ptr && !strcmp(ptr, "/pid"))
|
||||||
|
*ptr = 0;
|
||||||
|
|
||||||
|
/* Case /var/run/teamd/a1.pid */
|
||||||
|
ptr = strstr(buf, ".pid");
|
||||||
|
if (ptr && !strcmp(ptr, ".pid"))
|
||||||
|
*ptr = 0;
|
||||||
|
|
||||||
|
/* Always append /ID if service is declared with :ID */
|
||||||
|
if (svc->id[0]) {
|
||||||
|
strlcat(buf, "/", len);
|
||||||
|
strlcat(buf, svc->id, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
_d("Creating condition => %s", buf);
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cond_set_gen(const char *file, unsigned int gen)
|
||||||
|
{
|
||||||
|
char *ptr, path[256];
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
fp = fopen(path, "w");
|
/* /var/run --> /run symlink may not exist (yet) */
|
||||||
|
ptr = pid_runpath(file, path, sizeof(path));
|
||||||
|
|
||||||
|
fp = fopen(ptr, "w");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@@ -124,6 +208,7 @@ static int svc_has_cond(svc_t *svc)
|
|||||||
case SVC_TYPE_SERVICE:
|
case SVC_TYPE_SERVICE:
|
||||||
case SVC_TYPE_TASK:
|
case SVC_TYPE_TASK:
|
||||||
case SVC_TYPE_RUN:
|
case SVC_TYPE_RUN:
|
||||||
|
case SVC_TYPE_SYSV:
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -148,7 +233,7 @@ static void cond_update(const char *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void cond_set(const char *name)
|
void cond_set(const char *name)
|
||||||
{
|
{
|
||||||
_d("%s", name);
|
_d("%s", name);
|
||||||
if (string_compare(name, "nop"))
|
if (string_compare(name, "nop"))
|
||||||
return;
|
return;
|
||||||
@@ -167,7 +252,7 @@ void cond_set_oneshot(const char *name)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
path = cond_path(name);
|
path = cond_path(name);
|
||||||
_d("s => %s", name, path);
|
_d("%s => %s", name, path);
|
||||||
|
|
||||||
if (cond_checkpath(path))
|
if (cond_checkpath(path))
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -29,7 +29,6 @@
|
|||||||
#include "pid.h"
|
#include "pid.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
|
|
||||||
|
|
||||||
const char *condstr(enum cond_state s)
|
const char *condstr(enum cond_state s)
|
||||||
{
|
{
|
||||||
static const char *strs[] = {
|
static const char *strs[] = {
|
||||||
@@ -43,21 +42,25 @@ const char *condstr(enum cond_state s)
|
|||||||
|
|
||||||
const char *cond_path(const char *name)
|
const char *cond_path(const char *name)
|
||||||
{
|
{
|
||||||
|
static char path[256];
|
||||||
char tmp[MAX_ARG_LEN];
|
char tmp[MAX_ARG_LEN];
|
||||||
static char file[MAX_ARG_LEN];
|
|
||||||
|
|
||||||
snprintf(tmp, sizeof(tmp), COND_PATH "/%s", name);
|
snprintf(tmp, sizeof(tmp), COND_PATH "/%s", name);
|
||||||
|
|
||||||
return pid_runpath(tmp, file, sizeof(file));
|
return pid_runpath(tmp, path, sizeof(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int cond_get_gen(const char *path)
|
unsigned int cond_get_gen(const char *file)
|
||||||
{
|
{
|
||||||
unsigned int gen;
|
unsigned int gen;
|
||||||
|
char *ptr, path[256];
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
fp = fopen(path, "r");
|
/* /var/run --> /run symlink may not exist (yet) */
|
||||||
|
ptr = pid_runpath(file, path, sizeof(path));
|
||||||
|
|
||||||
|
fp = fopen(ptr, "r");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -89,9 +92,9 @@ enum cond_state cond_get(const char *name)
|
|||||||
|
|
||||||
enum cond_state cond_get_agg(const char *names)
|
enum cond_state cond_get_agg(const char *names)
|
||||||
{
|
{
|
||||||
char *cond;
|
static char conds[MAX_COND_LEN];
|
||||||
enum cond_state s = COND_ON;
|
enum cond_state s = COND_ON;
|
||||||
static char conds[MAX_ARG_LEN];
|
char *cond;
|
||||||
|
|
||||||
if (!names)
|
if (!names)
|
||||||
return COND_ON;
|
return COND_ON;
|
||||||
@@ -105,8 +108,8 @@ enum cond_state cond_get_agg(const char *names)
|
|||||||
|
|
||||||
int cond_affects(const char *name, const char *names)
|
int cond_affects(const char *name, const char *names)
|
||||||
{
|
{
|
||||||
|
static char conds[MAX_COND_LEN];
|
||||||
char *cond;
|
char *cond;
|
||||||
static char conds[MAX_ARG_LEN];
|
|
||||||
|
|
||||||
if (!name || !names)
|
if (!name || !names)
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define FINIT_COND_H_
|
#define FINIT_COND_H_
|
||||||
|
|
||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
|
#include <svc.h>
|
||||||
|
|
||||||
#define COND_DIR "finit/cond"
|
#define COND_DIR "finit/cond"
|
||||||
#define COND_PATH _PATH_VARRUN COND_DIR
|
#define COND_PATH _PATH_VARRUN COND_DIR
|
||||||
@@ -13,6 +14,7 @@ typedef enum cond_state {
|
|||||||
COND_ON
|
COND_ON
|
||||||
} cond_state_t;
|
} cond_state_t;
|
||||||
|
|
||||||
|
char *mkcond (svc_t *svc, char *buf, size_t len);
|
||||||
const char *condstr (enum cond_state s);
|
const char *condstr (enum cond_state s);
|
||||||
const char *cond_path (const char *name);
|
const char *cond_path (const char *name);
|
||||||
unsigned int cond_get_gen (const char *path);
|
unsigned int cond_get_gen (const char *path);
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include <lite/lite.h>
|
#include <lite/lite.h>
|
||||||
#include <lite/queue.h> /* BSD sys/queue.h API */
|
#include <lite/queue.h> /* BSD sys/queue.h API */
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
#include <glob.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
@@ -52,7 +53,7 @@ struct conf_change {
|
|||||||
char *name;
|
char *name;
|
||||||
};
|
};
|
||||||
|
|
||||||
static uev_t w1, w2, w3;
|
static uev_t w1, w2, w3, w4;
|
||||||
static TAILQ_HEAD(head, conf_change) conf_change_list = TAILQ_HEAD_INITIALIZER(conf_change_list);
|
static TAILQ_HEAD(head, conf_change) conf_change_list = TAILQ_HEAD_INITIALIZER(conf_change_list);
|
||||||
|
|
||||||
static int parse_conf(char *file);
|
static int parse_conf(char *file);
|
||||||
@@ -267,7 +268,7 @@ char *rlim2str(int rlim)
|
|||||||
|
|
||||||
char *lim2str(struct rlimit *rlim)
|
char *lim2str(struct rlimit *rlim)
|
||||||
{
|
{
|
||||||
char tmp[20];
|
char tmp[25];
|
||||||
static char buf[42];
|
static char buf[42];
|
||||||
|
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
@@ -463,6 +464,12 @@ static void parse_dynamic(char *line, struct rlimit rlimit[], char *file)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Similar to task but is treated like a SysV init script */
|
||||||
|
if (MATCH_CMD(line, "sysv ", x)) {
|
||||||
|
service_register(SVC_TYPE_SYSV, x, rlimit, file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Classic inetd service */
|
/* Classic inetd service */
|
||||||
if (MATCH_CMD(line, "inetd ", x)) {
|
if (MATCH_CMD(line, "inetd ", x)) {
|
||||||
#ifdef INETD_ENABLED
|
#ifdef INETD_ENABLED
|
||||||
@@ -577,8 +584,8 @@ static int parse_conf(char *file)
|
|||||||
*/
|
*/
|
||||||
int conf_reload(void)
|
int conf_reload(void)
|
||||||
{
|
{
|
||||||
int i, num;
|
size_t i;
|
||||||
struct dirent **e;
|
glob_t gl;
|
||||||
|
|
||||||
/* Mark and sweep */
|
/* Mark and sweep */
|
||||||
svc_mark_dynamic();
|
svc_mark_dynamic();
|
||||||
@@ -601,20 +608,14 @@ int conf_reload(void)
|
|||||||
parse_conf(FINIT_CONF);
|
parse_conf(FINIT_CONF);
|
||||||
|
|
||||||
/* Next, read all *.conf in /etc/finit.d/ */
|
/* Next, read all *.conf in /etc/finit.d/ */
|
||||||
num = scandir(rcsd, &e, NULL, alphasort);
|
glob("/etc/finit.d/*.conf", 0, NULL, &gl);
|
||||||
if (num < 0) {
|
glob("/etc/finit.d/enabled/*.conf", GLOB_APPEND, NULL, &gl);
|
||||||
_d("Skipping %s, no files found ...", rcsd);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < num; i++) {
|
for (i = 0; i < gl.gl_pathc; i++) {
|
||||||
char *name = e[i]->d_name;
|
char *path = gl.gl_pathv[i];
|
||||||
char path[LINE_SIZE];
|
|
||||||
size_t len;
|
size_t len;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
snprintf(path, sizeof(path), "%s/%s", rcsd, name);
|
|
||||||
|
|
||||||
/* Check that it's an actual file ... beyond any symlinks */
|
/* Check that it's an actual file ... beyond any symlinks */
|
||||||
if (lstat(path, &st)) {
|
if (lstat(path, &st)) {
|
||||||
_d("Skipping %s, cannot access: %s", path, strerror(errno));
|
_d("Skipping %s, cannot access: %s", path, strerror(errno));
|
||||||
@@ -650,9 +651,7 @@ int conf_reload(void)
|
|||||||
parse_conf_dynamic(path);
|
parse_conf_dynamic(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (num--)
|
globfree(&gl);
|
||||||
free(e[num]);
|
|
||||||
free(e);
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
/* Drop record of all .conf changes */
|
/* Drop record of all .conf changes */
|
||||||
@@ -706,6 +705,8 @@ static int do_change(char *name, uint32_t mask)
|
|||||||
{
|
{
|
||||||
struct conf_change *node;
|
struct conf_change *node;
|
||||||
|
|
||||||
|
_d("Change detected for %s, mask 0x%08x", name, mask);
|
||||||
|
|
||||||
node = conf_find(name);
|
node = conf_find(name);
|
||||||
if (mask & (IN_DELETE | IN_MOVED_FROM)) {
|
if (mask & (IN_DELETE | IN_MOVED_FROM)) {
|
||||||
drop_change(node);
|
drop_change(node);
|
||||||
@@ -727,6 +728,7 @@ static int do_change(char *name, uint32_t mask)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_d("Event registered for %s, mask 0x%x", name, mask);
|
||||||
TAILQ_INSERT_HEAD(&conf_change_list, node,link);
|
TAILQ_INSERT_HEAD(&conf_change_list, node,link);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -782,6 +784,11 @@ static void conf_cb(uev_t *w, void *arg, int events)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_AUTO_RELOAD
|
||||||
|
if (conf_any_change())
|
||||||
|
service_reload_dynamic();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_watcher(uev_ctx_t *ctx, uev_t *w, char *path, uint32_t opt)
|
static int add_watcher(uev_ctx_t *ctx, uev_t *w, char *path, uint32_t opt)
|
||||||
@@ -834,6 +841,7 @@ static int add_watcher(uev_ctx_t *ctx, uev_t *w, char *path, uint32_t opt)
|
|||||||
close(fd);
|
close(fd);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
_d("Set up inotify watcher for %s ...", path);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -856,8 +864,9 @@ int conf_monitor(uev_ctx_t *ctx)
|
|||||||
* changes to either symlink or target.
|
* changes to either symlink or target.
|
||||||
*/
|
*/
|
||||||
rc += add_watcher(ctx, &w1, FINIT_RCSD, 0);
|
rc += add_watcher(ctx, &w1, FINIT_RCSD, 0);
|
||||||
rc += add_watcher(ctx, &w2, FINIT_RCSD "/available", IN_DONT_FOLLOW);
|
rc += add_watcher(ctx, &w2, FINIT_RCSD "/available/", IN_DONT_FOLLOW);
|
||||||
rc += add_watcher(ctx, &w3, FINIT_CONF, 0);
|
rc += add_watcher(ctx, &w3, FINIT_RCSD "/enabled/", 0);
|
||||||
|
rc += add_watcher(ctx, &w4, FINIT_CONF, 0);
|
||||||
|
|
||||||
return rc + conf_reload();
|
return rc + conf_reload();
|
||||||
}
|
}
|
||||||
@@ -868,7 +877,7 @@ int conf_monitor(uev_ctx_t *ctx)
|
|||||||
int conf_init(void)
|
int conf_init(void)
|
||||||
{
|
{
|
||||||
hostname = strdup(DEFHOST);
|
hostname = strdup(DEFHOST);
|
||||||
w1.fd = w2.fd = w3.fd = -1;
|
w1.fd = w2.fd = w3.fd = w4.fd = -1;
|
||||||
|
|
||||||
return conf_monitor(NULL);
|
return conf_monitor(NULL);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -231,6 +231,7 @@ int exec_runtask(char *cmd, char *args[])
|
|||||||
strlcat(buf, args[i], sizeof(buf));
|
strlcat(buf, args[i], sizeof(buf));
|
||||||
}
|
}
|
||||||
logit(LOG_DEBUG, "Calling %s %s", _PATH_BSHELL, buf);
|
logit(LOG_DEBUG, "Calling %s %s", _PATH_BSHELL, buf);
|
||||||
|
_d("Calling %s %s", _PATH_BSHELL, buf);
|
||||||
|
|
||||||
return execvp(_PATH_BSHELL, argv);
|
return execvp(_PATH_BSHELL, argv);
|
||||||
}
|
}
|
||||||
@@ -239,6 +240,7 @@ static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit
|
|||||||
{
|
{
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
struct termios term;
|
struct termios term;
|
||||||
|
char name[80];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reset to sane defaults in case of messup from prev. session
|
* Reset to sane defaults in case of messup from prev. session
|
||||||
@@ -282,13 +284,16 @@ static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit
|
|||||||
|
|
||||||
/* Finit is responsible for the UTMP INIT_PROCESS record */
|
/* Finit is responsible for the UTMP INIT_PROCESS record */
|
||||||
utmp_set_init(tty, 0);
|
utmp_set_init(tty, 0);
|
||||||
prctl(PR_SET_NAME, procname, 0, 0, 0);
|
if (!strncmp("/dev/", tty, 5))
|
||||||
|
tty += 5;
|
||||||
|
snprintf(name, sizeof(name), "%s %s", procname, tty);
|
||||||
|
prctl(PR_SET_NAME, name, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int activate_console(int noclear, int nowait)
|
static int activate_console(int noclear, int nowait)
|
||||||
{
|
{
|
||||||
|
struct termios orig;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct termios term;
|
|
||||||
|
|
||||||
if (!noclear)
|
if (!noclear)
|
||||||
(void)write(STDERR_FILENO, "\e[r\e[H\e[J", 9);
|
(void)write(STDERR_FILENO, "\e[r\e[H\e[J", 9);
|
||||||
@@ -297,15 +302,20 @@ static int activate_console(int noclear, int nowait)
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* Disable ECHO, XON/OFF while waiting for <CR> */
|
/* Disable ECHO, XON/OFF while waiting for <CR> */
|
||||||
if (!tcgetattr(STDIN_FILENO, &term)) {
|
if (!tcgetattr(STDIN_FILENO, &orig)) {
|
||||||
term.c_iflag &= ~(IXON|IXOFF);
|
struct termios c = orig;
|
||||||
term.c_lflag &= ~ECHO;
|
|
||||||
tcsetattr(STDIN_FILENO, TCSANOW, &term);
|
c.c_iflag &= ~(BRKINT|ICRNL|INPCK|ISTRIP|IXON|IXOFF);
|
||||||
|
c.c_oflag &= ~(OPOST);
|
||||||
|
c.c_cflag |= (CS8);
|
||||||
|
c.c_lflag &= ~(ECHO|ICANON|IEXTEN|ISIG);
|
||||||
|
tcsetattr(STDIN_FILENO, TCSANOW, &c);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!fexist(SYNC_SHUTDOWN)) {
|
while (!fexist(SYNC_SHUTDOWN)) {
|
||||||
char c;
|
char c;
|
||||||
static const char clr[] = "\r\e[2K";
|
static const char clr[] = "\r\e[2K";
|
||||||
|
static const char cup[] = "\e[A";
|
||||||
static const char msg[] = "\nPlease press Enter to activate this console.";
|
static const char msg[] = "\nPlease press Enter to activate this console.";
|
||||||
|
|
||||||
if (fexist(SYNC_STOPPED)) {
|
if (fexist(SYNC_STOPPED)) {
|
||||||
@@ -315,23 +325,21 @@ static int activate_console(int noclear, int nowait)
|
|||||||
|
|
||||||
(void)write(STDERR_FILENO, clr, strlen(clr));
|
(void)write(STDERR_FILENO, clr, strlen(clr));
|
||||||
(void)write(STDERR_FILENO, msg, strlen(msg));
|
(void)write(STDERR_FILENO, msg, strlen(msg));
|
||||||
while (read(STDIN_FILENO, &c, 1) == 1 && c != '\n')
|
while (read(STDIN_FILENO, &c, 1) == 1 && c != '\r')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (fexist(SYNC_STOPPED))
|
if (fexist(SYNC_STOPPED))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
(void)write(STDERR_FILENO, clr, strlen(clr));
|
(void)write(STDERR_FILENO, clr, strlen(clr));
|
||||||
|
(void)write(STDERR_FILENO, cup, strlen(cup));
|
||||||
ret = 1;
|
ret = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Restore ECHO, XON/OFF */
|
/* Restore TTY */
|
||||||
if (!tcgetattr(STDIN_FILENO, &term)) {
|
if (tcsetattr(STDIN_FILENO, TCSANOW, &orig) == -1)
|
||||||
term.c_iflag |= IXON|IXOFF;
|
ret = 0;
|
||||||
term.c_lflag |= ECHO;
|
|
||||||
tcsetattr(STDIN_FILENO, TCSANOW, &term);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -361,15 +369,12 @@ pid_t run_getty(char *tty, char *baud, char *term, int noclear, int nowait, stru
|
|||||||
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
speed_t speed = B38400;
|
speed_t speed;
|
||||||
|
|
||||||
if (baud) {
|
speed = stty_parse_speed(baud);
|
||||||
speed = stty_parse_speed(baud);
|
logit(LOG_INFO, "Starting built-in getty on %s, speed %u", tty, speed);
|
||||||
if (B0 == speed)
|
prepare_tty(tty, speed, "tty", rlimit);
|
||||||
logit(LOG_CRIT, "TTY %s: Invalid speed %s", tty, baud);
|
|
||||||
}
|
|
||||||
|
|
||||||
prepare_tty(tty, speed, "finit-getty", rlimit);
|
|
||||||
if (activate_console(noclear, nowait))
|
if (activate_console(noclear, nowait))
|
||||||
_exit(getty(tty, speed, term, NULL));
|
_exit(getty(tty, speed, term, NULL));
|
||||||
}
|
}
|
||||||
@@ -407,6 +412,7 @@ pid_t run_getty2(char *tty, char *cmd, char *args[], int noclear, int nowait, st
|
|||||||
dup2(fd, STDERR_FILENO);
|
dup2(fd, STDERR_FILENO);
|
||||||
|
|
||||||
/* Dunno speed, tell stty() to not mess with it */
|
/* Dunno speed, tell stty() to not mess with it */
|
||||||
|
logit(LOG_INFO, "Starting external getty on %s, speed %u", tty, B0);
|
||||||
prepare_tty(tty, B0, "getty", rlimit);
|
prepare_tty(tty, B0, "getty", rlimit);
|
||||||
|
|
||||||
if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0)
|
if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0)
|
||||||
@@ -449,12 +455,16 @@ int run_parts(char *dir, char *cmd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < num; i++) {
|
for (i = 0; i < num; i++) {
|
||||||
int j = 0;
|
|
||||||
pid_t pid = 0;
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
char *args[NUM_ARGS];
|
char path[512];
|
||||||
|
char *argv[4] = {
|
||||||
|
"sh",
|
||||||
|
"-c",
|
||||||
|
path,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
char *name = e[i]->d_name;
|
char *name = e[i]->d_name;
|
||||||
char path[LINE_SIZE];
|
pid_t pid = 0;
|
||||||
|
|
||||||
snprintf(path, sizeof(path), "%s/%s", dir, name);
|
snprintf(path, sizeof(path), "%s/%s", dir, name);
|
||||||
if (stat(path, &st)) {
|
if (stat(path, &st)) {
|
||||||
@@ -467,29 +477,22 @@ int run_parts(char *dir, char *cmd)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill in args[], starting with full path to executable */
|
|
||||||
args[j++] = path;
|
|
||||||
|
|
||||||
/* If the callee didn't supply a run_parts() argument */
|
/* If the callee didn't supply a run_parts() argument */
|
||||||
if (!cmd) {
|
if (!cmd) {
|
||||||
/* Check if S<NUM>service or K<NUM>service notation is used */
|
/* Check if S<NUM>service or K<NUM>service notation is used */
|
||||||
_d("Checking if %s is a sysvinit startstop script ...", name);
|
_d("Checking if %s is a sysvinit startstop script ...", name);
|
||||||
if (name[0] == 'S' && isdigit(name[1])) {
|
if (name[0] == 'S' && isdigit(name[1]))
|
||||||
args[j++] = "start";
|
strlcat(path, " start", sizeof(path));
|
||||||
} else if (name[0] == 'K' && isdigit(name[1])) {
|
else if (name[0] == 'K' && isdigit(name[1]))
|
||||||
args[j++] = "stop";
|
strlcat(path, " stop", sizeof(path));
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
args[j++] = cmd;
|
strlcat(path, cmd, sizeof(path));
|
||||||
}
|
}
|
||||||
args[j++] = NULL;
|
|
||||||
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
_d("Calling %s ...", path);
|
|
||||||
sig_unblock();
|
sig_unblock();
|
||||||
execv(path, args);
|
return execvp(_PATH_BSHELL, argv);
|
||||||
exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
complete(path, pid);
|
complete(path, pid);
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
#include <lite/lite.h>
|
#include <lite/lite.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
|
#include "cgroup.h"
|
||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
@@ -47,9 +48,8 @@
|
|||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "utmp-api.h"
|
#include "utmp-api.h"
|
||||||
#include "watchdog.h"
|
#include "schedule.h"
|
||||||
|
|
||||||
int wdogpid = 0; /* No watchdog by default */
|
|
||||||
int runlevel = 0; /* Bootstrap 'S' */
|
int runlevel = 0; /* Bootstrap 'S' */
|
||||||
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
|
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
|
||||||
int prevlevel = -1;
|
int prevlevel = -1;
|
||||||
@@ -63,15 +63,16 @@ char *rcsd = FINIT_RCSD;
|
|||||||
char *runparts = NULL;
|
char *runparts = NULL;
|
||||||
|
|
||||||
uev_ctx_t *ctx = NULL; /* Main loop context */
|
uev_ctx_t *ctx = NULL; /* Main loop context */
|
||||||
|
svc_t *wdog = NULL; /* No watchdog by default */
|
||||||
|
|
||||||
|
static int udev = 0; /* Runtime detection of udev */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Show user configured banner before service bootstrap progress
|
* Show user configured banner before service bootstrap progress
|
||||||
*/
|
*/
|
||||||
static void banner(void)
|
static void banner(void)
|
||||||
{
|
{
|
||||||
char *buf = INIT_HEADING;
|
|
||||||
char separator[SCREEN_WIDTH];
|
|
||||||
|
|
||||||
if (plugin_exists(HOOK_BANNER)) {
|
if (plugin_exists(HOOK_BANNER)) {
|
||||||
plugin_run_hooks(HOOK_BANNER);
|
plugin_run_hooks(HOOK_BANNER);
|
||||||
return;
|
return;
|
||||||
@@ -80,8 +81,7 @@ static void banner(void)
|
|||||||
if (log_is_silent())
|
if (log_is_silent())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
memset(separator, '=', sizeof(separator));
|
print_banner(INIT_HEADING);
|
||||||
fprintf(stderr, "\e[2K\e[1m%s %.*s\e[0m\n", buf, SCREEN_WIDTH - (int)strlen(buf) - 2, separator);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ismnt(char *file, char *dir)
|
static int ismnt(char *file, char *dir)
|
||||||
@@ -214,15 +214,20 @@ static void emergency_shell(void)
|
|||||||
*/
|
*/
|
||||||
static void finalize(void)
|
static void finalize(void)
|
||||||
{
|
{
|
||||||
|
svc_t *svc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Track bundled watchdogd in case a better one turns up
|
||||||
|
*/
|
||||||
|
svc = svc_find(FINIT_LIBPATH_ "/watchdogd", "1");
|
||||||
|
if (svc)
|
||||||
|
wdog = svc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Run startup scripts in the runparts directory, if any.
|
* Run startup scripts in the runparts directory, if any.
|
||||||
*/
|
*/
|
||||||
if (runparts && fisdir(runparts) && !rescue) {
|
if (runparts && fisdir(runparts) && !rescue)
|
||||||
_d("Running startup scripts in %s ...", runparts);
|
|
||||||
run_parts(runparts, NULL);
|
run_parts(runparts, NULL);
|
||||||
if (conf_any_change())
|
|
||||||
service_reload_dynamic();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Start all tasks/services in the configured runlevel
|
* Start all tasks/services in the configured runlevel
|
||||||
@@ -240,11 +245,8 @@ static void finalize(void)
|
|||||||
service_step_all(SVC_TYPE_ANY);
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
|
||||||
/* Convenient SysV compat for when you just don't care ... */
|
/* Convenient SysV compat for when you just don't care ... */
|
||||||
if (!access(FINIT_RC_LOCAL, X_OK) && !rescue) {
|
if (!access(FINIT_RC_LOCAL, X_OK) && !rescue)
|
||||||
run_interactive(FINIT_RC_LOCAL, "Calling %s", FINIT_RC_LOCAL);
|
run_interactive(FINIT_RC_LOCAL, "Calling %s", FINIT_RC_LOCAL);
|
||||||
if (conf_any_change())
|
|
||||||
service_reload_dynamic();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hooks that should run at the very end */
|
/* Hooks that should run at the very end */
|
||||||
_d("Calling all system up hooks ...");
|
_d("Calling all system up hooks ...");
|
||||||
@@ -260,13 +262,61 @@ static void finalize(void)
|
|||||||
tty_runlevel();
|
tty_runlevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
/*
|
||||||
|
* Start cranking the big state machine
|
||||||
|
*/
|
||||||
|
static void crank_worker(void *unused)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* Initalize state machine and start all bootstrap tasks
|
||||||
|
* NOTE: no network available!
|
||||||
|
*/
|
||||||
|
sm_init(&sm);
|
||||||
|
sm_step(&sm);
|
||||||
|
|
||||||
|
/* Debian has this little script to copy generated rules while the system was read-only */
|
||||||
|
if (udev && fexist("/lib/udev/udev-finish"))
|
||||||
|
run_interactive("/lib/udev/udev-finish", "Finalizing udev");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wait for system bootstrap to complete, all SVC_TYPE_RUNTASK must be
|
||||||
|
* allowed to complete their work in [S], or timeout, before we call
|
||||||
|
* finalize(), should not take more than 120 sec.
|
||||||
|
*/
|
||||||
|
static void final_worker(void *work)
|
||||||
|
{
|
||||||
|
static int cnt = 120;
|
||||||
|
|
||||||
|
_d("Step all services ...");
|
||||||
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
|
||||||
|
if (cnt-- > 0 && !service_completed()) {
|
||||||
|
_d("Not all bootstrap run/tasks have completed yet ... %d", cnt);
|
||||||
|
schedule_work(work);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cnt > 0)
|
||||||
|
_d("All run/task have completed, resuming bootstrap.");
|
||||||
|
else
|
||||||
|
_d("Timeout, resuming bootstrap.");
|
||||||
|
|
||||||
|
finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct wq crank = {
|
||||||
|
.cb = crank_worker
|
||||||
|
};
|
||||||
|
struct wq final = {
|
||||||
|
.cb = final_worker,
|
||||||
|
.delay = 1000
|
||||||
|
};
|
||||||
|
uev_ctx_t loop;
|
||||||
char *path;
|
char *path;
|
||||||
char cmd[256];
|
char cmd[256];
|
||||||
int udev = 0;
|
|
||||||
uev_t timer; /* Bootstrap timer, on timeout call finalize() */
|
|
||||||
uev_ctx_t loop;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* finit/init/telinit client tool uses /dev/initctl pipe
|
* finit/init/telinit client tool uses /dev/initctl pipe
|
||||||
@@ -275,27 +325,48 @@ int main(int argc, char* argv[])
|
|||||||
if (getpid() != 1)
|
if (getpid() != 1)
|
||||||
return client(argc, argv);
|
return client(argc, argv);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hide command line arguments from ps (in particular for
|
||||||
|
* forked children that don't execv()). This is an ugly
|
||||||
|
* hack that only works on Linux.
|
||||||
|
* https://web.archive.org/web/20110227041321/http://netsplit.com/2007/01/10/hiding-arguments-from-ps/
|
||||||
|
*/
|
||||||
|
if (argc > 1) {
|
||||||
|
char *arg_end;
|
||||||
|
|
||||||
|
arg_end = argv[argc-1] + strlen (argv[argc-1]);
|
||||||
|
*arg_end = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initalize event context.
|
* Initalize event context.
|
||||||
*/
|
*/
|
||||||
uev_init(&loop);
|
uev_init1(&loop, 1);
|
||||||
ctx = &loop;
|
ctx = &loop;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the PATH early to something sane
|
* Set PATH and SHELL early to something sane
|
||||||
*/
|
*/
|
||||||
setenv("PATH", _PATH_STDPATH, 1);
|
setenv("PATH", _PATH_STDPATH, 1);
|
||||||
|
setenv("SHELL", _PATH_BSHELL, 1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mount base file system, kernel is assumed to run devtmpfs for /dev
|
* Mount base file system, kernel is assumed to run devtmpfs for /dev
|
||||||
*/
|
*/
|
||||||
chdir("/");
|
chdir("/");
|
||||||
umask(0);
|
umask(0);
|
||||||
mount("none", "/proc", "proc", 0, NULL);
|
if (mount("none", "/proc", "proc", 0, NULL))
|
||||||
mount("none", "/sys", "sysfs", 0, NULL);
|
_pe("Failed mounting /proc");
|
||||||
|
if (mount("none", "/sys", "sysfs", 0, NULL))
|
||||||
|
_pe("Failed mounting /sysfs");
|
||||||
if (fisdir("/proc/bus/usb"))
|
if (fisdir("/proc/bus/usb"))
|
||||||
mount("none", "/proc/bus/usb", "usbfs", 0, NULL);
|
mount("none", "/proc/bus/usb", "usbfs", 0, NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize default control groups, if available
|
||||||
|
*/
|
||||||
|
cgroup_init();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse kernel command line (debug, rescue, splash, etc.)
|
* Parse kernel command line (debug, rescue, splash, etc.)
|
||||||
* Also calls log_init() to set correct log level
|
* Also calls log_init() to set correct log level
|
||||||
@@ -350,9 +421,9 @@ int main(int argc, char* argv[])
|
|||||||
else if (whichp("udevadm"))
|
else if (whichp("udevadm"))
|
||||||
run_interactive("udevadm info --cleanup-db", "Cleaning up udev db");
|
run_interactive("udevadm info --cleanup-db", "Cleaning up udev db");
|
||||||
|
|
||||||
/* Some systems use /dev/pts */
|
/* Modern systems use /dev/pts */
|
||||||
makedir("/dev/pts", 0755);
|
makedir("/dev/pts", 0755);
|
||||||
mount("devpts", "/dev/pts", "devpts", 0, "gid=5,mode=620");
|
mount("devpts", "/dev/pts", "devpts", 0, "gid=5,mode=620,ptmxmode=0666");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some systems rely on us to both create /dev/shm and, to mount
|
* Some systems rely on us to both create /dev/shm and, to mount
|
||||||
@@ -362,84 +433,99 @@ int main(int argc, char* argv[])
|
|||||||
*/
|
*/
|
||||||
makedir("/dev/shm", 0755);
|
makedir("/dev/shm", 0755);
|
||||||
if (!fismnt("/dev/shm") && !ismnt("/etc/fstab", "/dev/shm"))
|
if (!fismnt("/dev/shm") && !ismnt("/etc/fstab", "/dev/shm"))
|
||||||
mount("shm", "/dev/shm", "tmpfs", 0, NULL);
|
mount("shm", "/dev/shm", "tmpfs", 0, "mode=0777");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* New tmpfs based /run for volatile runtime data
|
* New tmpfs based /run for volatile runtime data
|
||||||
* For details, see http://lwn.net/Articles/436012/
|
* For details, see http://lwn.net/Articles/436012/
|
||||||
*/
|
*/
|
||||||
if (fisdir("/run") && !fismnt("/run"))
|
if (fisdir("/run") && !fismnt("/run"))
|
||||||
mount("tmpfs", "/run", "tmpfs", MS_NODEV, "mode=0755,size=10%");
|
mount("tmpfs", "/run", "tmpfs", MS_NODEV | MS_NOSUID | MS_NOEXEC, "mode=0755,size=10%");
|
||||||
umask(022);
|
umask(022);
|
||||||
|
|
||||||
|
/* Bootstrap conditions, needed for hooks */
|
||||||
|
cond_init();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Populate /dev and prepare for runtime events from kernel.
|
* Populate /dev and prepare for runtime events from kernel.
|
||||||
|
* Prefer udev if mdev is also available on the system.
|
||||||
*/
|
*/
|
||||||
path = which("mdev");
|
path = which("udevd");
|
||||||
|
if (!path)
|
||||||
|
path = which("/lib/systemd/systemd-udevd");
|
||||||
if (path) {
|
if (path) {
|
||||||
/* Embedded Linux systems usually have BusyBox mdev */
|
|
||||||
if (log_is_debug())
|
|
||||||
touch("/dev/mdev.log");
|
|
||||||
|
|
||||||
snprintf(cmd, sizeof(cmd), "%s -s", path);
|
|
||||||
} else {
|
|
||||||
/* Desktop and server distros usually have a variant of udev */
|
/* Desktop and server distros usually have a variant of udev */
|
||||||
path = which("udevd");
|
udev = 1;
|
||||||
if (!path)
|
|
||||||
path = which("/lib/systemd/systemd-udevd");
|
|
||||||
if (path) {
|
|
||||||
udev = 1;
|
|
||||||
|
|
||||||
/* Register udevd as a monitored service, started much later */
|
/* Register udevd as a monitored service */
|
||||||
snprintf(cmd, sizeof(cmd), "[12345] %s -- Device event manager daemon", path);
|
snprintf(cmd, sizeof(cmd), "[S12345789] pid:udevd %s -- Device event managing daemon", path);
|
||||||
if (service_register(SVC_TYPE_SERVICE, cmd, global_rlimit, NULL)) {
|
if (service_register(SVC_TYPE_SERVICE, cmd, global_rlimit, NULL)) {
|
||||||
_pe("Failed registering %s", path);
|
_pe("Failed registering %s", path);
|
||||||
udev = 0;
|
udev = 0;
|
||||||
}
|
} else {
|
||||||
|
snprintf(cmd, sizeof(cmd), ":1 [S] <svc%s> "
|
||||||
|
"udevadm trigger -c add -t devices "
|
||||||
|
"-- Requesting device events", path);
|
||||||
|
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
||||||
|
|
||||||
/* Start a temporary udevd instance to populate /dev */
|
snprintf(cmd, sizeof(cmd), ":2 [S] <svc%s> "
|
||||||
snprintf(cmd, sizeof(cmd), "%s --daemon", path);
|
"udevadm trigger -c add -t subsystems "
|
||||||
|
"-- Requesting subsystem events", path);
|
||||||
|
service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (path) {
|
|
||||||
free(path);
|
free(path);
|
||||||
|
} else {
|
||||||
|
path = which("mdev");
|
||||||
|
if (path) {
|
||||||
|
/* Embedded Linux systems usually have BusyBox mdev */
|
||||||
|
if (log_is_debug())
|
||||||
|
touch("/dev/mdev.log");
|
||||||
|
|
||||||
run_interactive(cmd, "Populating device tree");
|
snprintf(cmd, sizeof(cmd), "%s -s", path);
|
||||||
if (udev && whichp("udevadm")) {
|
free(path);
|
||||||
run("udevadm trigger --action=add --type=subsystems");
|
|
||||||
run("udevadm trigger --action=add --type=devices");
|
|
||||||
run("udevadm settle --timeout=120");
|
|
||||||
|
|
||||||
/* Tell temporary udevd to exit, we'll start a monitored instance later */
|
run_interactive(cmd, "Populating device tree");
|
||||||
run("udevadm control --exit");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Start built-in watchdog as soon as possible, if enabled
|
* Start bundled watchdogd as soon as possible, if enabled
|
||||||
*/
|
*/
|
||||||
wdogpid = watchdog(argv[0]);
|
if (which(FINIT_LIBPATH_ "/watchdogd"))
|
||||||
|
service_register(SVC_TYPE_SERVICE, FINIT_LIBPATH_ "/watchdogd -- Finit watchdog daemon", global_rlimit, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mount filesystems
|
* Mount filesystems
|
||||||
*/
|
*/
|
||||||
if (!rescue) {
|
if (!rescue) {
|
||||||
#ifdef REMOUNT_ROOTFS
|
#ifndef SYSROOT
|
||||||
run("mount -n -o remount,rw /");
|
/*
|
||||||
#endif
|
* Remount / read-write if it exists in fstab is not 'ro'.
|
||||||
#ifdef SYSROOT
|
* This is what the Debian sysv initscripts does.
|
||||||
|
*/
|
||||||
|
if (setfsent()) {
|
||||||
|
struct fstab *fs;
|
||||||
|
|
||||||
|
while ((fs = getfsent())) {
|
||||||
|
if (strcmp(fs->fs_file, "/"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strcmp(fs->fs_type, "ro"))
|
||||||
|
run_interactive("mount -n -o remount,rw /", "Remounting / as read-write");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
endfsent();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/*
|
||||||
|
* XXX: Untested, in the initramfs age we should
|
||||||
|
* probably use switch_root instead.
|
||||||
|
*/
|
||||||
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");
|
|
||||||
|
|
||||||
/* Bootstrap conditions, needed for hooks */
|
|
||||||
cond_init();
|
|
||||||
|
|
||||||
if (!rescue) {
|
if (!rescue) {
|
||||||
_d("Root FS up, calling hooks ...");
|
_d("Root FS up, calling hooks ...");
|
||||||
plugin_run_hooks(HOOK_ROOTFS_UP);
|
plugin_run_hooks(HOOK_ROOTFS_UP);
|
||||||
@@ -469,26 +555,18 @@ int main(int argc, char* argv[])
|
|||||||
*/
|
*/
|
||||||
conf_monitor(&loop);
|
conf_monitor(&loop);
|
||||||
|
|
||||||
/*
|
_d("Starting initctl API responder ...");
|
||||||
* Initalize state machine and start all bootstrap tasks
|
|
||||||
* NOTE: no network available!
|
|
||||||
*/
|
|
||||||
sm_init(&sm);
|
|
||||||
sm_step(&sm);
|
|
||||||
|
|
||||||
/* Start new initctl API responder */
|
|
||||||
api_init(&loop);
|
api_init(&loop);
|
||||||
umask(022);
|
umask(022);
|
||||||
|
|
||||||
/*
|
_d("Starting the big state machine ...");
|
||||||
* Wait for all SVC_TYPE_RUNTASK to have completed their work in
|
schedule_work(&crank);
|
||||||
* [S], or timeout, before calling finalize()
|
|
||||||
*/
|
|
||||||
_d("Starting bootstrap finalize timer ...");
|
_d("Starting bootstrap finalize timer ...");
|
||||||
uev_timer_init(&loop, &timer, service_bootstrap_cb, finalize, 1000, 1000);
|
schedule_work(&final);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enter main loop to monior /dev/initctl and services
|
* Enter main loop to monitor /dev/initctl and services
|
||||||
*/
|
*/
|
||||||
_d("Entering main loop ...");
|
_d("Entering main loop ...");
|
||||||
return uev_run(&loop, 0);
|
return uev_run(&loop, 0);
|
||||||
|
|||||||
@@ -45,7 +45,6 @@
|
|||||||
#define _PATH_VARRUN "/var/run/"
|
#define _PATH_VARRUN "/var/run/"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define CMD_SIZE 256
|
#define CMD_SIZE 256
|
||||||
#define LINE_SIZE 1024
|
#define LINE_SIZE 1024
|
||||||
#define BUF_SIZE 4096
|
#define BUF_SIZE 4096
|
||||||
@@ -75,7 +74,7 @@
|
|||||||
#define INIT_CMD_RELOAD_SVC 12 /* SIGHUP service */
|
#define INIT_CMD_RELOAD_SVC 12 /* SIGHUP service */
|
||||||
#define INIT_CMD_RESTART_SVC 13 /* STOP + START service */
|
#define INIT_CMD_RESTART_SVC 13 /* STOP + START service */
|
||||||
#define INIT_CMD_QUERY_INETD 14
|
#define INIT_CMD_QUERY_INETD 14
|
||||||
#define INIT_CMD_EMIT 15
|
#define INIT_CMD_UNUSED1 15 /* Unused, was INIT_CMD_EMIT */
|
||||||
#define INIT_CMD_GET_RUNLEVEL 16
|
#define INIT_CMD_GET_RUNLEVEL 16
|
||||||
#define INIT_CMD_WDOG_HELLO 128 /* Watchdog register and hello */
|
#define INIT_CMD_WDOG_HELLO 128 /* Watchdog register and hello */
|
||||||
#define INIT_CMD_SVC_ITER 129
|
#define INIT_CMD_SVC_ITER 129
|
||||||
@@ -84,6 +83,7 @@
|
|||||||
#define INIT_CMD_NACK 254
|
#define INIT_CMD_NACK 254
|
||||||
#define INIT_CMD_ACK 255
|
#define INIT_CMD_ACK 255
|
||||||
|
|
||||||
|
/* Traditionally aligned on 384 bytes */
|
||||||
struct init_request {
|
struct init_request {
|
||||||
int magic; /* Magic number */
|
int magic; /* Magic number */
|
||||||
int cmd; /* What kind of request */
|
int cmd; /* What kind of request */
|
||||||
@@ -92,7 +92,6 @@ struct init_request {
|
|||||||
char data[368];
|
char data[368];
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int wdogpid;
|
|
||||||
extern int runlevel;
|
extern int runlevel;
|
||||||
extern int cfglevel;
|
extern int cfglevel;
|
||||||
extern int prevlevel;
|
extern int prevlevel;
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
|
#include "cgroup.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "sig.h"
|
#include "sig.h"
|
||||||
#include "utmp-api.h"
|
#include "utmp-api.h"
|
||||||
@@ -192,6 +193,7 @@ static int do_login(char *name)
|
|||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
|
cgroup_user(name);
|
||||||
execl(_PATH_LOGIN, _PATH_LOGIN, name, NULL);
|
execl(_PATH_LOGIN, _PATH_LOGIN, name, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -209,8 +211,9 @@ static int do_login(char *name)
|
|||||||
|
|
||||||
int getty(char *tty, speed_t speed, char *term, char *user)
|
int getty(char *tty, speed_t speed, char *term, char *user)
|
||||||
{
|
{
|
||||||
int fd;
|
const char cln[] = "\r\e[2K\n";
|
||||||
char name[30];
|
char name[30];
|
||||||
|
int fd;
|
||||||
|
|
||||||
/* Detach from initial controlling TTY */
|
/* Detach from initial controlling TTY */
|
||||||
vhangup();
|
vhangup();
|
||||||
@@ -222,10 +225,15 @@ int getty(char *tty, speed_t speed, char *term, char *user)
|
|||||||
dup2(fd, STDIN_FILENO);
|
dup2(fd, STDIN_FILENO);
|
||||||
dup2(fd, STDOUT_FILENO);
|
dup2(fd, STDOUT_FILENO);
|
||||||
dup2(fd, STDERR_FILENO);
|
dup2(fd, STDERR_FILENO);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0)
|
if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0)
|
||||||
warn("Failed TIOCSCTTY");
|
warn("Failed TIOCSCTTY");
|
||||||
|
|
||||||
|
/* Set up TTY, re-enabling ISIG et al. */
|
||||||
|
stty(STDIN_FILENO, speed);
|
||||||
|
(void)write(STDOUT_FILENO, cln, strlen(cln));
|
||||||
|
|
||||||
/* The getty process is responsible for the UTMP login record */
|
/* The getty process is responsible for the UTMP login record */
|
||||||
utmp_set_login(tty, NULL);
|
utmp_set_login(tty, NULL);
|
||||||
if (!user)
|
if (!user)
|
||||||
@@ -233,11 +241,7 @@ int getty(char *tty, speed_t speed, char *term, char *user)
|
|||||||
else
|
else
|
||||||
strlcpy(name, user, sizeof(name));
|
strlcpy(name, user, sizeof(name));
|
||||||
|
|
||||||
/* Set up TTY, re-enabling ISIG et al. */
|
if (term && term[0])
|
||||||
stty(fd, speed);
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
if (term)
|
|
||||||
setenv("TERM", term, 1);
|
setenv("TERM", term, 1);
|
||||||
|
|
||||||
return do_login(name);
|
return do_login(name);
|
||||||
|
|||||||
@@ -39,6 +39,30 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "utmp-api.h"
|
#include "utmp-api.h"
|
||||||
|
|
||||||
|
static int progress_style = PROGRESS_STYLE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: the pending status (⋯) must be last item. Also, ⋯ is not
|
||||||
|
* off-by-one, it's a multi-byte character.
|
||||||
|
*/
|
||||||
|
#define STATUS_CLASS { \
|
||||||
|
CHOOSE(" OK ", " OK ", "\e[1;32m"), /* Green */ \
|
||||||
|
CHOOSE("FAIL", "FAIL", "\e[1;31m"), /* Red */ \
|
||||||
|
CHOOSE("WARN", "WARN", "\e[1;31m"), /* Red */ \
|
||||||
|
CHOOSE(" \\/ ", " ⋯ ", "\e[1;33m"), /* Yellow */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CHOOSE(x,y,z) x
|
||||||
|
static const char *status1[] = STATUS_CLASS;
|
||||||
|
#undef CHOOSE
|
||||||
|
|
||||||
|
#define CHOOSE(x,y,z) y
|
||||||
|
static const char *status2[] = STATUS_CLASS;
|
||||||
|
#undef CHOOSE
|
||||||
|
|
||||||
|
#define CHOOSE(x,y,z) z
|
||||||
|
static const char *color[] = STATUS_CLASS;
|
||||||
|
|
||||||
|
|
||||||
char *strip_line(char *line)
|
char *strip_line(char *line)
|
||||||
{
|
{
|
||||||
@@ -57,6 +81,81 @@ char *strip_line(char *line)
|
|||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return screen length of string, not counting escape chars, and
|
||||||
|
* accounting for unicode characters as only one screen byte wide
|
||||||
|
*/
|
||||||
|
size_t slen(char *string)
|
||||||
|
{
|
||||||
|
unsigned char *buf = (unsigned char *)string;
|
||||||
|
size_t len = 0;
|
||||||
|
|
||||||
|
while (*buf) {
|
||||||
|
/* Skip ANSI escape sequences */
|
||||||
|
if (*buf == '\e') {
|
||||||
|
while (*buf && !isalpha(*buf))
|
||||||
|
buf++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Skip 3-byte unicode */
|
||||||
|
if (*buf == 0xe2) {
|
||||||
|
for (int cnt = 3; *buf && cnt >= 0; cnt--)
|
||||||
|
buf++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
len++;
|
||||||
|
buf++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ch may be an ascii or unicode character
|
||||||
|
*/
|
||||||
|
static char *pad(char *buf, size_t len, char *ch, size_t width)
|
||||||
|
{
|
||||||
|
size_t i = slen(buf);
|
||||||
|
|
||||||
|
strlcat(buf, " ", len);
|
||||||
|
|
||||||
|
width -= 8; /* Skip leading '[ STAT ]' */
|
||||||
|
while (i < width) {
|
||||||
|
strlcat(buf, ch, len);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_banner(const char *heading)
|
||||||
|
{
|
||||||
|
char buf[4 * SCREEN_WIDTH];
|
||||||
|
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
strlcat(buf, "\r\e[2K", sizeof(buf));
|
||||||
|
if (progress_style == 1) {
|
||||||
|
strlcat(buf, "\e[1m", sizeof(buf));
|
||||||
|
strlcat(buf, heading, sizeof(buf));
|
||||||
|
pad(buf, sizeof(buf), "=", SCREEN_WIDTH - 2);
|
||||||
|
} else {
|
||||||
|
size_t wmax = 80 <= SCREEN_WIDTH ? 80 : SCREEN_WIDTH;
|
||||||
|
|
||||||
|
strlcat(buf, "\e[1;31m⏺ \e[1;33m⏺ \e[1;32m⏺ \e[0m\e[1m ", sizeof(buf));
|
||||||
|
strlcat(buf, heading, sizeof(buf));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Padding with full-width '═' sign from unicode,
|
||||||
|
* we could also use '―' or something else.
|
||||||
|
*/
|
||||||
|
pad(buf, sizeof(buf), "═", wmax);
|
||||||
|
}
|
||||||
|
strlcat(buf, "\e[0m\n", sizeof(buf));
|
||||||
|
|
||||||
|
(void)write(STDERR_FILENO, buf, strlen(buf));
|
||||||
|
}
|
||||||
|
|
||||||
static size_t print_timestamp(char *buf, size_t len)
|
static size_t print_timestamp(char *buf, size_t len)
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_PRINTK_TIME)
|
#if defined(CONFIG_PRINTK_TIME)
|
||||||
@@ -77,6 +176,26 @@ static size_t print_timestamp(char *buf, size_t len)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *status(int rc)
|
||||||
|
{
|
||||||
|
static char buf[64];
|
||||||
|
|
||||||
|
if (rc < 0 || rc >= (int)NELEMS(status1))
|
||||||
|
rc = NELEMS(status1) - 1; /* Default to "⋯" (pending) */
|
||||||
|
|
||||||
|
if (progress_style == 1) {
|
||||||
|
int hl = 1;
|
||||||
|
|
||||||
|
if (rc == 1 || rc == 2)
|
||||||
|
hl = 7;
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf), "\e[%dm[%s]\e[0m", hl, status1[rc]);
|
||||||
|
} else
|
||||||
|
snprintf(buf, sizeof(buf), "\e[1m[%s%s\e[0m\e[1m]\e[0m ", color[rc], status2[rc]);
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
void printv(const char *fmt, va_list ap)
|
void printv(const char *fmt, va_list ap)
|
||||||
{
|
{
|
||||||
char buf[SCREEN_WIDTH];
|
char buf[SCREEN_WIDTH];
|
||||||
@@ -91,51 +210,32 @@ void printv(const char *fmt, va_list ap)
|
|||||||
len = print_timestamp(buf, sizeof(buf));
|
len = print_timestamp(buf, sizeof(buf));
|
||||||
vsnprintf(&buf[len], sizeof(buf) - len, fmt, ap);
|
vsnprintf(&buf[len], sizeof(buf) - len, fmt, ap);
|
||||||
|
|
||||||
len = strlen(buf);
|
if (progress_style == 1)
|
||||||
buf[len++] = ' ';
|
fprintf(stderr, "\r%s ", pad(buf, sizeof(buf), ".", sizeof(buf)));
|
||||||
for (size_t i = len; i < (sizeof(buf) - 8); i++)
|
else
|
||||||
buf[i] = '.'; /* pad with dots. */
|
fprintf(stderr, "\r\e[2K%s%s", status(3), buf);
|
||||||
|
|
||||||
fprintf(stderr, "\r%s ", buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void print(int action, const char *fmt, ...)
|
void print(int rc, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
|
||||||
const char success[] = "\e[1m[ OK ]\e[0m\n";
|
|
||||||
const char failure[] = "\e[7m[FAIL]\e[0m\n";
|
|
||||||
const char warning[] = "\e[7m[WARN]\e[0m\n";
|
|
||||||
const char pending[] = "\e[1m[ \\/ ]\e[0m\n";
|
|
||||||
|
|
||||||
if (log_is_silent())
|
if (log_is_silent())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (fmt) {
|
if (fmt) {
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
printv(fmt, ap);
|
printv(fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (action) {
|
if (rc < 0)
|
||||||
case -1:
|
return;
|
||||||
break;
|
|
||||||
|
|
||||||
case 0:
|
if (progress_style == 1)
|
||||||
write(STDERR_FILENO, success, sizeof(success));
|
fprintf(stderr, "%s\n", status(rc));
|
||||||
break;
|
else
|
||||||
|
fprintf(stderr, ".\r%s\n", status(rc));
|
||||||
case 1:
|
|
||||||
write(STDERR_FILENO, failure, sizeof(failure));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
write(STDERR_FILENO, warning, sizeof(warning));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
write(STDERR_FILENO, pending, sizeof(pending));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_desc(char *action, char *desc)
|
void print_desc(char *action, char *desc)
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ int sh (char *tty);
|
|||||||
int stty (int fd, speed_t speed);
|
int stty (int fd, speed_t speed);
|
||||||
speed_t stty_parse_speed(char *baud);
|
speed_t stty_parse_speed(char *baud);
|
||||||
|
|
||||||
|
void print_banner (const char *heading);
|
||||||
void printv (const char *fmt, va_list ap);
|
void printv (const char *fmt, va_list ap);
|
||||||
void print (int action, const char *fmt, ...);
|
void print (int action, const char *fmt, ...);
|
||||||
void print_desc (char *action, char *desc);
|
void print_desc (char *action, char *desc);
|
||||||
|
|||||||
@@ -43,12 +43,13 @@
|
|||||||
} while (0);
|
} while (0);
|
||||||
|
|
||||||
/* Peek into SOCK_DGRAM socket to figure out where an inbound packet comes from. */
|
/* Peek into SOCK_DGRAM socket to figure out where an inbound packet comes from. */
|
||||||
static int inetd_dgram_peek(int sd, char *ifname)
|
static int inetd_dgram_peek(int sd, char *ifname, size_t len)
|
||||||
{
|
{
|
||||||
char cmbuf[0x100];
|
|
||||||
struct msghdr msgh;
|
|
||||||
struct cmsghdr *cmsg;
|
struct cmsghdr *cmsg;
|
||||||
|
struct msghdr msgh;
|
||||||
|
char cmbuf[0x100];
|
||||||
|
|
||||||
|
memset(ifname, 0, len);
|
||||||
memset(&msgh, 0, sizeof(msgh));
|
memset(&msgh, 0, sizeof(msgh));
|
||||||
msgh.msg_control = cmbuf;
|
msgh.msg_control = cmbuf;
|
||||||
msgh.msg_controllen = sizeof(cmbuf);
|
msgh.msg_controllen = sizeof(cmbuf);
|
||||||
@@ -56,13 +57,15 @@ static int inetd_dgram_peek(int sd, char *ifname)
|
|||||||
if (recvmsg(sd, &msgh, MSG_PEEK) < 0)
|
if (recvmsg(sd, &msgh, MSG_PEEK) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg; cmsg = CMSG_NXTHDR(&msgh,cmsg)) {
|
for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg; cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
|
||||||
struct in_pktinfo *ipi = (struct in_pktinfo *)CMSG_DATA(cmsg);
|
struct in_pktinfo *ipi = (struct in_pktinfo *)CMSG_DATA(cmsg);
|
||||||
|
char tmp[IF_NAMESIZE + 1] = { 0 };
|
||||||
|
|
||||||
if (cmsg->cmsg_level != SOL_IP || cmsg->cmsg_type != IP_PKTINFO)
|
if (cmsg->cmsg_level != SOL_IP || cmsg->cmsg_type != IP_PKTINFO)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if_indextoname(ipi->ipi_ifindex, ifname);
|
if_indextoname(ipi->ipi_ifindex, tmp);
|
||||||
|
strlcpy(ifname, tmp, len);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -73,11 +76,11 @@ static int inetd_dgram_peek(int sd, char *ifname)
|
|||||||
/* Peek into SOCK_DGRAM socket to figure out where an inbound packet comes from. */
|
/* Peek into SOCK_DGRAM socket to figure out where an inbound packet comes from. */
|
||||||
static void inetd_dgram_drop(int sd, const char *ifname)
|
static void inetd_dgram_drop(int sd, const char *ifname)
|
||||||
{
|
{
|
||||||
char pkt_interface[17];
|
char pkt_interface[IF_NAMESIZE + 1];
|
||||||
char buf[BUFSIZ];
|
char buf[BUFSIZ];
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
inetd_dgram_peek(sd, pkt_interface);
|
inetd_dgram_peek(sd, pkt_interface, sizeof(pkt_interface));
|
||||||
if (string_compare(pkt_interface, ifname)) {
|
if (string_compare(pkt_interface, ifname)) {
|
||||||
if (recv(sd, buf, sizeof(buf), 0) < 0)
|
if (recv(sd, buf, sizeof(buf), 0) < 0)
|
||||||
break;
|
break;
|
||||||
@@ -88,12 +91,13 @@ static void inetd_dgram_drop(int sd, const 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 */
|
||||||
static int inetd_stream_peek(int sd, char *ifname)
|
static int inetd_stream_peek(int sd, char *ifname, size_t ilen)
|
||||||
{
|
{
|
||||||
struct ifaddrs *ifaddr, *ifa;
|
struct ifaddrs *ifaddr, *ifa;
|
||||||
struct sockaddr_in sin;
|
struct sockaddr_in sin;
|
||||||
socklen_t len = sizeof(sin);
|
socklen_t len = sizeof(sin);
|
||||||
|
|
||||||
|
memset(ifname, 0, ilen);
|
||||||
if (-1 == getsockname(sd, (struct sockaddr *)&sin, &len))
|
if (-1 == getsockname(sd, (struct sockaddr *)&sin, &len))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@@ -112,7 +116,7 @@ static int inetd_stream_peek(int sd, char *ifname)
|
|||||||
|
|
||||||
iin = (struct sockaddr_in *)ifa->ifa_addr;
|
iin = (struct sockaddr_in *)ifa->ifa_addr;
|
||||||
if (!memcmp(&sin.sin_addr, &iin->sin_addr, len)) {
|
if (!memcmp(&sin.sin_addr, &iin->sin_addr, len)) {
|
||||||
strncpy(ifname, ifa->ifa_name, IF_NAMESIZE);
|
strlcpy(ifname, ifa->ifa_name, ilen);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -122,11 +126,12 @@ static int inetd_stream_peek(int sd, char *ifname)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_stdin(svc_t *svc)
|
static int get_stdin(svc_t *svc, char *iifname, size_t len)
|
||||||
{
|
{
|
||||||
int stdin = svc->inetd.watcher.fd;
|
int stdin = svc->inetd.watcher.fd;
|
||||||
char ifname[IF_NAMESIZE] = "UNKNOWN";
|
char ifname[IF_NAMESIZE + 1] = "UNKNOWN";
|
||||||
|
|
||||||
|
memset(iifname, 0, len);
|
||||||
if (svc->inetd.type == SOCK_STREAM) {
|
if (svc->inetd.type == SOCK_STREAM) {
|
||||||
/* Open new client socket from server socket */
|
/* Open new client socket from server socket */
|
||||||
stdin = accept(stdin, NULL, NULL);
|
stdin = accept(stdin, NULL, NULL);
|
||||||
@@ -137,9 +142,9 @@ static int get_stdin(svc_t *svc)
|
|||||||
|
|
||||||
_d("New client socket %d accepted for inetd service %d/tcp", stdin, svc->inetd.port);
|
_d("New client socket %d accepted for inetd service %d/tcp", stdin, svc->inetd.port);
|
||||||
|
|
||||||
inetd_stream_peek(stdin, ifname);
|
inetd_stream_peek(stdin, ifname, sizeof(ifname));
|
||||||
} else { /* SOCK_DGRAM */
|
} else { /* SOCK_DGRAM */
|
||||||
inetd_dgram_peek(stdin, ifname);
|
inetd_dgram_peek(stdin, ifname, sizeof(ifname));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!inetd_is_allowed(&svc->inetd, ifname)) {
|
if (!inetd_is_allowed(&svc->inetd, ifname)) {
|
||||||
@@ -152,6 +157,9 @@ static int get_stdin(svc_t *svc)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return ingress interface */
|
||||||
|
strlcpy(iifname, ifname, len);
|
||||||
|
|
||||||
return stdin;
|
return stdin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,6 +168,8 @@ static void socket_cb(uev_t *w, void *arg, int events)
|
|||||||
{
|
{
|
||||||
svc_t *svc = (svc_t *)arg, *task;
|
svc_t *svc = (svc_t *)arg, *task;
|
||||||
const char *conn = " connection";
|
const char *conn = " connection";
|
||||||
|
char iifname[IF_NAMESIZE + 1] = "UNKNOWN";
|
||||||
|
char id[MAX_ID_LEN];
|
||||||
int stdin;
|
int stdin;
|
||||||
|
|
||||||
_d("%s: Got socket event ...", svc->cmd);
|
_d("%s: Got socket event ...", svc->cmd);
|
||||||
@@ -168,7 +178,7 @@ static void socket_cb(uev_t *w, void *arg, int events)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
stdin = get_stdin(svc);
|
stdin = get_stdin(svc, iifname, sizeof(iifname));
|
||||||
if (stdin < 0) {
|
if (stdin < 0) {
|
||||||
logit(LOG_CRIT, "%s: Unable to accept incoming connection", svc->cmd);
|
logit(LOG_CRIT, "%s: Unable to accept incoming connection", svc->cmd);
|
||||||
return;
|
return;
|
||||||
@@ -185,7 +195,8 @@ static void socket_cb(uev_t *w, void *arg, int events)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
task = svc_new(svc->cmd, svc->inetd.next_id++, SVC_TYPE_INETD_CONN);
|
snprintf(id, sizeof(id), "%d", svc->inetd.next_id++);
|
||||||
|
task = svc_new(svc->cmd, id, SVC_TYPE_INETD_CONN);
|
||||||
if (!task) {
|
if (!task) {
|
||||||
logit(LOG_CRIT, "%s: Unable to allocate service for inetd client", svc->cmd);
|
logit(LOG_CRIT, "%s: Unable to allocate service for inetd client", svc->cmd);
|
||||||
if (svc->inetd.type == SOCK_STREAM)
|
if (svc->inetd.type == SOCK_STREAM)
|
||||||
@@ -216,6 +227,8 @@ static void socket_cb(uev_t *w, void *arg, int events)
|
|||||||
memcpy(task->args, svc->args, sizeof(task->args));
|
memcpy(task->args, svc->args, sizeof(task->args));
|
||||||
strlcpy(task->desc, svc->desc, sizeof(task->desc) - strlen(conn));
|
strlcpy(task->desc, svc->desc, sizeof(task->desc) - strlen(conn));
|
||||||
strlcat(task->desc, conn, sizeof(task->desc));
|
strlcat(task->desc, conn, sizeof(task->desc));
|
||||||
|
strlcpy(task->iifname, iifname, sizeof(task->iifname));
|
||||||
|
strlcpy(task->name, svc->name, sizeof(task->name));
|
||||||
|
|
||||||
task->stdin_fd = stdin;
|
task->stdin_fd = stdin;
|
||||||
service_step(task);
|
service_step(task);
|
||||||
@@ -335,6 +348,22 @@ int inetd_start(inetd_t *inetd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void inetd_stop_children(inetd_t *inetd, int check_allowed)
|
||||||
|
{
|
||||||
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
|
svc = svc_job_iterator(&iter, 1, inetd->svc->job);
|
||||||
|
while (svc) {
|
||||||
|
if (!svc_is_inetd(svc)) {
|
||||||
|
if (!check_allowed || !inetd_is_allowed(inetd, svc->iifname)) {
|
||||||
|
svc_stop(svc);
|
||||||
|
service_step(svc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
svc = svc_job_iterator(&iter, 0, inetd->svc->job);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void inetd_stop(inetd_t *inetd)
|
void inetd_stop(inetd_t *inetd)
|
||||||
{
|
{
|
||||||
if (!inetd || !inetd->svc) {
|
if (!inetd || !inetd->svc) {
|
||||||
@@ -354,6 +383,8 @@ void inetd_stop(inetd_t *inetd)
|
|||||||
_d("Shutting down inet socket %d ...", inetd->watcher.fd);
|
_d("Shutting down inet socket %d ...", inetd->watcher.fd);
|
||||||
close(inetd->watcher.fd);
|
close(inetd->watcher.fd);
|
||||||
inetd->watcher.fd = -1;
|
inetd->watcher.fd = -1;
|
||||||
|
|
||||||
|
inetd_stop_children(inetd, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ int inetd_check_loop(struct sockaddr *sa, socklen_t len, char *name);
|
|||||||
|
|
||||||
int inetd_start (inetd_t *inetd);
|
int inetd_start (inetd_t *inetd);
|
||||||
void inetd_stop (inetd_t *inetd);
|
void inetd_stop (inetd_t *inetd);
|
||||||
|
void inetd_stop_children (inetd_t *inetd, int check_allowed);
|
||||||
|
|
||||||
int inetd_new (inetd_t *inetd, char *name, char *service, char *proto, int forking, svc_t *svc);
|
int inetd_new (inetd_t *inetd, char *name, char *service, char *proto, int forking, svc_t *svc);
|
||||||
int inetd_del (inetd_t *inetd);
|
int inetd_del (inetd_t *inetd);
|
||||||
|
|||||||
@@ -140,7 +140,6 @@ static int do_svc(int cmd, char *arg)
|
|||||||
return client_send(&rq, sizeof(rq));
|
return client_send(&rq, sizeof(rq));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_emit (char *arg) { return do_svc(INIT_CMD_EMIT, arg); }
|
|
||||||
static int do_reload (char *arg) { return do_svc(INIT_CMD_RELOAD, arg); }
|
static int do_reload (char *arg) { return do_svc(INIT_CMD_RELOAD, arg); }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -173,7 +172,7 @@ static int do_restart(char *arg) { return do_startstop(INIT_CMD_RESTART_SVC, arg
|
|||||||
|
|
||||||
static void show_cond_one(const char *_conds)
|
static void show_cond_one(const char *_conds)
|
||||||
{
|
{
|
||||||
static char conds[MAX_ARG_LEN];
|
static char conds[MAX_COND_LEN];
|
||||||
char *cond;
|
char *cond;
|
||||||
|
|
||||||
strlcpy(conds, _conds, sizeof(conds));
|
strlcpy(conds, _conds, sizeof(conds));
|
||||||
@@ -202,22 +201,6 @@ static void show_cond_one(const char *_conds)
|
|||||||
putchar('>');
|
putchar('>');
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_cond_magic(char op, char *cond)
|
|
||||||
{
|
|
||||||
char event[368]; /* sizeof(init_request.data) */
|
|
||||||
|
|
||||||
if (!cond || strlen(cond) < 1)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
event[0] = op;
|
|
||||||
strlcpy(&event[1], cond, sizeof(event) - 1);
|
|
||||||
|
|
||||||
return do_emit(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int do_cond_set (char *cond) { return do_cond_magic('+', cond); }
|
|
||||||
static int do_cond_clear(char *cond) { return do_cond_magic('-', cond); }
|
|
||||||
|
|
||||||
static int dump_one_cond(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftwbuf)
|
static int dump_one_cond(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftwbuf)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
@@ -279,8 +262,6 @@ static int do_cond(char *cmd)
|
|||||||
char *arg;
|
char *arg;
|
||||||
struct command command[] = {
|
struct command command[] = {
|
||||||
{ "show", do_cond_show },
|
{ "show", do_cond_show },
|
||||||
{ "set", do_cond_set },
|
|
||||||
{ "clear", do_cond_clear },
|
|
||||||
{ "dump", do_cond_dump },
|
{ "dump", do_cond_dump },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
@@ -435,17 +416,17 @@ static int show_status(char *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!verbose)
|
if (!verbose)
|
||||||
printheader(NULL, "# STATUS PID RUNLEVELS SERVICE DESCRIPTION", 0);
|
printheader(NULL, "# STATUS PID RUNLEVELS SERVICE DESCRIPTION", 0);
|
||||||
|
|
||||||
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
|
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
|
||||||
char jobid[10], args[512] = "", *lvls;
|
char jobid[20], args[512] = "", *lvls;
|
||||||
|
|
||||||
// if (svc_is_unique(svc))
|
if (!svc->id[0])
|
||||||
// snprintf(jobid, sizeof(jobid), "%d", svc->job);
|
snprintf(jobid, sizeof(jobid), "%d", svc->job);
|
||||||
// else
|
else
|
||||||
snprintf(jobid, sizeof(jobid), "%d:%d", svc->job, svc->id);
|
snprintf(jobid, sizeof(jobid), "%d:%s", svc->job, svc->id);
|
||||||
|
|
||||||
printf("%-9s %7s ", jobid, svc_status(svc));
|
printf("%-9s %8s ", jobid, svc_status(svc));
|
||||||
if (svc_is_inetd(svc))
|
if (svc_is_inetd(svc))
|
||||||
printf("inetd ");
|
printf("inetd ");
|
||||||
else
|
else
|
||||||
@@ -459,14 +440,7 @@ static int show_status(char *arg)
|
|||||||
|
|
||||||
if (!verbose) {
|
if (!verbose) {
|
||||||
int adj = screen_cols - 60;
|
int adj = screen_cols - 60;
|
||||||
char *name = strrchr(svc->cmd, '/');
|
printf("%-16.16s %-*.*s\n", svc->name, adj, adj, svc->desc);
|
||||||
|
|
||||||
if (!name)
|
|
||||||
name = svc->cmd;
|
|
||||||
else
|
|
||||||
name++;
|
|
||||||
|
|
||||||
printf("%-16.16s %-*.*s\n", name, adj, adj, svc->desc);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -516,12 +490,78 @@ static int show_status(char *arg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dump_cgroup(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftwbuf)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
char *group;
|
||||||
|
char path[256];
|
||||||
|
char buf[256];
|
||||||
|
int user = 0;
|
||||||
|
int num = 0;
|
||||||
|
|
||||||
|
if (tflag == FTW_F)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "%s/cgroup.procs", fpath);
|
||||||
|
fp = fopen(path, "r");
|
||||||
|
if (!fp)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (strstr(fpath, "finit/user"))
|
||||||
|
user = 1;
|
||||||
|
|
||||||
|
group = strrchr(fpath, '/');
|
||||||
|
if (!group)
|
||||||
|
goto err;
|
||||||
|
group++;
|
||||||
|
|
||||||
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
FILE *cfp;
|
||||||
|
int pid;
|
||||||
|
|
||||||
|
if (num == 0)
|
||||||
|
printf("%c :- %s/", user ? ' ' : '|', group);
|
||||||
|
num++;
|
||||||
|
|
||||||
|
pid = atoi(chomp(buf));
|
||||||
|
snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
|
||||||
|
cfp = fopen(path, "r");
|
||||||
|
if (!cfp)
|
||||||
|
continue;
|
||||||
|
fgets(buf, sizeof(buf), cfp);
|
||||||
|
fclose(cfp);
|
||||||
|
|
||||||
|
printf("\n%c :- %d %s", user ? ' ' : '|', pid, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
err:
|
||||||
|
fclose(fp);
|
||||||
|
if (num)
|
||||||
|
printf("\r%c\n", user ? ' ' : '|');
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int show_cgroup(char *arg)
|
||||||
|
{
|
||||||
|
puts("finit/");
|
||||||
|
puts("|- init/");
|
||||||
|
nftw("/sys/fs/cgroup/finit/init", dump_cgroup, 20, 0);
|
||||||
|
puts("|- system/");
|
||||||
|
nftw("/sys/fs/cgroup/finit/system", dump_cgroup, 20, 0);
|
||||||
|
puts("`- user/");
|
||||||
|
nftw("/sys/fs/cgroup/finit/user", dump_cgroup, 20, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int usage(int rc)
|
static int usage(int rc)
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Usage: %s [OPTIONS] [COMMAND]\n"
|
"Usage: %s [OPTIONS] [COMMAND]\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
|
" -b, --batch Batch mode, no screen size probing\n"
|
||||||
" -v, --verbose Verbose output\n"
|
" -v, --verbose Verbose output\n"
|
||||||
" -h, --help This help text\n"
|
" -h, --help This help text\n"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -537,8 +577,6 @@ static int usage(int rc)
|
|||||||
" reload Reload *.conf in /etc/finit.d/ (activates changes)\n"
|
" reload Reload *.conf in /etc/finit.d/ (activates changes)\n"
|
||||||
// " reload <JOB|NAME>[:ID] Reload (SIGHUP) service by job# or name\n"
|
// " reload <JOB|NAME>[:ID] Reload (SIGHUP) service by job# or name\n"
|
||||||
"\n"
|
"\n"
|
||||||
" cond set <COND> Set (assert) condition => +COND\n"
|
|
||||||
" cond clear <COND> Clear (deassert) condition => -COND\n"
|
|
||||||
" cond show Show condition status\n"
|
" cond show Show condition status\n"
|
||||||
" cond dump Dump all conditions and their status\n"
|
" cond dump Dump all conditions and their status\n"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -549,6 +587,8 @@ static int usage(int rc)
|
|||||||
" status <JOB|NAME>[:ID] Show service status, by job# or name\n"
|
" status <JOB|NAME>[:ID] Show service status, by job# or name\n"
|
||||||
" status | show Show status of services, default command\n"
|
" status | show Show status of services, default command\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
" ps List processes based on cgroups\n"
|
||||||
|
"\n"
|
||||||
" runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot\n"
|
" runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot\n"
|
||||||
" reboot Reboot system\n"
|
" reboot Reboot system\n"
|
||||||
" halt Halt system\n"
|
" halt Halt system\n"
|
||||||
@@ -567,7 +607,7 @@ static int do_help(char *arg)
|
|||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int c;
|
int interactive = 1, c;
|
||||||
char *cmd, arg[120];
|
char *cmd, arg[120];
|
||||||
struct command command[] = {
|
struct command command[] = {
|
||||||
{ "debug", toggle_debug },
|
{ "debug", toggle_debug },
|
||||||
@@ -589,6 +629,8 @@ int main(int argc, char *argv[])
|
|||||||
{ "status", show_status },
|
{ "status", show_status },
|
||||||
{ "show", show_status }, /* Convenience alias */
|
{ "show", show_status }, /* Convenience alias */
|
||||||
|
|
||||||
|
{ "ps", show_cgroup },
|
||||||
|
|
||||||
{ "runlevel", do_runlevel },
|
{ "runlevel", do_runlevel },
|
||||||
{ "reboot", do_reboot },
|
{ "reboot", do_reboot },
|
||||||
{ "halt", do_halt },
|
{ "halt", do_halt },
|
||||||
@@ -598,6 +640,7 @@ int main(int argc, char *argv[])
|
|||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
struct option long_options[] = {
|
struct option long_options[] = {
|
||||||
|
{"batch", 0, NULL, 'b'},
|
||||||
{"help", 0, NULL, 'h'},
|
{"help", 0, NULL, 'h'},
|
||||||
{"debug", 0, NULL, 'd'},
|
{"debug", 0, NULL, 'd'},
|
||||||
{"verbose", 0, NULL, 'v'},
|
{"verbose", 0, NULL, 'v'},
|
||||||
@@ -605,8 +648,12 @@ int main(int argc, char *argv[])
|
|||||||
};
|
};
|
||||||
|
|
||||||
progname(argv[0]);
|
progname(argv[0]);
|
||||||
while ((c = getopt_long(argc, argv, "h?v", long_options, NULL)) != EOF) {
|
while ((c = getopt_long(argc, argv, "bh?v", long_options, NULL)) != EOF) {
|
||||||
switch(c) {
|
switch(c) {
|
||||||
|
case 'b':
|
||||||
|
interactive = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
case '?':
|
case '?':
|
||||||
return usage(0);
|
return usage(0);
|
||||||
@@ -617,7 +664,8 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
screen_init();
|
if (interactive)
|
||||||
|
screen_init();
|
||||||
|
|
||||||
if (optind >= argc)
|
if (optind >= argc)
|
||||||
return show_status(NULL);
|
return show_status(NULL);
|
||||||
@@ -640,6 +688,19 @@ int main(int argc, char *argv[])
|
|||||||
return usage(1);
|
return usage(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void logit(int prio, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
if (prio <= LOG_ERR)
|
||||||
|
verrx(1, fmt, ap);
|
||||||
|
else
|
||||||
|
vwarnx(fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
|
|||||||
@@ -62,10 +62,8 @@ void log_init(int dbg)
|
|||||||
void log_exit(void)
|
void log_exit(void)
|
||||||
{
|
{
|
||||||
muffler();
|
muffler();
|
||||||
if (!silent) {
|
if (!silent)
|
||||||
sched_yield();
|
sched_yield();
|
||||||
fputs("\n", stderr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unless in debug mode at shutdown, Reinitialize screen,
|
* Unless in debug mode at shutdown, Reinitialize screen,
|
||||||
|
|||||||
@@ -26,6 +26,11 @@
|
|||||||
|
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
|
|
||||||
|
/* Local facility, unused in GNU but available in FreeBSD or sysklogd >= 2.0 */
|
||||||
|
#ifndef LOG_CONSOLE
|
||||||
|
#define LOG_CONSOLE (14<<3)
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Developer error and debug messages, otherwise --> use logit() <--
|
* Developer error and debug messages, otherwise --> use logit() <--
|
||||||
* ~~~~~~~~~~~
|
* ~~~~~~~~~~~
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ int pid_alive(pid_t pid)
|
|||||||
{
|
{
|
||||||
char name[24]; /* Enough for max pid_t */
|
char name[24]; /* Enough for max pid_t */
|
||||||
|
|
||||||
snprintf(name, sizeof(name), "/proc/%d", pid);
|
snprintf(name, sizeof(name), "/proc/%d/status", pid);
|
||||||
|
|
||||||
return fexist(name);
|
return fexist(name);
|
||||||
}
|
}
|
||||||
@@ -95,8 +95,8 @@ char *pid_get_name(pid_t pid, char *name, size_t len)
|
|||||||
|
|
||||||
char *pid_file(svc_t *svc)
|
char *pid_file(svc_t *svc)
|
||||||
{
|
{
|
||||||
|
static char path[256];
|
||||||
char fn[MAX_ARG_LEN];
|
char fn[MAX_ARG_LEN];
|
||||||
static char path[MAX_ARG_LEN];
|
|
||||||
|
|
||||||
if (svc->pidfile[0]) {
|
if (svc->pidfile[0]) {
|
||||||
if (svc->pidfile[0] == '!')
|
if (svc->pidfile[0] == '!')
|
||||||
@@ -109,6 +109,25 @@ char *pid_file(svc_t *svc)
|
|||||||
return pid_runpath(fn, path, sizeof(path));
|
return pid_runpath(fn, path, sizeof(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pid_t pid_file_read(const char *fn)
|
||||||
|
{
|
||||||
|
pid_t pid = 0;
|
||||||
|
FILE *fp;
|
||||||
|
char buf[42];
|
||||||
|
|
||||||
|
fp = fopen(fn, "r");
|
||||||
|
if (!fp)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
chomp(buf);
|
||||||
|
pid = atoi(buf);
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
|
||||||
int pid_file_create(svc_t *svc)
|
int pid_file_create(svc_t *svc)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|||||||
@@ -31,13 +31,25 @@ int pid_alive (pid_t pid);
|
|||||||
char *pid_get_name (pid_t pid, char *name, size_t len);
|
char *pid_get_name (pid_t pid, char *name, size_t len);
|
||||||
|
|
||||||
char *pid_file (svc_t *svc);
|
char *pid_file (svc_t *svc);
|
||||||
|
pid_t pid_file_read (const char *fn);
|
||||||
int pid_file_create (svc_t *svc);
|
int pid_file_create (svc_t *svc);
|
||||||
int pid_file_parse (svc_t *svc, char *arg);
|
int pid_file_parse (svc_t *svc, char *arg);
|
||||||
|
|
||||||
static inline char *pid_runpath(char *file, char *path, size_t len)
|
/**
|
||||||
|
* pid_runpath - Adjust /var/run --> /run path depending on system
|
||||||
|
* @file: Path to file in /run/path or /var/run/path
|
||||||
|
* @path: Pointer to buffer to write correct path
|
||||||
|
* @len: Length, in bytes, of @path buffer
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* Always returns a valid pointer, which can be either @path with a /run
|
||||||
|
* or /var/run prefix to @file, or it may be @file if the prefix is OK.
|
||||||
|
*/
|
||||||
|
static inline char *pid_runpath(const char *file, char *path, size_t len)
|
||||||
{
|
{
|
||||||
static int unknown = 1;
|
|
||||||
static char *prefix = "/var/run";
|
static char *prefix = "/var/run";
|
||||||
|
static int unknown = 1;
|
||||||
|
int rc;
|
||||||
|
|
||||||
if (unknown) {
|
if (unknown) {
|
||||||
if (fisdir("/run"))
|
if (fisdir("/run"))
|
||||||
@@ -50,7 +62,9 @@ static inline char *pid_runpath(char *file, char *path, size_t len)
|
|||||||
else if (!strncmp(file, "/run/", 5))
|
else if (!strncmp(file, "/run/", 5))
|
||||||
file += 5;
|
file += 5;
|
||||||
|
|
||||||
snprintf(path, len, "%s/%s", prefix, file);
|
rc = snprintf(path, len, "%s/%s", prefix, file);
|
||||||
|
if (rc < 0 || (size_t)rc >= len)
|
||||||
|
_e("File path '%s' truncated, should end with '%s'", path, file);
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -189,19 +189,11 @@ int plugin_exists(hook_point_t no)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Some hooks are called with a fixed argument, like HOOK_SVC_LOST */
|
/* Some hooks are called with a fixed argument */
|
||||||
void plugin_run_hook(hook_point_t no, void *arg)
|
void plugin_run_hook(hook_point_t no, void *arg)
|
||||||
{
|
{
|
||||||
static int last = -1;
|
|
||||||
plugin_t *p, *tmp;
|
plugin_t *p, *tmp;
|
||||||
|
|
||||||
/*
|
|
||||||
* End recursion: any plugin hook => start service => SVC start
|
|
||||||
* hook => start service ... err ... wait a second
|
|
||||||
*/
|
|
||||||
if (HOOK_SVC_START == last)
|
|
||||||
return;
|
|
||||||
|
|
||||||
PLUGIN_ITERATOR(p, tmp) {
|
PLUGIN_ITERATOR(p, tmp) {
|
||||||
if (p->hook[no].cb) {
|
if (p->hook[no].cb) {
|
||||||
_d("Calling %s hook n:o %d (arg: %p) ...", basename(p->name), no, arg);
|
_d("Calling %s hook n:o %d (arg: %p) ...", basename(p->name), no, arg);
|
||||||
@@ -209,15 +201,8 @@ void plugin_run_hook(hook_point_t no, void *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Guard against infinite recursion */
|
|
||||||
if (HOOK_SVC_START == no)
|
|
||||||
last = no;
|
|
||||||
|
|
||||||
cond_set_oneshot(hook_cond[no]);
|
cond_set_oneshot(hook_cond[no]);
|
||||||
service_step_all(SVC_TYPE_RUNTASK);
|
service_step_all(SVC_TYPE_RUNTASK);
|
||||||
|
|
||||||
if (HOOK_SVC_START == no)
|
|
||||||
last = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Regular hooks are called with the registered plugin's argument */
|
/* Regular hooks are called with the registered plugin's argument */
|
||||||
|
|||||||
@@ -56,8 +56,6 @@
|
|||||||
* according to the following scheme:
|
* according to the following scheme:
|
||||||
*
|
*
|
||||||
* - HOOK_SVC_RECONF :: action/svc/reconf
|
* - HOOK_SVC_RECONF :: action/svc/reconf
|
||||||
* - HOOK_SVC_LOST :: action/svc/lost
|
|
||||||
* - HOOK_SVC_START :: action/svc/start
|
|
||||||
* - HOOK_RUNLEVEL_CHANGE :: action/sys/runlevel
|
* - HOOK_RUNLEVEL_CHANGE :: action/sys/runlevel
|
||||||
*
|
*
|
||||||
* However, the implementation did not turn out to be stable enough for
|
* However, the implementation did not turn out to be stable enough for
|
||||||
@@ -76,8 +74,6 @@
|
|||||||
\
|
\
|
||||||
/* Runtime hooks, runlevel [S1-9] */ \
|
/* Runtime hooks, runlevel [S1-9] */ \
|
||||||
CHOOSE(HOOK_SVC_RECONF, "nop"), \
|
CHOOSE(HOOK_SVC_RECONF, "nop"), \
|
||||||
CHOOSE(HOOK_SVC_LOST, "nop"), \
|
|
||||||
CHOOSE(HOOK_SVC_START, "nop"), \
|
|
||||||
CHOOSE(HOOK_RUNLEVEL_CHANGE, "nop"), \
|
CHOOSE(HOOK_RUNLEVEL_CHANGE, "nop"), \
|
||||||
\
|
\
|
||||||
/* Shutdown hooks, runlevel [06] */ \
|
/* Shutdown hooks, runlevel [06] */ \
|
||||||
|
|||||||
@@ -28,17 +28,12 @@
|
|||||||
#include "svc.h"
|
#include "svc.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
|
||||||
/*
|
|
||||||
* Main loop context
|
|
||||||
*/
|
|
||||||
uev_ctx_t *ctx;
|
|
||||||
|
|
||||||
int api_init (uev_ctx_t *ctx);
|
int api_init (uev_ctx_t *ctx);
|
||||||
int api_exit (void);
|
int api_exit (void);
|
||||||
|
|
||||||
int client (int argc, char *argv[]);
|
int client (int argc, char *argv[]);
|
||||||
|
|
||||||
void service_monitor (pid_t lost);
|
void service_monitor (pid_t lost, int status);
|
||||||
|
|
||||||
const char *plugin_hook_str(hook_point_t no);
|
const char *plugin_hook_str(hook_point_t no);
|
||||||
int plugin_exists (hook_point_t no);
|
int plugin_exists (hook_point_t no);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* Example HOOK_SVC_LOST plugin, very noisy do not use as-is!
|
/* Work queue helper functions
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016 Joachim Nilsson <troglobit@gmail.com>
|
* Copyright (c) 2018 Joachim Nilsson <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -21,35 +21,44 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "svc.h"
|
#include "schedule.h"
|
||||||
#include "plugin.h"
|
|
||||||
|
|
||||||
static void lost_pid(void *arg)
|
#define SC_INIT 0x494E4954 /* "INIT", see ascii(7) */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* libuEv callback wrapper
|
||||||
|
*/
|
||||||
|
static void cb(uev_t *w, void *arg, int events)
|
||||||
{
|
{
|
||||||
pid_t pid = (uintptr_t)arg;
|
struct wq *work = (struct wq *)arg;
|
||||||
svc_t *svc;
|
|
||||||
|
|
||||||
svc = svc_find_by_pid(pid);
|
if (UEV_ERROR == events) {
|
||||||
if (!svc)
|
uev_timer_start(w);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
logit(LOG_INFO, "Lost PID %u, svc %s", pid, svc->cmd);
|
work->cb(work);
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
/*
|
||||||
.name = __FILE__,
|
* Place work on event queue
|
||||||
.hook[HOOK_SVC_LOST] = { .cb = lost_pid },
|
*/
|
||||||
};
|
int schedule_work(struct wq *work)
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
|
||||||
{
|
{
|
||||||
plugin_register(&plugin);
|
int msec;
|
||||||
}
|
|
||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
if (!work)
|
||||||
{
|
return errno = EINVAL;
|
||||||
plugin_unregister(&plugin);
|
|
||||||
|
msec = work->delay;
|
||||||
|
if (work->init != SC_INIT) {
|
||||||
|
work->init = SC_INIT;
|
||||||
|
return uev_timer_init(ctx, &work->watcher, cb, work, msec, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return uev_timer_set(&work->watcher, msec, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/* Save and restore RTC using hwclock
|
/* Work queue helper functions
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com>
|
* Copyright (c) 2018 Joachim Nilsson <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -21,49 +21,17 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <lite/lite.h>
|
#ifndef FINIT_SCHEDULE_H_
|
||||||
|
#define FINIT_SCHEDULE_H_
|
||||||
|
|
||||||
#include "finit.h"
|
struct wq {
|
||||||
#include "helpers.h"
|
uev_t watcher;
|
||||||
#include "plugin.h"
|
int init;
|
||||||
|
int delay; /* msec delay before starting work */
|
||||||
static void save(void *arg)
|
void (*cb)(void *);
|
||||||
{
|
void *arg;
|
||||||
_d("Saving system clock to RTC ...");
|
|
||||||
/* -w,--systohc, -u,--utc */
|
|
||||||
run_interactive("hwclock -w -u", "Saving system time (UTC) to RTC");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void restore(void *arg)
|
|
||||||
{
|
|
||||||
_d("Restoring system clock from RTC ...");
|
|
||||||
/* -s,--hctosys, -u,--utc */
|
|
||||||
run_interactive("hwclock -s -u", "Restoring system clock (UTC) from RTC");
|
|
||||||
}
|
|
||||||
|
|
||||||
static plugin_t plugin = {
|
|
||||||
.name = __FILE__,
|
|
||||||
.hook[HOOK_BASEFS_UP] = {
|
|
||||||
.cb = restore
|
|
||||||
},
|
|
||||||
.hook[HOOK_SHUTDOWN] = {
|
|
||||||
.cb = save
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
int schedule_work(struct wq *work);
|
||||||
{
|
|
||||||
plugin_register(&plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
#endif /* FINIT_SCHEDULE_H_ */
|
||||||
{
|
|
||||||
plugin_unregister(&plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Local Variables:
|
|
||||||
* indent-tabs-mode: t
|
|
||||||
* c-file-style: "linux"
|
|
||||||
* End:
|
|
||||||
*/
|
|
||||||
@@ -120,7 +120,7 @@ int serv_list(char *arg)
|
|||||||
if (fisdir(enabled))
|
if (fisdir(enabled))
|
||||||
do_list("ENABLED ", enabled);
|
do_list("ENABLED ", enabled);
|
||||||
if (fisdir(FINIT_RCSD))
|
if (fisdir(FINIT_RCSD))
|
||||||
do_list("ENABLED ", FINIT_RCSD);
|
do_list("STATIC ", FINIT_RCSD);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -128,8 +128,11 @@ int serv_list(char *arg)
|
|||||||
int serv_enable(char *arg)
|
int serv_enable(char *arg)
|
||||||
{
|
{
|
||||||
char corr[40];
|
char corr[40];
|
||||||
char link[80];
|
char link[256];
|
||||||
char path[80];
|
char path[256];
|
||||||
|
|
||||||
|
if (!arg || !arg[0])
|
||||||
|
return serv_list(NULL);
|
||||||
|
|
||||||
if (!strstr(arg, ".conf")) {
|
if (!strstr(arg, ".conf")) {
|
||||||
snprintf(corr, sizeof(corr), "%s.conf", arg);
|
snprintf(corr, sizeof(corr), "%s.conf", arg);
|
||||||
@@ -137,11 +140,14 @@ int serv_enable(char *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pushd(FINIT_RCSD);
|
pushd(FINIT_RCSD);
|
||||||
snprintf(path, sizeof(path), "available/%s", arg);
|
if (mkdir("enabled", 0755) && EEXIST != errno)
|
||||||
|
err(1, "Failed creating %s/enabled directory", FINIT_RCSD);
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "%s/%s", available, arg);
|
||||||
if (!fexist(path))
|
if (!fexist(path))
|
||||||
errx(1, "Cannot find %s", path);
|
errx(1, "Cannot find %s", path);
|
||||||
|
|
||||||
snprintf(link, sizeof(link), "%s/%s", FINIT_RCSD, arg);
|
snprintf(link, sizeof(link), "%s/%s", enabled, arg);
|
||||||
if (fexist(link))
|
if (fexist(link))
|
||||||
errx(1, "%s already exists", link);
|
errx(1, "%s already exists", link);
|
||||||
|
|
||||||
@@ -151,15 +157,18 @@ int serv_enable(char *arg)
|
|||||||
int serv_disable(char *arg)
|
int serv_disable(char *arg)
|
||||||
{
|
{
|
||||||
char corr[40];
|
char corr[40];
|
||||||
char link[80];
|
char link[256];
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
|
if (!arg || !arg[0])
|
||||||
|
return serv_list(NULL);
|
||||||
|
|
||||||
if (!strstr(arg, ".conf")) {
|
if (!strstr(arg, ".conf")) {
|
||||||
snprintf(corr, sizeof(corr), "%s.conf", arg);
|
snprintf(corr, sizeof(corr), "%s.conf", arg);
|
||||||
arg = corr;
|
arg = corr;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(link, sizeof(link), "%s/%s", FINIT_RCSD, arg);
|
snprintf(link, sizeof(link), "%s/%s", enabled, arg);
|
||||||
if (stat(link, &st))
|
if (stat(link, &st))
|
||||||
err(1, "Cannot find %s", link);
|
err(1, "Cannot find %s", link);
|
||||||
|
|
||||||
@@ -173,6 +182,9 @@ int serv_touch(char *arg)
|
|||||||
{
|
{
|
||||||
char corr[40];
|
char corr[40];
|
||||||
|
|
||||||
|
if (!arg || !arg[0])
|
||||||
|
return serv_list(NULL);
|
||||||
|
|
||||||
if (!strstr(arg, ".conf")) {
|
if (!strstr(arg, ".conf")) {
|
||||||
snprintf(corr, sizeof(corr), "%s.conf", arg);
|
snprintf(corr, sizeof(corr), "%s.conf", arg);
|
||||||
arg = corr;
|
arg = corr;
|
||||||
|
|||||||
@@ -36,8 +36,9 @@ void service_reload_dynamic (void);
|
|||||||
|
|
||||||
int service_step (svc_t *svc);
|
int service_step (svc_t *svc);
|
||||||
void service_step_all (int types);
|
void service_step_all (int types);
|
||||||
|
void service_worker (void *unused);
|
||||||
|
|
||||||
void service_bootstrap_cb (uev_t *w, void *arg, int events);
|
int service_completed (void);
|
||||||
|
|
||||||
#endif /* FINIT_SERVICE_H_ */
|
#endif /* FINIT_SERVICE_H_ */
|
||||||
|
|
||||||
|
|||||||
@@ -83,6 +83,8 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "utmp-api.h"
|
#include "utmp-api.h"
|
||||||
|
|
||||||
|
extern svc_t *wdog;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Old-style SysV shutdown sends a setenv cmd INIT_HALT with "=HALT",
|
* Old-style SysV shutdown sends a setenv cmd INIT_HALT with "=HALT",
|
||||||
* "=POWERDOWN", or "" to cancel shutdown, before requesting change to
|
* "=POWERDOWN", or "" to cancel shutdown, before requesting change to
|
||||||
@@ -96,6 +98,55 @@ static uev_t sighup_watcher, sigint_watcher, sigpwr_watcher;
|
|||||||
static uev_t sigchld_watcher;
|
static uev_t sigchld_watcher;
|
||||||
static uev_t sigstop_watcher, sigtstp_watcher, sigcont_watcher;
|
static uev_t sigstop_watcher, sigtstp_watcher, sigcont_watcher;
|
||||||
|
|
||||||
|
static struct sigmap {
|
||||||
|
int num;
|
||||||
|
char *name;
|
||||||
|
} signames[] = {
|
||||||
|
/* ISO C99 signals. */
|
||||||
|
{ SIGINT, "SIGINT" },
|
||||||
|
{ SIGILL, "SIGILL" },
|
||||||
|
{ SIGABRT, "SIGABRT" },
|
||||||
|
{ SIGFPE, "SIGFPE" },
|
||||||
|
{ SIGSEGV, "SIGSEGV" },
|
||||||
|
{ SIGTERM, "SIGTERM" },
|
||||||
|
/* Historical signals specified by POSIX. */
|
||||||
|
{ SIGHUP, "SIGHUP" },
|
||||||
|
{ SIGQUIT, "SIGQUIT" },
|
||||||
|
{ SIGTRAP, "SIGTRAP" },
|
||||||
|
{ SIGKILL, "SIGKILL" },
|
||||||
|
{ SIGBUS, "SIGBUS" },
|
||||||
|
{ SIGSYS, "SIGSYS" },
|
||||||
|
{ SIGPIPE, "SIGPIPE" },
|
||||||
|
{ SIGALRM, "SIGALRM" },
|
||||||
|
|
||||||
|
/* New(er) POSIX signals (1003.1-2008, 1003.1-2013). */
|
||||||
|
{ SIGURG, "SIGURG" },
|
||||||
|
{ SIGSTOP, "SIGSTOP" },
|
||||||
|
{ SIGTSTP, "SIGTSTP" },
|
||||||
|
{ SIGCONT, "SIGCONT" },
|
||||||
|
{ SIGCHLD, "SIGCHLD" },
|
||||||
|
{ SIGTTIN, "SIGTTIN" },
|
||||||
|
{ SIGTTOU, "SIGTTOU" },
|
||||||
|
{ SIGPOLL, "SIGPOLL" },
|
||||||
|
{ SIGXCPU, "SIGXCPU" },
|
||||||
|
{ SIGXFSZ, "SIGXFSZ" },
|
||||||
|
{ SIGVTALRM, "SIGVTALRM" },
|
||||||
|
{ SIGPROF, "SIGPROF" },
|
||||||
|
{ SIGUSR1, "SIGUSR1" },
|
||||||
|
{ SIGUSR2, "SIGUSR2" },
|
||||||
|
|
||||||
|
/* Nonstandard signals found in all modern POSIX systems
|
||||||
|
(including both BSD and Linux). */
|
||||||
|
{ SIGWINCH, "SIGWINCH" },
|
||||||
|
{ SIGSTKFLT, "SIGSTKFLT" },
|
||||||
|
{ SIGPWR, "SIGPWR" },
|
||||||
|
|
||||||
|
/* Archaic names for compatibility. */
|
||||||
|
{ SIGIO, "SIGIO" },
|
||||||
|
{ SIGIOT, "SIGIOT" },
|
||||||
|
{ SIGCLD, "SIGCLD" },
|
||||||
|
};
|
||||||
|
|
||||||
void mdadm_wait(void);
|
void mdadm_wait(void);
|
||||||
void unmount_tmpfs(void);
|
void unmount_tmpfs(void);
|
||||||
void unmount_regular(void);
|
void unmount_regular(void);
|
||||||
@@ -185,8 +236,8 @@ void do_shutdown(shutop_t op)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wdogpid) {
|
if (wdog) {
|
||||||
print(kill(wdogpid, SIGPWR) == 1, "Advising watchdog, system going down");
|
print(kill(wdog->pid, SIGPWR) == 1, "Advising watchdog, system going down");
|
||||||
do_sleep(2);
|
do_sleep(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,11 +259,11 @@ void do_shutdown(shutop_t op)
|
|||||||
|
|
||||||
/* Reboot via watchdog or kernel, or shutdown? */
|
/* Reboot via watchdog or kernel, or shutdown? */
|
||||||
if (op == SHUT_REBOOT) {
|
if (op == SHUT_REBOOT) {
|
||||||
if (wdogpid) {
|
if (wdog) {
|
||||||
int timeout = 10;
|
int timeout = 10;
|
||||||
|
|
||||||
/* Wait here until the WDT reboots, or timeout with fallback */
|
/* Wait here until the WDT reboots, or timeout with fallback */
|
||||||
print(kill(wdogpid, SIGTERM) == 1, "Pending watchdog reboot");
|
print(kill(wdog->pid, SIGTERM) == 1, "Pending watchdog reboot");
|
||||||
while (timeout--)
|
while (timeout--)
|
||||||
do_sleep(1);
|
do_sleep(1);
|
||||||
}
|
}
|
||||||
@@ -314,6 +365,7 @@ static void sigterm_cb(uev_t *w, void *arg, int events)
|
|||||||
static void sigchld_cb(uev_t *w, void *arg, int events)
|
static void sigchld_cb(uev_t *w, void *arg, int events)
|
||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
int status;
|
||||||
|
|
||||||
if (UEV_ERROR == events) {
|
if (UEV_ERROR == events) {
|
||||||
_e("Unrecoverable error in signal watcher");
|
_e("Unrecoverable error in signal watcher");
|
||||||
@@ -322,10 +374,10 @@ static void sigchld_cb(uev_t *w, void *arg, int events)
|
|||||||
|
|
||||||
/* Reap all the children! */
|
/* Reap all the children! */
|
||||||
do {
|
do {
|
||||||
pid = waitpid(-1, NULL, WNOHANG);
|
pid = waitpid(-1, &status, WNOHANG);
|
||||||
if (pid > 0) {
|
if (pid > 0) {
|
||||||
_d("Collected child %d", pid);
|
_d("Collected child %d", pid);
|
||||||
service_monitor(pid);
|
service_monitor(pid, status);
|
||||||
}
|
}
|
||||||
} while (pid > 0);
|
} while (pid > 0);
|
||||||
}
|
}
|
||||||
@@ -366,6 +418,38 @@ int sig_stopped(void)
|
|||||||
return stopped;
|
return stopped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert SIGFOO to a number, if it exists
|
||||||
|
*/
|
||||||
|
int sig_num(const char *name)
|
||||||
|
{
|
||||||
|
size_t i, offset = 0;
|
||||||
|
|
||||||
|
if (strncasecmp(name, "SIG", 3))
|
||||||
|
offset = 3;
|
||||||
|
|
||||||
|
for (i = 0; i < NELEMS(signames); i++) {
|
||||||
|
if (strcasecmp(name, &signames[i].name[offset]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return signames[i].num;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *sig_name(int signo)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < NELEMS(signames); i++) {
|
||||||
|
if (signames[i].num == signo)
|
||||||
|
return signames[i].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "SIGUNKOWN";
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Inital signal setup - ignore everything but SIGCHLD until we're capable of responding
|
* Inital signal setup - ignore everything but SIGCHLD until we're capable of responding
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -70,10 +70,13 @@ extern shutop_t halt;
|
|||||||
|
|
||||||
void do_shutdown (shutop_t op);
|
void do_shutdown (shutop_t op);
|
||||||
int sig_stopped (void);
|
int sig_stopped (void);
|
||||||
|
int sig_num (const char *name);
|
||||||
void sig_init (void);
|
void sig_init (void);
|
||||||
void sig_unblock (void);
|
void sig_unblock (void);
|
||||||
void sig_setup (uev_ctx_t *ctx);
|
void sig_setup (uev_ctx_t *ctx);
|
||||||
|
|
||||||
|
const char *sig_name(int signo);
|
||||||
|
|
||||||
#endif /* FINIT_SIG_H_ */
|
#endif /* FINIT_SIG_H_ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -72,6 +72,22 @@ static char *sm_status(sm_state_t state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable login in single user mode and shutdown/reboot
|
||||||
|
*
|
||||||
|
* Re-enable only when going from these runlevels, this way a user can
|
||||||
|
* manage /etc/nologin manually within the other runlevels without us
|
||||||
|
* pulling the rug from under their feet.
|
||||||
|
*/
|
||||||
|
static void nologin(void)
|
||||||
|
{
|
||||||
|
if (runlevel == 1 || runlevel == 0 || runlevel == 6)
|
||||||
|
touch("/etc/nologin");
|
||||||
|
|
||||||
|
if (prevlevel == 1 || prevlevel == 0 || prevlevel == 6)
|
||||||
|
erase("/etc/nologin");
|
||||||
|
}
|
||||||
|
|
||||||
void sm_set_runlevel(sm_t *sm, int newlevel)
|
void sm_set_runlevel(sm_t *sm, int newlevel)
|
||||||
{
|
{
|
||||||
sm->newlevel = newlevel;
|
sm->newlevel = newlevel;
|
||||||
@@ -101,7 +117,7 @@ restart:
|
|||||||
switch (sm->state) {
|
switch (sm->state) {
|
||||||
case SM_BOOTSTRAP_STATE:
|
case SM_BOOTSTRAP_STATE:
|
||||||
_d("Bootstrapping all services in runlevel S from %s", FINIT_CONF);
|
_d("Bootstrapping all services in runlevel S from %s", FINIT_CONF);
|
||||||
service_step_all(SVC_TYPE_RUN | SVC_TYPE_TASK | SVC_TYPE_SERVICE);
|
service_step_all(SVC_TYPE_RUNTASK | SVC_TYPE_SERVICE);
|
||||||
sm->state = SM_RUNNING_STATE;
|
sm->state = SM_RUNNING_STATE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -134,13 +150,11 @@ restart:
|
|||||||
}
|
}
|
||||||
|
|
||||||
_d("Setting new runlevel --> %d <-- previous %d", runlevel, prevlevel);
|
_d("Setting new runlevel --> %d <-- previous %d", runlevel, prevlevel);
|
||||||
|
logit(LOG_CONSOLE | LOG_NOTICE, "%s, entering runlevel %d", INIT_HEADING, runlevel);
|
||||||
runlevel_set(prevlevel, runlevel);
|
runlevel_set(prevlevel, runlevel);
|
||||||
|
|
||||||
/* Disable login in single-user mode as well as shutdown/reboot */
|
/* Disable login in single-user mode as well as shutdown/reboot */
|
||||||
if (runlevel == 1 || runlevel == 0 || runlevel == 6)
|
nologin();
|
||||||
touch("/etc/nologin");
|
|
||||||
else
|
|
||||||
erase("/etc/nologin");
|
|
||||||
|
|
||||||
/* Make sure to (re)load all *.conf in /etc/finit.d/ */
|
/* Make sure to (re)load all *.conf in /etc/finit.d/ */
|
||||||
if (conf_any_change())
|
if (conf_any_change())
|
||||||
@@ -149,7 +163,7 @@ restart:
|
|||||||
/* Reset once flag of runtasks */
|
/* Reset once flag of runtasks */
|
||||||
service_runtask_clean();
|
service_runtask_clean();
|
||||||
|
|
||||||
_d("Stopping services services not allowed in new runlevel ...");
|
_d("Stopping services not allowed in new runlevel ...");
|
||||||
sm->in_teardown = 1;
|
sm->in_teardown = 1;
|
||||||
service_step_all(SVC_TYPE_ANY);
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
|
||||||
@@ -171,7 +185,7 @@ restart:
|
|||||||
_d("All services have been stoppped, calling runlevel change hooks ...");
|
_d("All services have been stoppped, calling runlevel change hooks ...");
|
||||||
plugin_run_hooks(HOOK_RUNLEVEL_CHANGE); /* Reconfigure HW/VLANs/etc here */
|
plugin_run_hooks(HOOK_RUNLEVEL_CHANGE); /* Reconfigure HW/VLANs/etc here */
|
||||||
|
|
||||||
_d("Starting services services new to this runlevel ...");
|
_d("Starting services new to this runlevel ...");
|
||||||
sm->in_teardown = 0;
|
sm->in_teardown = 0;
|
||||||
service_step_all(SVC_TYPE_ANY);
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
|
||||||
@@ -205,7 +219,7 @@ restart:
|
|||||||
* Then, mark all affected service conditions as in-flux and
|
* Then, mark all affected service conditions as in-flux and
|
||||||
* let all affected services move to WAITING/HALTED
|
* let all affected services move to WAITING/HALTED
|
||||||
*/
|
*/
|
||||||
_d("Stopping services services not allowed after reconf ...");
|
_d("Stopping services not allowed after reconf ...");
|
||||||
sm->in_teardown = 1;
|
sm->in_teardown = 1;
|
||||||
cond_reload();
|
cond_reload();
|
||||||
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_INETD);
|
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_INETD);
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
|
#include <sys/ttydefaults.h> /* Not included by default in musl libc */
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
|
|
||||||
|
/* B0 means; keep kernel default */
|
||||||
speed_t stty_parse_speed(char *baud)
|
speed_t stty_parse_speed(char *baud)
|
||||||
{
|
{
|
||||||
char *ptr;
|
char *ptr;
|
||||||
@@ -66,6 +67,9 @@ speed_t stty_parse_speed(char *baud)
|
|||||||
{ 4000000, B4000000 },
|
{ 4000000, B4000000 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!baud || !baud[0])
|
||||||
|
return B0;
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
val = strtoul(baud, &ptr, 10);
|
val = strtoul(baud, &ptr, 10);
|
||||||
if (errno || ptr == baud)
|
if (errno || ptr == baud)
|
||||||
@@ -95,7 +99,7 @@ void stty(int fd, speed_t speed)
|
|||||||
tcflush(fd, TCIOFLUSH);
|
tcflush(fd, TCIOFLUSH);
|
||||||
|
|
||||||
/* Disable modem specific flags */
|
/* Disable modem specific flags */
|
||||||
term.c_cflag &= ~(0|CSTOPB|PARENB|PARODD);
|
term.c_cflag &= ~(0|CSTOPB|PARENB|PARODD|CBAUDEX);
|
||||||
term.c_cflag &= ~CRTSCTS;
|
term.c_cflag &= ~CRTSCTS;
|
||||||
term.c_cflag |= CLOCAL;
|
term.c_cflag |= CLOCAL;
|
||||||
|
|
||||||
@@ -104,7 +108,7 @@ void stty(int fd, speed_t speed)
|
|||||||
term.c_cc[VMIN] = 1;
|
term.c_cc[VMIN] = 1;
|
||||||
term.c_iflag = ICRNL|IXON|IXOFF;
|
term.c_iflag = ICRNL|IXON|IXOFF;
|
||||||
term.c_oflag = OPOST|ONLCR;
|
term.c_oflag = OPOST|ONLCR;
|
||||||
term.c_cflag |= CS8|CREAD|HUPCL|CBAUDEX;
|
term.c_cflag |= CS8|CREAD|HUPCL;
|
||||||
term.c_lflag |= ICANON|ISIG|ECHO|ECHOE|ECHOK|ECHOKE;
|
term.c_lflag |= ICANON|ISIG|ECHO|ECHOE|ECHOK|ECHOKE;
|
||||||
|
|
||||||
/* Reset special characters to defaults */
|
/* Reset special characters to defaults */
|
||||||
@@ -115,6 +119,12 @@ void stty(int fd, speed_t speed)
|
|||||||
term.c_cc[VKILL] = CTRL('U');
|
term.c_cc[VKILL] = CTRL('U');
|
||||||
term.c_cc[VERASE] = CERASE;
|
term.c_cc[VERASE] = CERASE;
|
||||||
tcsetattr(fd, TCSANOW, &term);
|
tcsetattr(fd, TCSANOW, &term);
|
||||||
|
|
||||||
|
/* Show cursor again, if it was hidden previously */
|
||||||
|
write(fd, "\033[?25h", 6);
|
||||||
|
|
||||||
|
/* Enable line wrap, if disabled previously */
|
||||||
|
write(fd, "\033[7h", 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
|
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <ctype.h> /* isdigit() */
|
#include <ctype.h> /* isdigit() */
|
||||||
|
#include <time.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
@@ -34,10 +36,39 @@
|
|||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "pid.h"
|
#include "pid.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "cond.h"
|
||||||
|
#include "schedule.h"
|
||||||
|
|
||||||
/* Each svc_t needs a unique job# */
|
/* Each svc_t needs a unique job# */
|
||||||
static int jobcounter = 1;
|
static int jobcounter = 1;
|
||||||
static TAILQ_HEAD(head, svc) svc_list = TAILQ_HEAD_INITIALIZER(svc_list);
|
static TAILQ_HEAD(, svc) svc_list = TAILQ_HEAD_INITIALIZER(svc_list);
|
||||||
|
static TAILQ_HEAD(, svc) gc_list = TAILQ_HEAD_INITIALIZER(gc_list);
|
||||||
|
|
||||||
|
static void svc_gc(void *arg)
|
||||||
|
{
|
||||||
|
struct timespec now;
|
||||||
|
struct wq *work = (struct wq *)arg;
|
||||||
|
svc_t *svc, *next;
|
||||||
|
|
||||||
|
clock_gettime(CLOCK_MONOTONIC_COARSE, &now);
|
||||||
|
TAILQ_FOREACH_SAFE(svc, &gc_list, link, next) {
|
||||||
|
char cond[MAX_COND_LEN];
|
||||||
|
int msec;
|
||||||
|
|
||||||
|
msec = (now.tv_sec - svc->gc.tv_sec) * 1000 +
|
||||||
|
(now.tv_nsec - svc->gc.tv_nsec) / 1000000;
|
||||||
|
if (msec < SVC_TERM_TIMEOUT)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
TAILQ_REMOVE(&gc_list, svc, link);
|
||||||
|
_d("Cleaning out %s, clearing any conditions ...", svc->name);
|
||||||
|
cond_clear(mkcond(svc, cond, sizeof(cond)));
|
||||||
|
free(svc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TAILQ_EMPTY(&gc_list))
|
||||||
|
schedule_work(work);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* svc_new - Create a new service
|
* svc_new - Create a new service
|
||||||
@@ -48,10 +79,9 @@ static TAILQ_HEAD(head, svc) svc_list = TAILQ_HEAD_INITIALIZER(svc_list);
|
|||||||
* Returns:
|
* Returns:
|
||||||
* A pointer to a new &svc_t object, or %NULL if out of empty slots.
|
* A pointer to a new &svc_t object, or %NULL if out of empty slots.
|
||||||
*/
|
*/
|
||||||
svc_t *svc_new(char *cmd, int id, int type)
|
svc_t *svc_new(char *cmd, char *id, int type)
|
||||||
{
|
{
|
||||||
int job = -1;
|
int job = -1;
|
||||||
char *desc;
|
|
||||||
svc_t *svc, *iter = NULL;
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
/* Find first job n:o if registering multiple instances */
|
/* Find first job n:o if registering multiple instances */
|
||||||
@@ -70,24 +100,31 @@ svc_t *svc_new(char *cmd, int id, int type)
|
|||||||
|
|
||||||
svc->type = type;
|
svc->type = type;
|
||||||
svc->job = job;
|
svc->job = job;
|
||||||
svc->id = id;
|
if (id && id[0])
|
||||||
|
strlcpy(svc->id, id, sizeof(svc->id));
|
||||||
strlcpy(svc->cmd, cmd, sizeof(svc->cmd));
|
strlcpy(svc->cmd, cmd, sizeof(svc->cmd));
|
||||||
|
|
||||||
/* Default description, if missing */
|
/* Default description, if missing */
|
||||||
desc = strrchr(cmd, '/');
|
strlcpy(svc->desc, svc->name, sizeof(svc->desc));
|
||||||
if (desc)
|
|
||||||
desc++;
|
/* Default HALT signal to send */
|
||||||
else
|
svc->sighalt = SIGTERM;
|
||||||
desc = cmd;
|
|
||||||
strlcpy(svc->desc, desc, sizeof(svc->desc));
|
/* Default delay between SIGTERM and SIGKILL */
|
||||||
|
svc->killdelay = SVC_TERM_TIMEOUT;
|
||||||
|
|
||||||
TAILQ_INSERT_TAIL(&svc_list, svc, link);
|
TAILQ_INSERT_TAIL(&svc_list, svc, link);
|
||||||
|
|
||||||
return svc;
|
return svc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct wq work = {
|
||||||
|
.cb = svc_gc,
|
||||||
|
.delay = SVC_TERM_TIMEOUT
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* svc_del - Delete a service object
|
* svc_del - Mark a service object for deletion
|
||||||
* @svc: Pointer to an &svc_t object
|
* @svc: Pointer to an &svc_t object
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
@@ -96,8 +133,10 @@ svc_t *svc_new(char *cmd, int id, int type)
|
|||||||
int svc_del(svc_t *svc)
|
int svc_del(svc_t *svc)
|
||||||
{
|
{
|
||||||
TAILQ_REMOVE(&svc_list, svc, link);
|
TAILQ_REMOVE(&svc_list, svc, link);
|
||||||
memset(svc, 0, sizeof(*svc));
|
TAILQ_INSERT_TAIL(&gc_list, svc, link);
|
||||||
free(svc);
|
|
||||||
|
clock_gettime(CLOCK_MONOTONIC_COARSE, &svc->gc);
|
||||||
|
schedule_work(&work);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -168,7 +207,7 @@ svc_t *svc_named_iterator(svc_t **iter, int first, char *cmd)
|
|||||||
svc_t *svc;
|
svc_t *svc;
|
||||||
|
|
||||||
for (svc = svc_iterator(iter, first); svc; svc = svc_iterator(iter, 0)) {
|
for (svc = svc_iterator(iter, first); svc; svc = svc_iterator(iter, 0)) {
|
||||||
char *name = basename(svc->cmd);
|
char *name = svc->name;
|
||||||
|
|
||||||
if (!strncmp(name, cmd, strlen(name)))
|
if (!strncmp(name, cmd, strlen(name)))
|
||||||
return svc;
|
return svc;
|
||||||
@@ -265,12 +304,12 @@ svc_t *svc_stop_completed(void)
|
|||||||
* Returns:
|
* Returns:
|
||||||
* A pointer to an &svc_t object, or %NULL if not found.
|
* A pointer to an &svc_t object, or %NULL if not found.
|
||||||
*/
|
*/
|
||||||
svc_t *svc_find(char *cmd, int id)
|
svc_t *svc_find(char *cmd, char *id)
|
||||||
{
|
{
|
||||||
svc_t *svc, *iter = NULL;
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
if (svc->id == id && !strncmp(svc->cmd, cmd, strlen(svc->cmd)))
|
if (!strcmp(svc->cmd, cmd) && !strcmp(svc->id, id))
|
||||||
return svc;
|
return svc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,12 +343,12 @@ svc_t *svc_find_by_pid(pid_t pid)
|
|||||||
* Returns:
|
* Returns:
|
||||||
* A pointer to an &svc_t object, or %NULL if not found.
|
* A pointer to an &svc_t object, or %NULL if not found.
|
||||||
*/
|
*/
|
||||||
svc_t *svc_find_by_jobid(int job, int id)
|
svc_t *svc_find_by_jobid(int job, char *id)
|
||||||
{
|
{
|
||||||
svc_t *svc, *iter = NULL;
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
if (svc->job == job && svc->id == id)
|
if (svc->job == job && !strcmp(svc->id, id))
|
||||||
return svc;
|
return svc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,19 +363,12 @@ svc_t *svc_find_by_jobid(int job, int id)
|
|||||||
* Returns:
|
* Returns:
|
||||||
* A pointer to an &svc_t object, or %NULL if not found.
|
* A pointer to an &svc_t object, or %NULL if not found.
|
||||||
*/
|
*/
|
||||||
svc_t *svc_find_by_nameid(char *name, int id)
|
svc_t *svc_find_by_nameid(char *name, char *id)
|
||||||
{
|
{
|
||||||
char *ptr;
|
|
||||||
svc_t *svc, *iter = NULL;
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
ptr = strrchr(svc->cmd, '/');
|
if (!strcmp(svc->id, id) && !strcmp(name, svc->name))
|
||||||
if (ptr)
|
|
||||||
ptr++;
|
|
||||||
else
|
|
||||||
ptr = svc->cmd;
|
|
||||||
|
|
||||||
if (svc->id == id && !strcmp(name, ptr))
|
|
||||||
return svc;
|
return svc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,18 +379,49 @@ svc_t *svc_find_by_nameid(char *name, int id)
|
|||||||
* svc_find_by_plidfile - Find an service object by its PID file
|
* svc_find_by_plidfile - Find an service object by its PID file
|
||||||
* @fn: PID file, can be absolute path or relative to /run
|
* @fn: PID file, can be absolute path or relative to /run
|
||||||
*
|
*
|
||||||
|
* This function is primarily used by the pidfile plugin to track the
|
||||||
|
* conditions and dependencies of services.
|
||||||
|
*
|
||||||
|
* Note, the PID file is assumed to exist so the contents can be
|
||||||
|
* compared to the the PID of a located service. There may be several
|
||||||
|
* services, in many runlevels, that use the same name for the PID file.
|
||||||
|
* So we won't know for sure until the PID is compared.
|
||||||
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* A pointer to an &svc_t object, or %NULL if not found.
|
* A pointer to an &svc_t object, or %NULL if not found.
|
||||||
*/
|
*/
|
||||||
svc_t *svc_find_by_pidfile(char *fn)
|
svc_t *svc_find_by_pidfile(char *fn)
|
||||||
{
|
{
|
||||||
svc_t *svc, *iter = NULL;
|
svc_t *svc, *iter = NULL;
|
||||||
|
char adjpath[strlen(fn) + 10]; /* + sizeof("/var/run/") */
|
||||||
|
char fnpath[PATH_MAX];
|
||||||
|
|
||||||
|
pid_runpath(fn, adjpath, sizeof(adjpath));
|
||||||
|
if (!realpath(adjpath, fnpath)) {
|
||||||
|
_pe("adjpath: %s, errno %d", adjpath, errno);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
char path[MAX_ARG_LEN];
|
char path[PATH_MAX];
|
||||||
|
char *pidfn;
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
if (string_compare(pid_runpath(fn, path, sizeof(path)), pid_file(svc)))
|
pidfn = pid_file(svc);
|
||||||
return svc;
|
if (!pidfn || !realpath(pidfn, path)) {
|
||||||
|
if (errno != ENOENT)
|
||||||
|
_pe("pidfn: %s, errno %d", pidfn ?: "<NULL>", errno);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string_compare(fnpath, path))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pid = pid_file_read(path);
|
||||||
|
if (svc->pid != pid)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return svc;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -379,7 +442,9 @@ void svc_mark_dynamic(void)
|
|||||||
svc_t *svc, *iter = NULL;
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
if (svc->protected)
|
if (svc->protect)
|
||||||
|
continue;
|
||||||
|
if (svc_is_inetd_conn(svc))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
*((int *)&svc->dirty) = -1;
|
*((int *)&svc->dirty) = -1;
|
||||||
@@ -471,18 +536,27 @@ int svc_enabled(svc_t *svc)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Same base service, return unique ID */
|
/*
|
||||||
int svc_next_id(char *cmd)
|
* Same base service, return unique ID as an integer
|
||||||
|
* Note: intended for use with INETD services.
|
||||||
|
*/
|
||||||
|
int svc_next_id_int(char *cmd)
|
||||||
{
|
{
|
||||||
int id = 0;
|
int n = 1;
|
||||||
svc_t *svc, *iter = NULL;
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
if (!strcmp(svc->cmd, cmd) && id < svc->id)
|
char id[MAX_ID_LEN];
|
||||||
id = svc->id;
|
|
||||||
|
snprintf(id, sizeof(id), "%d", n);
|
||||||
|
|
||||||
|
if (!strcmp(svc->cmd, cmd) && strcmp(svc->id, id))
|
||||||
|
return n;
|
||||||
|
|
||||||
|
n++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return id + 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int svc_is_unique(svc_t *svc)
|
int svc_is_unique(svc_t *svc)
|
||||||
@@ -506,31 +580,76 @@ int svc_is_unique(svc_t *svc)
|
|||||||
return unique;
|
return unique;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* break up "job:id job:id job:id ..." into several "job:id" tokens */
|
||||||
|
static char *tokstr(char *str, size_t len)
|
||||||
|
{
|
||||||
|
static char *cur = NULL;
|
||||||
|
static size_t pos = 0;
|
||||||
|
char *token;
|
||||||
|
|
||||||
|
if (!cur && !str)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (str) {
|
||||||
|
cur = str;
|
||||||
|
pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos >= len)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
token = &cur[pos];
|
||||||
|
while (pos < len) {
|
||||||
|
if (isspace(cur[pos])) {
|
||||||
|
cur[pos++] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Used by api.c (to start/stop/restart) and initctl.c (for input validation)
|
* Used by api.c (to start/stop/restart) and initctl.c (for input validation)
|
||||||
*/
|
*/
|
||||||
int svc_parse_jobstr(char *str, size_t len, int (*found)(svc_t *), int (not_found)(char *, int))
|
int svc_parse_jobstr(char *str, size_t len, int (*found)(svc_t *), int (not_found)(char *, char *))
|
||||||
{
|
{
|
||||||
|
char *input, *token;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
char *input, *token, *pos;
|
|
||||||
|
|
||||||
input = sanitize(str, len);
|
_d("Got str:'%s'", str);
|
||||||
if (!input)
|
input = tokstr(str, len);
|
||||||
return -1;
|
while (input) {
|
||||||
|
char *id = NULL;
|
||||||
token = strtok_r(input, " ", &pos);
|
|
||||||
while (token) {
|
|
||||||
int id = 1;
|
|
||||||
svc_t *svc, *iter = NULL;
|
svc_t *svc, *iter = NULL;
|
||||||
char *ptr = strchr(token, ':');
|
char *ptr;
|
||||||
|
|
||||||
|
_d("Got token:'%s'", input);
|
||||||
|
token = sanitize(input, len);
|
||||||
|
if (!token) {
|
||||||
|
_d("Sanitation of token:'%s' failed", input);
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
ptr = strchr(token, ':');
|
||||||
|
|
||||||
if (isdigit(token[0])) {
|
if (isdigit(token[0])) {
|
||||||
int job = atonum(token);
|
char *ep;
|
||||||
|
long job = 0;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
job = strtol(token, &ep, 10);
|
||||||
|
if ((errno == ERANGE && (job == LONG_MAX || job == LONG_MIN)) ||
|
||||||
|
(errno != 0 && job == 0) ||
|
||||||
|
(token == ep)) {
|
||||||
|
result++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!ptr) {
|
if (!ptr) {
|
||||||
svc = svc_job_iterator(&iter, 1, job);
|
svc = svc_job_iterator(&iter, 1, job);
|
||||||
if (!svc && not_found)
|
if (!svc && not_found)
|
||||||
result += not_found(NULL, job);
|
result += not_found(NULL, token);
|
||||||
|
|
||||||
while (svc) {
|
while (svc) {
|
||||||
if (found)
|
if (found)
|
||||||
@@ -539,8 +658,7 @@ int svc_parse_jobstr(char *str, size_t len, int (*found)(svc_t *), int (not_foun
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
*ptr++ = 0;
|
*ptr++ = 0;
|
||||||
id = atonum(ptr);
|
id = ptr;
|
||||||
job = atonum(token);
|
|
||||||
|
|
||||||
svc = svc_find_by_jobid(job, id);
|
svc = svc_find_by_jobid(job, id);
|
||||||
if (!svc && not_found)
|
if (!svc && not_found)
|
||||||
@@ -561,7 +679,7 @@ int svc_parse_jobstr(char *str, size_t len, int (*found)(svc_t *), int (not_foun
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
*ptr++ = 0;
|
*ptr++ = 0;
|
||||||
id = atonum(ptr);
|
id = ptr;
|
||||||
|
|
||||||
svc = svc_find_by_nameid(token, id);
|
svc = svc_find_by_nameid(token, id);
|
||||||
if (!svc && not_found)
|
if (!svc && not_found)
|
||||||
@@ -571,7 +689,8 @@ int svc_parse_jobstr(char *str, size_t len, int (*found)(svc_t *), int (not_foun
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
token = strtok_r(NULL, " ", &pos);
|
next:
|
||||||
|
input = tokstr(NULL, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -43,10 +43,11 @@ typedef enum {
|
|||||||
SVC_TYPE_RUN = 4, /* Like task, but wait for completion */
|
SVC_TYPE_RUN = 4, /* Like task, but wait for completion */
|
||||||
SVC_TYPE_INETD = 8, /* Classic inetd service */
|
SVC_TYPE_INETD = 8, /* Classic inetd service */
|
||||||
SVC_TYPE_INETD_CONN = 16, /* Single inetd connection */
|
SVC_TYPE_INETD_CONN = 16, /* Single inetd connection */
|
||||||
|
SVC_TYPE_SYSV = 32, /* SysV style init.d script w/ start/stop */
|
||||||
} svc_type_t;
|
} svc_type_t;
|
||||||
|
|
||||||
#define SVC_TYPE_ANY (-1)
|
#define SVC_TYPE_ANY (-1)
|
||||||
#define SVC_TYPE_RUNTASK (6)
|
#define SVC_TYPE_RUNTASK (SVC_TYPE_RUN | SVC_TYPE_TASK | SVC_TYPE_SYSV)
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SVC_HALTED_STATE = 0, /* Not allowed in runlevel, or not enabled. */
|
SVC_HALTED_STATE = 0, /* Not allowed in runlevel, or not enabled. */
|
||||||
@@ -66,12 +67,16 @@ typedef enum {
|
|||||||
SVC_BLOCK_RESTARTING,
|
SVC_BLOCK_RESTARTING,
|
||||||
} svc_block_t;
|
} svc_block_t;
|
||||||
|
|
||||||
|
#define MAX_ID_LEN 16
|
||||||
#define MAX_ARG_LEN 64
|
#define MAX_ARG_LEN 64
|
||||||
#define MAX_STR_LEN 64
|
#define MAX_STR_LEN 64
|
||||||
#define MAX_COND_LEN (MAX_ARG_LEN * 3)
|
#define MAX_COND_LEN (MAX_ARG_LEN * 3)
|
||||||
#define MAX_USER_LEN 16
|
#define MAX_USER_LEN 16
|
||||||
#define MAX_NUM_FDS 64 /* Max number of I/O plugins */
|
#define MAX_NUM_FDS 64 /* Max number of I/O plugins */
|
||||||
#define MAX_NUM_SVC_ARGS 32
|
#define MAX_NUM_SVC_ARGS 64
|
||||||
|
|
||||||
|
/* Default kill delay (msec) after SIGTERM (svc->sighalt) that we SIGKILL processes */
|
||||||
|
#define SVC_TERM_TIMEOUT 3000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Default enable for all services, can be stopped by means
|
* Default enable for all services, can be stopped by means
|
||||||
@@ -83,24 +88,30 @@ typedef struct svc {
|
|||||||
TAILQ_ENTRY(svc) link;
|
TAILQ_ENTRY(svc) link;
|
||||||
|
|
||||||
/* Instance specifics */
|
/* Instance specifics */
|
||||||
int job, id; /* JOB:ID */
|
int job; /* JOB: */
|
||||||
|
char id[MAX_ID_LEN]; /* :ID */
|
||||||
|
|
||||||
/* Limits and scoping */
|
/* Limits and scoping */
|
||||||
struct rlimit rlimit[RLIMIT_NLIMITS];
|
struct rlimit rlimit[RLIMIT_NLIMITS];
|
||||||
|
|
||||||
/* Service details */
|
/* Service details */
|
||||||
pid_t pid;
|
int sighalt; /* Signal to stop prorcess, default: SIGTERM */
|
||||||
char pidfile[MAX_ARG_LEN];
|
int killdelay; /* Delay in msec before sending SIGKILL */
|
||||||
|
pid_t pid;
|
||||||
|
char pidfile[256];
|
||||||
long start_time; /* Start time, as seconds since boot, from sysinfo() */
|
long start_time; /* Start time, as seconds since boot, from sysinfo() */
|
||||||
|
int started; /* Set for run/task/sysv to track if started */
|
||||||
|
int status; /* From waitpid() when process is collected */
|
||||||
const svc_state_t state; /* Paused, Reloading, Restart, Running, ... */
|
const svc_state_t state; /* Paused, Reloading, Restart, Running, ... */
|
||||||
svc_type_t type; /* Service, run, task, inetd, ... */
|
svc_type_t type; /* Service, run, task, inetd, ... */
|
||||||
int protected; /* Services like dbus-daemon & udev by Finit */
|
int protect; /* Services like dbus-daemon & udev by Finit */
|
||||||
const int dirty; /* -1: removal, 0: unmodified, 1: modified */
|
const int dirty; /* -1: removal, 0: unmodified, 1: modified */
|
||||||
int starting; /* ... waiting for pidfile to be re-asserted */
|
int starting; /* ... waiting for pidfile to be re-asserted */
|
||||||
int runlevels;
|
int runlevels;
|
||||||
int sighup; /* This service supports SIGHUP :) */
|
int sighup; /* This service supports SIGHUP :) */
|
||||||
svc_block_t block; /* Reason that this service is currently stopped */
|
svc_block_t block; /* Reason that this service is currently stopped */
|
||||||
char cond[MAX_COND_LEN];
|
char cond[MAX_COND_LEN];
|
||||||
|
char name[MAX_ARG_LEN];
|
||||||
|
|
||||||
/* Counters */
|
/* Counters */
|
||||||
char once; /* run/task, (at least) once per runlevel */
|
char once; /* run/task, (at least) once per runlevel */
|
||||||
@@ -109,11 +120,13 @@ typedef struct svc {
|
|||||||
/* For inetd services */
|
/* For inetd services */
|
||||||
inetd_t inetd;
|
inetd_t inetd;
|
||||||
int stdin_fd;
|
int stdin_fd;
|
||||||
|
char iifname[IF_NAMESIZE + 1]; /* Ingress interface for connection */
|
||||||
|
|
||||||
/* Set for services we need to redirect stdout/stderr to syslog */
|
/* Set for services we need to redirect stdout/stderr to syslog */
|
||||||
struct {
|
struct {
|
||||||
char enabled;
|
char enabled;
|
||||||
char null;
|
char null;
|
||||||
|
char console;
|
||||||
char file[64];
|
char file[64];
|
||||||
char prio[20];
|
char prio[20];
|
||||||
char ident[20];
|
char ident[20];
|
||||||
@@ -134,15 +147,18 @@ typedef struct svc {
|
|||||||
*/
|
*/
|
||||||
uev_t timer;
|
uev_t timer;
|
||||||
void (*timer_cb)(struct svc *svc);
|
void (*timer_cb)(struct svc *svc);
|
||||||
|
|
||||||
|
/* time at svc_del(), used by gc timer */
|
||||||
|
struct timespec gc;
|
||||||
} svc_t;
|
} svc_t;
|
||||||
|
|
||||||
svc_t *svc_new (char *cmd, int id, int type);
|
svc_t *svc_new (char *cmd, char *id, int type);
|
||||||
int svc_del (svc_t *svc);
|
int svc_del (svc_t *svc);
|
||||||
|
|
||||||
svc_t *svc_find (char *cmd, int id);
|
svc_t *svc_find (char *cmd, char *id);
|
||||||
svc_t *svc_find_by_pid (pid_t pid);
|
svc_t *svc_find_by_pid (pid_t pid);
|
||||||
svc_t *svc_find_by_jobid (int job, int id);
|
svc_t *svc_find_by_jobid (int job, char *id);
|
||||||
svc_t *svc_find_by_nameid (char *name, int id);
|
svc_t *svc_find_by_nameid (char *name, char *id);
|
||||||
svc_t *svc_find_by_pidfile (char *fn);
|
svc_t *svc_find_by_pidfile (char *fn);
|
||||||
|
|
||||||
svc_t *svc_iterator (svc_t **iter, int first);
|
svc_t *svc_iterator (svc_t **iter, int first);
|
||||||
@@ -163,40 +179,45 @@ int svc_clean_bootstrap (svc_t *svc);
|
|||||||
void svc_prune_bootstrap (void);
|
void svc_prune_bootstrap (void);
|
||||||
|
|
||||||
int svc_enabled (svc_t *svc);
|
int svc_enabled (svc_t *svc);
|
||||||
int svc_next_id (char *cmd);
|
int svc_next_id_int (char *cmd);
|
||||||
int svc_is_unique (svc_t *svc);
|
int svc_is_unique (svc_t *svc);
|
||||||
|
|
||||||
int svc_parse_jobstr (char *str, size_t len, int (*found)(svc_t *), int (not_found)(char *, int));
|
int svc_parse_jobstr (char *str, size_t len, int (*found)(svc_t *), int (not_found)(char *, char *));
|
||||||
|
|
||||||
static inline int svc_is_inetd (svc_t *svc) { return svc && SVC_TYPE_INETD == svc->type; }
|
static inline int svc_is_inetd (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_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_daemon (svc_t *svc) { return svc && SVC_TYPE_SERVICE == svc->type; }
|
||||||
|
static inline int svc_is_sysv (svc_t *svc) { return svc && SVC_TYPE_SYSV == svc->type; }
|
||||||
static inline int svc_is_runtask (svc_t *svc) { return svc && (SVC_TYPE_RUNTASK & svc->type); }
|
static inline int svc_is_runtask (svc_t *svc) { return svc && (SVC_TYPE_RUNTASK & svc->type); }
|
||||||
|
static inline int svc_is_forking (svc_t *svc) { return (svc_is_daemon(svc) || svc_is_sysv(svc)) && svc->pidfile[0] == '!'; }
|
||||||
|
|
||||||
static inline int svc_in_runlevel (svc_t *svc, int runlevel) { return svc && ISSET(svc->runlevels, runlevel); }
|
static inline int svc_in_runlevel (svc_t *svc, int runlevel) { return svc && ISSET(svc->runlevels, runlevel); }
|
||||||
static inline int svc_has_sighup (svc_t *svc) { return svc && 0 != svc->sighup; }
|
static inline int svc_has_sighup (svc_t *svc) { return svc && 0 != svc->sighup; }
|
||||||
static inline int svc_has_pidfile (svc_t *svc) { return svc_is_daemon(svc) && svc->pidfile[0] != 0 && svc->pidfile[0] != '!'; }
|
static inline int svc_has_pidfile (svc_t *svc) { return svc_is_daemon(svc) && svc->pidfile[0] != 0 && svc->pidfile[0] != '!'; }
|
||||||
|
|
||||||
static inline void svc_starting (svc_t *svc) { svc->starting = 1; }
|
static inline void svc_starting (svc_t *svc) { if (svc) svc->starting = 1; }
|
||||||
static inline void svc_started (svc_t *svc) { svc->starting = 0; }
|
static inline void svc_started (svc_t *svc) { if (svc) svc->starting = 0; }
|
||||||
static inline int svc_is_starting (svc_t *svc) { return 0 != svc->starting; }
|
static inline int svc_is_starting (svc_t *svc) { return svc && 0 != svc->starting; }
|
||||||
|
|
||||||
static inline int svc_is_removed (svc_t *svc) { return svc && -1 == svc->dirty; }
|
static inline int svc_is_removed (svc_t *svc) { return svc && -1 == svc->dirty; }
|
||||||
static inline int svc_is_changed (svc_t *svc) { return svc && 0 != svc->dirty; }
|
static inline int svc_is_changed (svc_t *svc) { return svc && 0 != svc->dirty; }
|
||||||
static inline int svc_is_updated (svc_t *svc) { return svc && 1 == svc->dirty; }
|
static inline int svc_is_updated (svc_t *svc) { return svc && 1 == svc->dirty; }
|
||||||
|
|
||||||
static inline int svc_is_blocked (svc_t *svc) { return svc->block != SVC_BLOCK_NONE; }
|
static inline int svc_is_blocked (svc_t *svc) { return svc && svc->block != SVC_BLOCK_NONE; }
|
||||||
static inline int svc_is_busy (svc_t *svc) { return svc->block == SVC_BLOCK_BUSY; }
|
static inline int svc_is_busy (svc_t *svc) { return svc && svc->block == SVC_BLOCK_BUSY; }
|
||||||
static inline void svc_unblock (svc_t *svc) { svc->block = SVC_BLOCK_NONE; }
|
static inline void svc_unblock (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_NONE; }
|
||||||
#define svc_start(svc) svc_unblock(svc)
|
#define svc_start(svc) svc_unblock(svc)
|
||||||
static inline void svc_stop (svc_t *svc) { svc->block = SVC_BLOCK_USER; }
|
static inline void svc_stop (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_USER; }
|
||||||
static inline void svc_busy (svc_t *svc) { svc->block = SVC_BLOCK_BUSY; }
|
static inline void svc_busy (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_BUSY; }
|
||||||
static inline void svc_missing (svc_t *svc) { svc->block = SVC_BLOCK_MISSING; }
|
static inline void svc_missing (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_MISSING; }
|
||||||
static inline void svc_restarting (svc_t *svc) { svc->block = SVC_BLOCK_RESTARTING; }
|
static inline void svc_restarting (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_RESTARTING; }
|
||||||
static inline void svc_crashing (svc_t *svc) { svc->block = SVC_BLOCK_CRASHING; }
|
static inline void svc_crashing (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_CRASHING; }
|
||||||
|
|
||||||
static inline char *svc_status(svc_t *svc)
|
static inline char *svc_status(svc_t *svc)
|
||||||
{
|
{
|
||||||
|
if (!svc)
|
||||||
|
return "Unknown";
|
||||||
|
|
||||||
switch (svc->state) {
|
switch (svc->state) {
|
||||||
case SVC_HALTED_STATE:
|
case SVC_HALTED_STATE:
|
||||||
switch (svc->block) {
|
switch (svc->block) {
|
||||||
@@ -218,6 +239,7 @@ static inline char *svc_status(svc_t *svc)
|
|||||||
case SVC_BLOCK_RESTARTING:
|
case SVC_BLOCK_RESTARTING:
|
||||||
return "restart";
|
return "restart";
|
||||||
}
|
}
|
||||||
|
return "unknown";
|
||||||
|
|
||||||
case SVC_DONE_STATE:
|
case SVC_DONE_STATE:
|
||||||
return "done";
|
return "done";
|
||||||
@@ -249,6 +271,9 @@ static inline char *svc_status(svc_t *svc)
|
|||||||
|
|
||||||
static inline const char *svc_dirtystr(svc_t *svc)
|
static inline const char *svc_dirtystr(svc_t *svc)
|
||||||
{
|
{
|
||||||
|
if (!svc)
|
||||||
|
return "Unknown";
|
||||||
|
|
||||||
if (svc_is_removed(svc))
|
if (svc_is_removed(svc))
|
||||||
return "removed";
|
return "removed";
|
||||||
if (svc_is_updated(svc))
|
if (svc_is_updated(svc))
|
||||||
|
|||||||
@@ -41,32 +41,16 @@
|
|||||||
#ifdef FALLBACK_SHELL
|
#ifdef FALLBACK_SHELL
|
||||||
static pid_t fallback = 0;
|
static pid_t fallback = 0;
|
||||||
#endif
|
#endif
|
||||||
static LIST_HEAD(, tty_node) tty_list = LIST_HEAD_INITIALIZER();
|
static LIST_HEAD(, tty) tty_list = LIST_HEAD_INITIALIZER();
|
||||||
|
|
||||||
static char *canonicalize(char *tty)
|
static char *canonicalize(char *tty)
|
||||||
{
|
{
|
||||||
char buf[42];
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
static char path[80];
|
static char path[80];
|
||||||
|
|
||||||
if (!tty)
|
if (!tty)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Auto-detect serial console, for embedded devices mostly */
|
|
||||||
if (!strcmp(tty, "@console")) {
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
fp = fopen("/sys/class/tty/console/active", "r");
|
|
||||||
if (!fp) {
|
|
||||||
_e("Cannot find system console, is sysfs not mounted?");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fgets(buf, sizeof(buf), fp))
|
|
||||||
tty = chomp(buf);
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
strlcpy(path, tty, sizeof(path));
|
strlcpy(path, tty, sizeof(path));
|
||||||
if (stat(path, &st)) {
|
if (stat(path, &st)) {
|
||||||
if (!strncmp(path, _PATH_DEV, strlen(_PATH_DEV))) {
|
if (!strncmp(path, _PATH_DEV, strlen(_PATH_DEV))) {
|
||||||
@@ -88,7 +72,7 @@ static char *canonicalize(char *tty)
|
|||||||
|
|
||||||
void tty_mark(void)
|
void tty_mark(void)
|
||||||
{
|
{
|
||||||
tty_node_t *tty;
|
struct tty *tty;
|
||||||
|
|
||||||
LIST_FOREACH(tty, &tty_list, link)
|
LIST_FOREACH(tty, &tty_list, link)
|
||||||
tty->dirty = -1;
|
tty->dirty = -1;
|
||||||
@@ -96,17 +80,17 @@ void tty_mark(void)
|
|||||||
|
|
||||||
void tty_sweep(void)
|
void tty_sweep(void)
|
||||||
{
|
{
|
||||||
tty_node_t *tty, *tmp;
|
struct tty *tty, *tmp;
|
||||||
|
|
||||||
LIST_FOREACH_SAFE(tty, &tty_list, link, tmp) {
|
LIST_FOREACH_SAFE(tty, &tty_list, link, tmp) {
|
||||||
if (!tty->dirty)
|
if (!tty->dirty)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_d("TTY %s dirty, stopping ...", tty->data.name);
|
_d("TTY %s dirty, stopping ...", tty->name);
|
||||||
tty_stop(&tty->data);
|
tty_stop(tty);
|
||||||
|
|
||||||
if (tty->dirty == -1) {
|
if (tty->dirty == -1) {
|
||||||
_d("TTY %s removed, cleaning up.", tty->data.name);
|
_d("TTY %s removed, cleaning up.", tty->name);
|
||||||
tty_unregister(tty);
|
tty_unregister(tty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,12 +120,12 @@ void tty_sweep(void)
|
|||||||
*/
|
*/
|
||||||
int tty_register(char *line, struct rlimit rlimit[], char *file)
|
int tty_register(char *line, struct rlimit rlimit[], char *file)
|
||||||
{
|
{
|
||||||
tty_node_t *entry;
|
struct tty *entry;
|
||||||
int insert = 0, noclear = 0, nowait = 0, nologin = 0;
|
|
||||||
size_t i, num = 0;
|
size_t i, num = 0;
|
||||||
char *tok, *cmd = NULL, *args[TTY_MAX_ARGS];
|
char *tok, *cmd = NULL, *args[TTY_MAX_ARGS], buf[256];
|
||||||
char *dev = NULL, *baud = NULL;
|
char *dev = NULL, *baud = NULL;
|
||||||
char *runlevels = NULL, *term = NULL;
|
char *runlevels = NULL, *term = NULL;
|
||||||
|
int insert = 0, noclear = 0, nowait = 0, nologin = 0, atcon = 0;
|
||||||
|
|
||||||
if (!line) {
|
if (!line) {
|
||||||
_e("Missing argument");
|
_e("Missing argument");
|
||||||
@@ -169,25 +153,29 @@ int tty_register(char *line, struct rlimit rlimit[], char *file)
|
|||||||
|
|
||||||
/* Iterate over all args */
|
/* Iterate over all args */
|
||||||
for (i = 0; i < num; i++) {
|
for (i = 0; i < num; i++) {
|
||||||
/* First, figure out if built-in or external */
|
/*
|
||||||
if (!dev && !cmd) {
|
* First, figure out if built-in or external getty
|
||||||
|
* tty [12345] /dev/ttyAMA0 115200 noclear vt220 # built-in
|
||||||
|
* tty [12345] /sbin/getty -L 115200 @console vt100 noclear # external
|
||||||
|
*/
|
||||||
|
if ((!cmd && !dev) || (cmd && !dev)) {
|
||||||
if (args[i][0] == '[')
|
if (args[i][0] == '[')
|
||||||
runlevels = line;
|
runlevels = line;
|
||||||
if (!strcmp(args[i], "@console"))
|
if (!strcmp(args[i], "@console") || !strcmp(args[i], "console"))
|
||||||
dev = args[i];
|
dev = args[i];
|
||||||
if (!strncmp(args[i], "/dev", 4))
|
if (!strncmp(args[i], "/dev", 4))
|
||||||
dev = args[i];
|
dev = args[i];
|
||||||
if (!strncmp(args[i], "tty", 3))
|
if (!strncmp(args[i], "tty", 3))
|
||||||
dev = args[i];
|
dev = args[i];
|
||||||
if (!access(args[i], X_OK))
|
if (!access(args[i], X_OK))
|
||||||
cmd = strdup(args[i]);
|
cmd = args[i];
|
||||||
|
|
||||||
/* The first arg must be one of the above */
|
/* The first arg must be one of the above */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Built-in getty args */
|
/* Built-in getty args */
|
||||||
if (dev) {
|
if (!cmd && dev) {
|
||||||
if (isdigit(args[i][0])) {
|
if (isdigit(args[i][0])) {
|
||||||
baud = args[i];
|
baud = args[i];
|
||||||
continue;
|
continue;
|
||||||
@@ -200,51 +188,63 @@ int tty_register(char *line, struct rlimit rlimit[], char *file)
|
|||||||
if (i + 1 == num)
|
if (i + 1 == num)
|
||||||
term = args[i];
|
term = args[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* External getty, figure out the device */
|
|
||||||
if (cmd) {
|
|
||||||
if (!strncmp(args[i], "/dev", 4))
|
|
||||||
dev = args[i];
|
|
||||||
|
|
||||||
if (!strncmp(args[i], "tty", 3))
|
|
||||||
dev = args[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
error:
|
error:
|
||||||
_e("Incomplete or non-existing TTY device given, cannot register.");
|
_e("Incomplete or non-existing TTY device given, cannot register.");
|
||||||
if (cmd)
|
|
||||||
free(cmd);
|
|
||||||
|
|
||||||
return errno = EINVAL;
|
return errno = EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Auto-detect serial console, for embedded devices mostly */
|
||||||
|
if (!strcmp(dev, "@console") || !strcmp(dev, "console")) {
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopen("/sys/class/tty/console/active", "r");
|
||||||
|
if (!fp) {
|
||||||
|
_e("Cannot find system console, is sysfs not mounted?");
|
||||||
|
return errno = ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
atcon = 1;
|
||||||
|
if (fgets(buf, sizeof(buf), fp))
|
||||||
|
dev = strtok(chomp(buf), " \t");
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
again:
|
||||||
/* Ensure all getty (built-in + external) are registered with absolute path */
|
/* Ensure all getty (built-in + external) are registered with absolute path */
|
||||||
dev = canonicalize(dev);
|
dev = canonicalize(dev);
|
||||||
if (!dev)
|
if (!dev)
|
||||||
goto error;
|
goto error;
|
||||||
dev = strdup(dev);
|
|
||||||
|
|
||||||
entry = tty_find(dev);
|
entry = tty_find(dev);
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
insert = 1;
|
|
||||||
entry = calloc(1, sizeof(*entry));
|
entry = calloc(1, sizeof(*entry));
|
||||||
if (!entry) {
|
if (!entry)
|
||||||
free(dev);
|
|
||||||
if (cmd)
|
|
||||||
free(cmd);
|
|
||||||
return errno = ENOMEM;
|
return errno = ENOMEM;
|
||||||
|
insert = 1;
|
||||||
|
} else {
|
||||||
|
if (entry->cmd) {
|
||||||
|
free(entry->cmd);
|
||||||
|
entry->cmd = NULL;
|
||||||
|
for (i = 0; i < TTY_MAX_ARGS; i++) {
|
||||||
|
if (entry->args[i])
|
||||||
|
free(entry->args[i]);
|
||||||
|
entry->args[i] = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
insert = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry->data.name = dev;
|
strlcpy(entry->name, dev, sizeof(entry->name));
|
||||||
entry->data.baud = baud ? strdup(baud) : NULL;
|
strlcpy(entry->baud, baud ? baud : "", sizeof(entry->baud));
|
||||||
entry->data.term = term ? strdup(term) : NULL;
|
strlcpy(entry->term, term ? term : "", sizeof(entry->term));
|
||||||
entry->data.noclear = noclear;
|
entry->noclear = noclear;
|
||||||
entry->data.nowait = nowait;
|
entry->nowait = nowait;
|
||||||
entry->data.nologin = nologin;
|
entry->nologin = nologin;
|
||||||
entry->data.runlevels = conf_parse_runlevels(runlevels);
|
entry->runlevels = conf_parse_runlevels(runlevels);
|
||||||
|
|
||||||
/* External getty */
|
/* External getty */
|
||||||
if (cmd) {
|
if (cmd) {
|
||||||
@@ -255,12 +255,19 @@ int tty_register(char *line, struct rlimit rlimit[], char *file)
|
|||||||
tok = cmd;
|
tok = cmd;
|
||||||
else
|
else
|
||||||
tok++;
|
tok++;
|
||||||
entry->data.cmd = cmd;
|
entry->cmd = strdup(cmd);
|
||||||
args[1] = strdup(tok);
|
args[1] = strdup(tok);
|
||||||
|
|
||||||
for (i = 1; i < num; i++)
|
for (i = 1; i < num; i++) {
|
||||||
entry->data.args[j++] = strdup(args[i]);
|
char *arg = args[i];
|
||||||
entry->data.args[++j] = NULL;
|
|
||||||
|
/* Replace @console with actual device */
|
||||||
|
if (arg && (!strcmp(arg, "@console") || !strcmp(arg, "console")))
|
||||||
|
arg = dev;
|
||||||
|
if (arg)
|
||||||
|
entry->args[j++] = strdup(arg);
|
||||||
|
}
|
||||||
|
entry->args[++j] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("Registering %s getty on TTY %s at %s baud with term %s on runlevels %s",
|
_d("Registering %s getty on TTY %s at %s baud with term %s on runlevels %s",
|
||||||
@@ -270,7 +277,7 @@ int tty_register(char *line, struct rlimit rlimit[], char *file)
|
|||||||
LIST_INSERT_HEAD(&tty_list, entry, link);
|
LIST_INSERT_HEAD(&tty_list, entry, link);
|
||||||
|
|
||||||
/* Register configured limits */
|
/* Register configured limits */
|
||||||
memcpy(entry->data.rlimit, rlimit, sizeof(entry->data.rlimit));
|
memcpy(entry->rlimit, rlimit, sizeof(entry->rlimit));
|
||||||
|
|
||||||
if (file && conf_changed(file))
|
if (file && conf_changed(file))
|
||||||
entry->dirty = 1; /* Modified, restart */
|
entry->dirty = 1; /* Modified, restart */
|
||||||
@@ -278,10 +285,18 @@ int tty_register(char *line, struct rlimit rlimit[], char *file)
|
|||||||
entry->dirty = 0; /* Not modified */
|
entry->dirty = 0; /* Not modified */
|
||||||
_d("TTY %s is %sdirty", dev, entry->dirty ? "" : "NOT ");
|
_d("TTY %s is %sdirty", dev, entry->dirty ? "" : "NOT ");
|
||||||
|
|
||||||
|
if (atcon) {
|
||||||
|
dev = strtok(NULL, " \t");
|
||||||
|
if (dev) {
|
||||||
|
_d("Found another @console: %s", dev);
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tty_unregister(tty_node_t *tty)
|
int tty_unregister(struct tty *tty)
|
||||||
{
|
{
|
||||||
if (!tty) {
|
if (!tty) {
|
||||||
_e("Missing argument");
|
_e("Missing argument");
|
||||||
@@ -290,20 +305,14 @@ int tty_unregister(tty_node_t *tty)
|
|||||||
|
|
||||||
LIST_REMOVE(tty, link);
|
LIST_REMOVE(tty, link);
|
||||||
|
|
||||||
if (tty->data.name)
|
if (tty->cmd) {
|
||||||
free(tty->data.name);
|
|
||||||
if (tty->data.baud)
|
|
||||||
free(tty->data.baud);
|
|
||||||
if (tty->data.term)
|
|
||||||
free(tty->data.term);
|
|
||||||
if (tty->data.cmd) {
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
free(tty->data.cmd);
|
free(tty->cmd);
|
||||||
for (i = 0; i < TTY_MAX_ARGS; i++) {
|
for (i = 0; i < TTY_MAX_ARGS; i++) {
|
||||||
if (tty->data.args[i])
|
if (tty->args[i])
|
||||||
free(tty->data.args[i]);
|
free(tty->args[i]);
|
||||||
tty->data.args[i] = NULL;
|
tty->args[i] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(tty);
|
free(tty);
|
||||||
@@ -311,12 +320,12 @@ int tty_unregister(tty_node_t *tty)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
tty_node_t *tty_find(char *dev)
|
struct tty *tty_find(char *dev)
|
||||||
{
|
{
|
||||||
tty_node_t *entry;
|
struct tty *entry;
|
||||||
|
|
||||||
LIST_FOREACH(entry, &tty_list, link) {
|
LIST_FOREACH(entry, &tty_list, link) {
|
||||||
if (!strcmp(dev, entry->data.name))
|
if (!strcmp(dev, entry->name))
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,7 +335,7 @@ tty_node_t *tty_find(char *dev)
|
|||||||
size_t tty_num(void)
|
size_t tty_num(void)
|
||||||
{
|
{
|
||||||
size_t num = 0;
|
size_t num = 0;
|
||||||
tty_node_t *entry;
|
struct tty *entry;
|
||||||
|
|
||||||
LIST_FOREACH(entry, &tty_list, link)
|
LIST_FOREACH(entry, &tty_list, link)
|
||||||
num++;
|
num++;
|
||||||
@@ -337,22 +346,22 @@ size_t tty_num(void)
|
|||||||
size_t tty_num_active(void)
|
size_t tty_num_active(void)
|
||||||
{
|
{
|
||||||
size_t num = 0;
|
size_t num = 0;
|
||||||
tty_node_t *entry;
|
struct tty *entry;
|
||||||
|
|
||||||
LIST_FOREACH(entry, &tty_list, link) {
|
LIST_FOREACH(entry, &tty_list, link) {
|
||||||
if (entry->data.pid)
|
if (entry->pid)
|
||||||
num++;
|
num++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
tty_node_t *tty_find_by_pid(pid_t pid)
|
struct tty *tty_find_by_pid(pid_t pid)
|
||||||
{
|
{
|
||||||
tty_node_t *entry;
|
struct tty *entry;
|
||||||
|
|
||||||
LIST_FOREACH(entry, &tty_list, link) {
|
LIST_FOREACH(entry, &tty_list, link) {
|
||||||
if (entry->data.pid == pid)
|
if (entry->pid == pid)
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,7 +384,7 @@ static int tty_exist(char *dev)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tty_start(finit_tty_t *tty)
|
void tty_start(struct tty *tty)
|
||||||
{
|
{
|
||||||
char *dev;
|
char *dev;
|
||||||
|
|
||||||
@@ -396,17 +405,19 @@ void tty_start(finit_tty_t *tty)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tty->nologin) {
|
if (tty->nologin) {
|
||||||
|
_d("%s: Starting /bin/sh ...", dev);
|
||||||
tty->pid = run_sh(dev, tty->noclear, tty->nowait, tty->rlimit);
|
tty->pid = run_sh(dev, tty->noclear, tty->nowait, tty->rlimit);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_d("%s: Starting %sgetty ...", dev, !tty->cmd ? "built-in " : "");
|
||||||
if (!tty->cmd)
|
if (!tty->cmd)
|
||||||
tty->pid = run_getty(dev, tty->baud, tty->term, tty->noclear, tty->nowait, tty->rlimit);
|
tty->pid = run_getty(dev, tty->baud, tty->term, tty->noclear, tty->nowait, tty->rlimit);
|
||||||
else
|
else
|
||||||
tty->pid = run_getty2(dev, tty->cmd, tty->args, tty->noclear, tty->nowait, tty->rlimit);
|
tty->pid = run_getty2(dev, tty->cmd, tty->args, tty->noclear, tty->nowait, tty->rlimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tty_stop(finit_tty_t *tty)
|
void tty_stop(struct tty *tty)
|
||||||
{
|
{
|
||||||
if (!tty->pid)
|
if (!tty->pid)
|
||||||
return;
|
return;
|
||||||
@@ -423,7 +434,7 @@ void tty_stop(finit_tty_t *tty)
|
|||||||
tty->pid = 0;
|
tty->pid = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tty_enabled(finit_tty_t *tty)
|
int tty_enabled(struct tty *tty)
|
||||||
{
|
{
|
||||||
if (!tty)
|
if (!tty)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -471,12 +482,12 @@ int tty_fallback(pid_t lost)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tty_action(tty_node_t *tty)
|
static void tty_action(struct tty *tty)
|
||||||
{
|
{
|
||||||
if (!tty_enabled(&tty->data))
|
if (!tty_enabled(tty))
|
||||||
tty_stop(&tty->data);
|
tty_stop(tty);
|
||||||
else
|
else
|
||||||
tty_start(&tty->data);
|
tty_start(tty);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -484,7 +495,7 @@ static void tty_action(tty_node_t *tty)
|
|||||||
*/
|
*/
|
||||||
int tty_respawn(pid_t pid)
|
int tty_respawn(pid_t pid)
|
||||||
{
|
{
|
||||||
tty_node_t *tty = tty_find_by_pid(pid);
|
struct tty *tty = tty_find_by_pid(pid);
|
||||||
|
|
||||||
if (!tty)
|
if (!tty)
|
||||||
return tty_fallback(pid);
|
return tty_fallback(pid);
|
||||||
@@ -493,7 +504,7 @@ int tty_respawn(pid_t pid)
|
|||||||
utmp_set_dead(pid);
|
utmp_set_dead(pid);
|
||||||
|
|
||||||
/* Clear PID to be able to respawn it. */
|
/* Clear PID to be able to respawn it. */
|
||||||
tty->data.pid = 0;
|
tty->pid = 0;
|
||||||
tty_action(tty);
|
tty_action(tty);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -504,7 +515,7 @@ int tty_respawn(pid_t pid)
|
|||||||
*/
|
*/
|
||||||
void tty_reload(char *dev)
|
void tty_reload(char *dev)
|
||||||
{
|
{
|
||||||
tty_node_t *tty;
|
struct tty *tty;
|
||||||
|
|
||||||
if (dev) {
|
if (dev) {
|
||||||
tty = tty_find(dev);
|
tty = tty_find(dev);
|
||||||
@@ -529,7 +540,7 @@ void tty_reload(char *dev)
|
|||||||
/* Start all TTYs that exist in the system and are allowed at this runlevel */
|
/* Start all TTYs that exist in the system and are allowed at this runlevel */
|
||||||
void tty_runlevel(void)
|
void tty_runlevel(void)
|
||||||
{
|
{
|
||||||
tty_node_t *tty;
|
struct tty *tty;
|
||||||
|
|
||||||
LIST_FOREACH(tty, &tty_list, link)
|
LIST_FOREACH(tty, &tty_list, link)
|
||||||
tty_action(tty);
|
tty_action(tty);
|
||||||
|
|||||||
@@ -32,10 +32,12 @@
|
|||||||
#define TTY_MAX_ARGS 16
|
#define TTY_MAX_ARGS 16
|
||||||
#define EVENT_SIZE ((sizeof(struct inotify_event) + NAME_MAX + 1))
|
#define EVENT_SIZE ((sizeof(struct inotify_event) + NAME_MAX + 1))
|
||||||
|
|
||||||
typedef struct {
|
struct tty {
|
||||||
char *name;
|
LIST_ENTRY(tty) link;
|
||||||
char *baud;
|
|
||||||
char *term;
|
char name[42];
|
||||||
|
char baud[10];
|
||||||
|
char term[10];
|
||||||
int noclear;
|
int noclear;
|
||||||
int nowait;
|
int nowait;
|
||||||
int nologin;
|
int nologin;
|
||||||
@@ -48,32 +50,24 @@ typedef struct {
|
|||||||
|
|
||||||
/* Limits and scoping */
|
/* Limits and scoping */
|
||||||
struct rlimit rlimit[RLIMIT_NLIMITS];
|
struct rlimit rlimit[RLIMIT_NLIMITS];
|
||||||
} finit_tty_t;
|
|
||||||
|
|
||||||
typedef struct tty_node {
|
/* Set if modified => reloaded, or -1 when marked for removal */
|
||||||
LIST_ENTRY(tty_node) link;
|
int dirty;
|
||||||
finit_tty_t data;
|
};
|
||||||
|
|
||||||
/* XXX: Yes, TTYs should be refactored into a separate SVC type. */
|
|
||||||
int dirty; /* Set if old mtime != new mtime => reloaded,
|
|
||||||
* or -1 when marked for removal */
|
|
||||||
} tty_node_t;
|
|
||||||
|
|
||||||
//extern LIST_HEAD(, tty_node) tty_list;
|
|
||||||
|
|
||||||
void tty_mark (void);
|
void tty_mark (void);
|
||||||
void tty_sweep (void);
|
void tty_sweep (void);
|
||||||
|
|
||||||
int tty_register (char *line, struct rlimit rlimit[], char *file);
|
int tty_register (char *line, struct rlimit rlimit[], char *file);
|
||||||
int tty_unregister (tty_node_t *tty);
|
int tty_unregister (struct tty *tty);
|
||||||
|
|
||||||
tty_node_t *tty_find (char *dev);
|
struct tty *tty_find (char *dev);
|
||||||
size_t tty_num (void);
|
size_t tty_num (void);
|
||||||
size_t tty_num_active (void);
|
size_t tty_num_active (void);
|
||||||
tty_node_t *tty_find_by_pid (pid_t pid);
|
struct tty *tty_find_by_pid (pid_t pid);
|
||||||
void tty_start (finit_tty_t *tty);
|
void tty_start (struct tty *tty);
|
||||||
void tty_stop (finit_tty_t *tty);
|
void tty_stop (struct tty *tty);
|
||||||
int tty_enabled (finit_tty_t *tty);
|
int tty_enabled (struct tty *tty);
|
||||||
int tty_respawn (pid_t pid);
|
int tty_respawn (pid_t pid);
|
||||||
void tty_reload (char *dev);
|
void tty_reload (char *dev);
|
||||||
void tty_runlevel (void);
|
void tty_runlevel (void);
|
||||||
|
|||||||
@@ -24,8 +24,11 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <ctype.h> /* isprint() */
|
#include <ctype.h> /* isprint() */
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <regex.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/sysinfo.h> /* sysinfo() */
|
#include <sys/sysinfo.h> /* sysinfo() */
|
||||||
#include <lite/lite.h> /* strlcat() */
|
#include <lite/lite.h> /* strlcat() */
|
||||||
@@ -46,6 +49,32 @@ char *progname(char *arg0)
|
|||||||
return prognm;
|
return prognm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int echo(char *file, int append, char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
if (!file)
|
||||||
|
fp = stdout;
|
||||||
|
else
|
||||||
|
fp = fopen(file, append ? "a" : "w");
|
||||||
|
if (!fp)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (fmt) {
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vfprintf(fp, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* echo(1) always adds a newline */
|
||||||
|
fprintf(fp, "\n");
|
||||||
|
if (file)
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int strtobytes(char *arg)
|
int strtobytes(char *arg)
|
||||||
{
|
{
|
||||||
int mod = 0, bytes;
|
int mod = 0, bytes;
|
||||||
@@ -77,7 +106,11 @@ int strtobytes(char *arg)
|
|||||||
|
|
||||||
void do_sleep(unsigned int sec)
|
void do_sleep(unsigned int sec)
|
||||||
{
|
{
|
||||||
while ((sec = sleep(sec)))
|
struct timespec requested_sleep = {
|
||||||
|
.tv_sec = sec,
|
||||||
|
.tv_nsec = 0,
|
||||||
|
};
|
||||||
|
while (nanosleep(&requested_sleep, &requested_sleep))
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,29 +165,29 @@ char *uptime(long secs, char *buf, size_t len)
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allowed characters in job/id/name */
|
/*
|
||||||
static int isallowed(int ch)
|
* Verify string argument is NUL terminated
|
||||||
{
|
* Verify string is a JOB[:ID], JOB and ID
|
||||||
return isprint(ch);
|
* can both be string or number, or combo.
|
||||||
}
|
*/
|
||||||
|
|
||||||
/* Sanitize user input, make sure to NUL terminate. */
|
|
||||||
char *sanitize(char *arg, size_t len)
|
char *sanitize(char *arg, size_t len)
|
||||||
{
|
{
|
||||||
size_t i = 0;
|
const char *regex = "[a-z0-9_]+[:]?[a-z0-9_]*";
|
||||||
|
regex_t preg;
|
||||||
|
int rc;
|
||||||
|
|
||||||
while (isallowed(arg[i]) && i < len)
|
if (strlen(arg) > len)
|
||||||
i++;
|
return NULL;
|
||||||
|
|
||||||
if (i + 1 < len) {
|
if (regcomp(&preg, regex, REG_ICASE | REG_EXTENDED))
|
||||||
arg[i + 1] = 0;
|
return NULL;
|
||||||
return arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i > 0 && arg[i] == 0)
|
rc = regexec(&preg, arg, 0, NULL, 0);
|
||||||
return arg;
|
regfree(&preg);
|
||||||
|
if (rc)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
return NULL;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ extern char *prognm;
|
|||||||
#include <lite/conio.h>
|
#include <lite/conio.h>
|
||||||
|
|
||||||
char *progname (char *arg0);
|
char *progname (char *arg0);
|
||||||
|
int echo (char *file, int append, char *fmt, ...);
|
||||||
int strtobytes (char *arg);
|
int strtobytes (char *arg);
|
||||||
void do_sleep (unsigned int sec);
|
void do_sleep (unsigned int sec);
|
||||||
|
|
||||||
@@ -51,6 +52,12 @@ void screen_init (void);
|
|||||||
void screen_exit (void);
|
void screen_exit (void);
|
||||||
int screen_width (void);
|
int screen_width (void);
|
||||||
|
|
||||||
|
static inline char *strterm(char *str, size_t len)
|
||||||
|
{
|
||||||
|
str[len - 1] = 0;
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* FINIT_UTIL_H_ */
|
#endif /* FINIT_UTIL_H_ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* Built-in watchdog daemon
|
/* Built-in watchdog daemon
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016 Joachim Nilsson <troglobit@gmail.com>
|
* Copyright (c) 2016-2018 Joachim Nilsson <troglobit@gmail.com>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -9,24 +9,30 @@
|
|||||||
* copies of the Software, and to permit persons to whom the Software is
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
* furnished to do so, subject to the following conditions:
|
* furnished to do so, subject to the following conditions:
|
||||||
*
|
*
|
||||||
* The above copyright notice and this permission notice shall be included in
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
* all copies or substantial portions of the Software.
|
* copies or substantial portions of the Software.
|
||||||
*
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
* 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
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* THE SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <syslog.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <linux/watchdog.h>
|
#include <linux/watchdog.h>
|
||||||
|
|
||||||
#include "finit.h"
|
|
||||||
#include "log.h"
|
|
||||||
#include "watchdog.h"
|
#include "watchdog.h"
|
||||||
|
|
||||||
int running = 1;
|
int running = 1;
|
||||||
@@ -51,6 +57,9 @@ static int init(char *progname, char *devnode)
|
|||||||
signal(SIGTERM, sighandler);
|
signal(SIGTERM, sighandler);
|
||||||
signal(SIGPWR, sighandler);
|
signal(SIGPWR, sighandler);
|
||||||
|
|
||||||
|
openlog(&progname[1], LOG_CONS | LOG_PID, LOG_DAEMON);
|
||||||
|
syslog(LOG_INFO, "Finit v%s basic watchdogd starting ...", VERSION);
|
||||||
|
|
||||||
fd = open(devnode, O_WRONLY);
|
fd = open(devnode, O_WRONLY);
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
return -1;
|
return -1;
|
||||||
@@ -78,6 +87,7 @@ static int loop(int fd, int timeout)
|
|||||||
|
|
||||||
/* External watchdogd wants to take over ... */
|
/* External watchdogd wants to take over ... */
|
||||||
if (handover) {
|
if (handover) {
|
||||||
|
syslog(LOG_INFO, "Handing over %s and exiting ...", WDT_DEVNODE);
|
||||||
ioctl(fd, WDIOC_KEEPALIVE, &dummy);
|
ioctl(fd, WDIOC_KEEPALIVE, &dummy);
|
||||||
return !write(fd, "V", 1);
|
return !write(fd, "V", 1);
|
||||||
}
|
}
|
||||||
@@ -85,34 +95,30 @@ static int loop(int fd, int timeout)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int watchdog(char *progname)
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int pid;
|
int fd, ret;
|
||||||
|
|
||||||
pid = fork();
|
fd = init(argv[0], WDT_DEVNODE);
|
||||||
if (pid == 0) {
|
if (fd == -1) {
|
||||||
int fd, ret;
|
if (ENOENT != errno)
|
||||||
|
syslog(LOG_CRIT, "Failed connecting to watchdog %s", WDT_DEVNODE);
|
||||||
fd = init(progname, WDT_DEVNODE);
|
return 1;
|
||||||
if (fd == -1) {
|
|
||||||
_pe("Failed connecting to watchdog %s", WDT_DEVNODE);
|
|
||||||
_exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = loop(fd, WDT_TIMEOUT);
|
|
||||||
while (!handover) {
|
|
||||||
/* Waiting for SIGTERM ... */
|
|
||||||
sleep(1);
|
|
||||||
|
|
||||||
/* Set lowest possible timeout on SIGTERM */
|
|
||||||
ioctl(fd, WDIOC_SETTIMEOUT, &shutdown);
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
_exit(ret);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return pid;
|
ret = loop(fd, WDT_TIMEOUT);
|
||||||
|
while (!handover) {
|
||||||
|
syslog(LOG_ALERT, "System going down ...");
|
||||||
|
|
||||||
|
/* Waiting for SIGTERM ... */
|
||||||
|
sleep(1);
|
||||||
|
|
||||||
|
/* Set lowest possible timeout on SIGTERM */
|
||||||
|
ioctl(fd, WDIOC_SETTIMEOUT, &shutdown);
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||