mirror of
https://github.com/troglobit/finit.git
synced 2026-10-14 10:19:36 +00:00
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 |
No files matched your search
File renamed without changes.
@@ -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]
|
||||||
+8
-6
@@ -9,14 +9,16 @@ sudo: false
|
|||||||
#sudo: true
|
#sudo: true
|
||||||
|
|
||||||
# Test build with both GCC and Clang (LLVM)
|
# Test build with both GCC and Clang (LLVM)
|
||||||
# - clang
|
|
||||||
compiler:
|
compiler:
|
||||||
- gcc
|
- gcc
|
||||||
|
- clang
|
||||||
|
|
||||||
|
# The secure: declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||||
|
# via the "travis encrypt" command using the project repo's public key
|
||||||
env:
|
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,7 +30,7 @@ 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
|
||||||
|
|
||||||
@@ -43,10 +45,10 @@ install:
|
|||||||
# 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 --disable-inetd --enable-static
|
- ./configure --prefix=/tmp --disable-inetd --enable-static
|
||||||
- make clean
|
- make clean
|
||||||
- make V=1 -j5
|
- make V=1 -j5
|
||||||
- PKG_CONFIG_PATH=/tmp/lib/pkgconfig ./configure --prefix=/tmp --enable-inetd-echo-plugin --enable-inetd-time-plugin --enable-x11-common-plugin --enable-inetd-chargen-plugin --enable-fallback-shell --enable-watchdog
|
- ./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 V=1 -j5
|
- make V=1 -j5
|
||||||
|
|||||||
+62
-8
@@ -4,14 +4,25 @@ Change Log
|
|||||||
All relevant changes are documented in this file.
|
All relevant changes are documented in this file.
|
||||||
|
|
||||||
|
|
||||||
[3.2][UNRELEASED] - 2018-10-xx
|
[3.2][UNRELEASED] - 2020-04-xx
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
Bug fix release.
|
Bug fix release, but also cgroups and a new progress!
|
||||||
|
|
||||||
|
https://twitter.com/b0rk/status/1214341831049252870?s=20
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
* Add support for `--disable-docs` and `--disable-contrib` to speed up
|
* 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
|
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`
|
* Add `-b`, batch mode, for non-interactive use to `initctl`
|
||||||
* Prefer udev to handle `/dev/` if mdev is also available
|
* Prefer udev to handle `/dev/` if mdev is also available
|
||||||
* Redirect dbus daemon output to syslog
|
* Redirect dbus daemon output to syslog
|
||||||
@@ -19,7 +30,7 @@ Bug fix release.
|
|||||||
* Finit no longer automatically reloads its `*.conf` files after running
|
* Finit no longer automatically reloads its `*.conf` files after running
|
||||||
`/etc/rc.local` or run-parts. Use `initctl reload` instead.
|
`/etc/rc.local` or run-parts. Use `initctl reload` instead.
|
||||||
* `initctl` without an argument or option now defaults to list services
|
* `initctl` without an argument or option now defaults to list services
|
||||||
* Converted built-in watchdog daemon to standalone mini watchdogd
|
* Convert built-in watchdog daemon to standalone mini watchdogd, issue #102
|
||||||
* Improved watchdog hand-over, now based on `svc_t` and not PID
|
* Improved watchdog hand-over, now based on `svc_t` and not PID
|
||||||
* Extended bootstrap, runlevel S, timeout: 10 --> 120 sec. before services
|
* Extended bootstrap, runlevel S, timeout: 10 --> 120 sec. before services
|
||||||
not allowed in the runtime runlevel are unconditionally stopped
|
not allowed in the runtime runlevel are unconditionally stopped
|
||||||
@@ -32,7 +43,35 @@ Bug fix release.
|
|||||||
event, because services may depend on each other
|
event, because services may depend on each other
|
||||||
* Require new libuEv API: `uev_init1()` to reduce event cache so that
|
* Require new libuEv API: `uev_init1()` to reduce event cache so that
|
||||||
the kernel can invalidate deleted events before enqueing to userspace
|
the kernel can invalidate deleted events before 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
|
### Fixes
|
||||||
|
|
||||||
* Fix #96: Start udevd as a proper service
|
* Fix #96: Start udevd as a proper service
|
||||||
@@ -50,18 +89,29 @@ Bug fix release.
|
|||||||
that do not have a watchdog
|
that do not have a watchdog
|
||||||
* Fix #100: Early condition handling may not work if `/var/run` does
|
* Fix #100: Early condition handling may not work if `/var/run` does
|
||||||
not yet exist (symlink to `/run`). Added compat layer for access
|
not yet exist (symlink to `/run`). Added compat layer for access
|
||||||
* Fix #103: Register multiple getty if `@console` resolves to >1 TTY
|
* Fix #103: Register multiple getty if `@console` resolves to >1 TTY,
|
||||||
* Fix #105: Only remove /etc/nologin when moving from runlevel 0, 1, 6
|
* Fix #105: Only remove /etc/nologin when moving from runlevel 0, 1, 6
|
||||||
* Fix #106: Don't mark inetd connections for deletion at .conf reload.
|
* Fix #106: Don't mark inetd connections for deletion at .conf reload.
|
||||||
Fixed by Jonas Johansson, Westermo
|
Fixed by Jonas Johansson, Westermo
|
||||||
* Fix #107: Stop spawned inetd conncections when stopping inetd service.
|
* Fix #107: Stop spawned inetd conncections when stopping inetd service.
|
||||||
Fixed by Jonas Johansson, Westermo
|
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
|
* Fix #111: Only restart inetd services when necessary. E.g., if the
|
||||||
listening interface is changed. Only stop established connections
|
listening interface is changed. Only stop established connections
|
||||||
which are no longer allowed, i.e. do not touch already allowed
|
which are no longer allowed, i.e. do not touch already allowed
|
||||||
established connections. Fixed by Jonas Johansson, Westermo
|
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
|
* Fix: update inetd service args on config change. Found and fixed by
|
||||||
Petrus Hellgren, Westermo
|
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
|
* Fix `initctl [start | restart]`, should behave the same for services
|
||||||
that have crashed. Found by Mattias Walström, Westermo
|
that have crashed. Found by Mattias Walström, Westermo
|
||||||
* Wait for bootstrap phase to complete before cleaning out any bootstrap
|
* Wait for bootstrap phase to complete before cleaning out any bootstrap
|
||||||
@@ -69,7 +119,11 @@ Bug fix release.
|
|||||||
* Reassert condition when an unmodified run/task/service goes from
|
* Reassert condition when an unmodified run/task/service goes from
|
||||||
WAITING back to RUNNING again after a reconfiguration event.
|
WAITING back to RUNNING again after a reconfiguration event.
|
||||||
Found and fixed by Jonas Johansson, Westermo
|
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
|
* 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
|
||||||
@@ -144,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
|
||||||
|
|
||||||
@@ -207,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
|
||||||
|
|||||||
+2
-2
@@ -6,8 +6,8 @@ EXTRA_DIST = README.md LICENSE ChangeLog.md contrib/finit.conf
|
|||||||
if CONTRIB
|
if CONTRIB
|
||||||
SUBDIRS += contrib
|
SUBDIRS += contrib
|
||||||
endif
|
endif
|
||||||
if DOCS
|
if DOC
|
||||||
SUBDIRS += docs
|
SUBDIRS += doc
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Compat hook
|
# Compat hook
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
+42
-18
@@ -1,4 +1,4 @@
|
|||||||
AC_INIT(Finit, 3.2-rc1, 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,6 +40,9 @@ 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.2.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])
|
||||||
@@ -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,13 +81,17 @@ 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(docs,
|
AC_ARG_ENABLE(doc,
|
||||||
AS_HELP_STRING([--disable-docs], [Disable build and install of docs section]),,[
|
AS_HELP_STRING([--disable-doc], [Disable build and install of doc/ section]),,[
|
||||||
enable_docs=yes])
|
enable_doc=yes])
|
||||||
|
|
||||||
AC_ARG_ENABLE(contrib,
|
AC_ARG_ENABLE(contrib,
|
||||||
AS_HELP_STRING([--disable-contrib], [Disable build and install of contrib section]),,[
|
AS_HELP_STRING([--disable-contrib], [Disable build and install of contrib section]),,[
|
||||||
@@ -95,6 +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([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.])
|
||||||
@@ -136,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
|
||||||
@@ -146,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])])
|
||||||
@@ -165,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.])])
|
||||||
|
|
||||||
@@ -223,7 +245,8 @@ 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(DOCS, [test "x$enable_docs" = "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"])
|
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
|
||||||
@@ -263,15 +286,16 @@ Behavior:
|
|||||||
Plugins...............: $plugins
|
Plugins...............: $plugins
|
||||||
|
|
||||||
Optional features:
|
Optional features:
|
||||||
Install docs/.........: $enable_docs
|
Install doc/..........: $enable_doc
|
||||||
Install contrib/......: $enable_contrib
|
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 \
|
||||||
|
|||||||
@@ -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 \
|
||||||
|
|||||||
@@ -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 \
|
||||||
|
|||||||
@@ -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
|
||||||
File renamed without changes.
@@ -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)
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
config.md
|
||||||
@@ -21,6 +21,9 @@ can also be used.
|
|||||||
Near Future
|
Near Future
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
* When a process dies, and Finit does not restart it, we should collect
|
||||||
|
a `siginfo_t` from the SIGCHLD signal and supply to the user in case
|
||||||
|
`initctl status <process>` is called to debug the issue.
|
||||||
* Merge UDP redirect service uredir as an UDP inetd variant
|
* 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
|
||||||
@@ -30,8 +33,6 @@ Near Future
|
|||||||
* Cron/At support, see below
|
* Cron/At support, see below
|
||||||
* Write man pages for finit and `finit.conf`, steal from the excellent
|
* Write man pages for finit and `finit.conf`, steal from the excellent
|
||||||
`pimd` man pages ...
|
`pimd` man pages ...
|
||||||
* Add simple, *very* simple, `finit-simple.conf` example. To illustrate
|
|
||||||
how close Finit3 still is to the original easy-to-use Finit0 :)
|
|
||||||
|
|
||||||
|
|
||||||
General
|
General
|
||||||
@@ -59,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
|
||||||
----
|
----
|
||||||
@@ -114,5 +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`
|
||||||
|
|
||||||
|
|
||||||
[Solaris SMF]: http://www.oracle.com/technetwork/articles/servers-storage-admin/intro-smf-basics-s11-1729181.html
|
|
||||||
@@ -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.
|
||||||
@@ -73,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
|
||||||
File renamed without changes.
@@ -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,6 +395,7 @@ 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
|
||||||
|
|
||||||
File renamed without changes.
File renamed without changes.
@@ -42,11 +42,12 @@ 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.
|
||||||
|
|
||||||
|
* *modules-load.so*: Scans /etc/modules-load.d for modules to modprobe.
|
||||||
|
|
||||||
* *netlink.so*: Listens to Linux kernel Netlink events for gateway and
|
* *netlink.so*: Listens to Linux kernel Netlink events for gateway and
|
||||||
interfaces. These events are then sent to the Finit service monitor
|
interfaces. These events are then sent to the Finit service monitor
|
||||||
for services that may want to be SIGHUP'ed on new default route or
|
for services that may want to be SIGHUP'ed on new default route or
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+10
-2
@@ -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,6 +39,10 @@ libplug_la_SOURCES += time.c
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if BUILD_MODULES_LOAD_PLUGIN
|
||||||
|
libplug_la_SOURCES += modules-load.c
|
||||||
|
endif
|
||||||
|
|
||||||
if BUILD_NETLINK_PLUGIN
|
if BUILD_NETLINK_PLUGIN
|
||||||
libplug_la_SOURCES += netlink.c
|
libplug_la_SOURCES += netlink.c
|
||||||
endif
|
endif
|
||||||
@@ -48,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
|
||||||
@@ -80,6 +84,10 @@ pkglib_LTLIBRARIES += time.la
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if BUILD_MODULES_LOAD_PLUGIN
|
||||||
|
pkglib_LTLIBRARIES += modules-load.la
|
||||||
|
endif
|
||||||
|
|
||||||
if BUILD_NETLINK_PLUGIN
|
if BUILD_NETLINK_PLUGIN
|
||||||
pkglib_LTLIBRARIES += netlink.la
|
pkglib_LTLIBRARIES += netlink.la
|
||||||
endif
|
endif
|
||||||
|
|||||||
+1
-1
@@ -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] log:prio:daemon.info,tag:dbus %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:
|
||||||
|
*/
|
||||||
+222
-40
@@ -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,55 +22,237 @@
|
|||||||
* 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 wd_entry {
|
||||||
|
TAILQ_ENTRY(wd_entry) link;
|
||||||
|
char *path;
|
||||||
|
int fd;
|
||||||
|
};
|
||||||
|
|
||||||
struct context {
|
struct context {
|
||||||
int fd;
|
int fd;
|
||||||
int wd;
|
TAILQ_HEAD(, wd_entry) wd_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct context pidfile_ctx;
|
||||||
|
|
||||||
|
static int watcher_add(struct context *ctx, char *path)
|
||||||
|
{
|
||||||
|
struct wd_entry *wd;
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -91,7 +274,7 @@ static void pidfile_reconf(void *arg)
|
|||||||
if (svc_is_changed(svc) || svc_is_starting(svc))
|
if (svc_is_changed(svc) || svc_is_starting(svc))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
mkcond(cond, sizeof(cond), svc->cmd);
|
mkcond(svc, cond, sizeof(cond));
|
||||||
if (cond_get(cond) == COND_ON)
|
if (cond_get(cond) == COND_ON)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -110,7 +293,6 @@ static void pidfile_reconf(void *arg)
|
|||||||
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.
|
||||||
@@ -123,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");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,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,
|
||||||
@@ -166,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);
|
||||||
|
|||||||
+160
@@ -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:
|
||||||
|
*/
|
||||||
+6
-3
@@ -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,16 +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
|
if WATCHDOGD
|
||||||
pkglibexec_PROGRAMS = watchdogd
|
pkglibexec_PROGRAMS = watchdogd
|
||||||
endif
|
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 \
|
||||||
|
|||||||
@@ -93,27 +93,26 @@ 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(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[13] = "";
|
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,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)
|
||||||
@@ -132,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);
|
||||||
}
|
}
|
||||||
@@ -164,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;
|
||||||
@@ -299,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;
|
||||||
@@ -352,8 +327,8 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
if (wdog) {
|
if (wdog) {
|
||||||
logit(LOG_NOTICE, "Stopping and removing %s (PID:%d)", wdog->cmd, wdog->pid);
|
logit(LOG_NOTICE, "Stopping and removing %s (PID:%d)", wdog->cmd, wdog->pid);
|
||||||
stop(wdog);
|
stop(wdog);
|
||||||
if (wdog->protected) {
|
if (wdog->protect) {
|
||||||
wdog->protected = 0;
|
wdog->protect = 0;
|
||||||
wdog->runlevels = 0;
|
wdog->runlevels = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -373,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;
|
||||||
|
|
||||||
|
|||||||
Executable
+11
@@ -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
|
||||||
+140
@@ -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:
|
||||||
|
*/
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/* Save and restore RTC using hwclock
|
/* Finit control group support functions
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012 Joachim Nilsson <troglobit@gmail.com>
|
* Copyright (c) 2019 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,12 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <lite/lite.h>
|
#ifndef FINIT_CGROUP_H_
|
||||||
|
#define FINIT_CGROUP_H_
|
||||||
|
|
||||||
#include "finit.h"
|
void cgroup_init (void);
|
||||||
#include "helpers.h"
|
|
||||||
#include "plugin.h"
|
|
||||||
|
|
||||||
static void save(void *arg)
|
int cgroup_user (char *name);
|
||||||
{
|
int cgroup_service (char *cmd, char *id, int pid);
|
||||||
_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)
|
#endif /* FINIT_CGROUP_H_ */
|
||||||
{
|
|
||||||
_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)
|
|
||||||
{
|
|
||||||
plugin_register(&plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
|
||||||
{
|
|
||||||
plugin_unregister(&plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Local Variables:
|
|
||||||
* indent-tabs-mode: t
|
|
||||||
* c-file-style: "linux"
|
|
||||||
* End:
|
|
||||||
*/
|
|
||||||
+1
-1
@@ -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 = {
|
||||||
|
|||||||
+1
-1
@@ -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_ */
|
||||||
+82
-1
@@ -31,6 +31,86 @@
|
|||||||
#include "pid.h"
|
#include "pid.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
static int cond_set_gen(const char *file, unsigned int gen)
|
||||||
{
|
{
|
||||||
char *ptr, path[256];
|
char *ptr, path[256];
|
||||||
@@ -128,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:
|
||||||
@@ -171,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;
|
||||||
|
|||||||
+6
-13
@@ -29,13 +29,6 @@
|
|||||||
#include "pid.h"
|
#include "pid.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
|
|
||||||
|
|
||||||
char *mkcond(char *buf, size_t len, char *nm)
|
|
||||||
{
|
|
||||||
snprintf(buf, len, "svc%s%s", nm[0] != '/' ? "/" : "", nm);
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *condstr(enum cond_state s)
|
const char *condstr(enum cond_state s)
|
||||||
{
|
{
|
||||||
static const char *strs[] = {
|
static const char *strs[] = {
|
||||||
@@ -49,18 +42,18 @@ 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 *file)
|
unsigned int cond_get_gen(const char *file)
|
||||||
{
|
{
|
||||||
char *ptr, path[256];
|
|
||||||
unsigned int gen;
|
unsigned int gen;
|
||||||
|
char *ptr, path[256];
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -99,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;
|
||||||
@@ -115,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
-1
@@ -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,7 +14,7 @@ typedef enum cond_state {
|
|||||||
COND_ON
|
COND_ON
|
||||||
} cond_state_t;
|
} cond_state_t;
|
||||||
|
|
||||||
char *mkcond (char *buf, size_t len, char *nm);
|
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);
|
||||||
|
|||||||
+27
-19
@@ -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);
|
||||||
@@ -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);
|
||||||
@@ -783,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)
|
||||||
@@ -835,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;
|
||||||
}
|
}
|
||||||
@@ -857,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();
|
||||||
}
|
}
|
||||||
@@ -869,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);
|
||||||
}
|
}
|
||||||
|
|||||||
+40
-37
@@ -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 && baud[0]) {
|
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);
|
||||||
|
|||||||
+55
-18
@@ -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"
|
||||||
@@ -72,9 +73,6 @@ static int udev = 0; /* Runtime detection of udev */
|
|||||||
*/
|
*/
|
||||||
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;
|
||||||
@@ -83,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, "\n\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)
|
||||||
@@ -222,7 +219,7 @@ static void finalize(void)
|
|||||||
/*
|
/*
|
||||||
* Track bundled watchdogd in case a better one turns up
|
* Track bundled watchdogd in case a better one turns up
|
||||||
*/
|
*/
|
||||||
svc = svc_find(FINIT_LIBPATH_ "/watchdogd", 1);
|
svc = svc_find(FINIT_LIBPATH_ "/watchdogd", "1");
|
||||||
if (svc)
|
if (svc)
|
||||||
wdog = svc;
|
wdog = svc;
|
||||||
|
|
||||||
@@ -308,7 +305,7 @@ static void final_worker(void *work)
|
|||||||
finalize();
|
finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct wq crank = {
|
struct wq crank = {
|
||||||
.cb = crank_worker
|
.cb = crank_worker
|
||||||
@@ -328,6 +325,19 @@ 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.
|
||||||
*/
|
*/
|
||||||
@@ -345,11 +355,18 @@ int main(int argc, char* argv[])
|
|||||||
*/
|
*/
|
||||||
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
|
||||||
@@ -404,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
|
||||||
@@ -416,14 +433,14 @@ 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 */
|
/* Bootstrap conditions, needed for hooks */
|
||||||
@@ -475,16 +492,36 @@ int main(int argc, char* argv[])
|
|||||||
* Start bundled watchdogd as soon as possible, if enabled
|
* Start bundled watchdogd as soon as possible, if enabled
|
||||||
*/
|
*/
|
||||||
if (which(FINIT_LIBPATH_ "/watchdogd"))
|
if (which(FINIT_LIBPATH_ "/watchdogd"))
|
||||||
service_register(SVC_TYPE_SERVICE, FINIT_LIBPATH_ "/watchdogd", global_rlimit, NULL);
|
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
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -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 */
|
||||||
|
|||||||
+9
-5
@@ -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,10 +241,6 @@ 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. */
|
|
||||||
stty(fd, speed);
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
if (term && term[0])
|
if (term && term[0])
|
||||||
setenv("TERM", term, 1);
|
setenv("TERM", term, 1);
|
||||||
|
|
||||||
|
|||||||
+132
-32
@@ -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);
|
||||||
|
|||||||
+4
-1
@@ -169,6 +169,7 @@ 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 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);
|
||||||
@@ -194,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)
|
||||||
@@ -226,6 +228,7 @@ static void socket_cb(uev_t *w, void *arg, int events)
|
|||||||
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->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);
|
||||||
|
|||||||
+91
-37
@@ -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,6 +490,71 @@ 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,
|
||||||
@@ -538,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"
|
||||||
@@ -550,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"
|
||||||
@@ -590,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 },
|
||||||
@@ -647,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,6 +31,7 @@ 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);
|
||||||
|
|
||||||
@@ -46,8 +47,9 @@ int pid_file_parse (svc_t *svc, char *arg);
|
|||||||
*/
|
*/
|
||||||
static inline char *pid_runpath(const char *file, char *path, size_t len)
|
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"))
|
||||||
@@ -60,7 +62,9 @@ static inline char *pid_runpath(const 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;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -33,7 +33,7 @@ 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);
|
||||||
|
|||||||
+10
-7
@@ -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,8 @@ 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])
|
if (!arg || !arg[0])
|
||||||
return serv_list(NULL);
|
return serv_list(NULL);
|
||||||
@@ -140,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);
|
||||||
|
|
||||||
@@ -154,7 +157,7 @@ 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])
|
if (!arg || !arg[0])
|
||||||
@@ -165,7 +168,7 @@ int serv_disable(char *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);
|
||||||
|
|
||||||
|
|||||||
+380
-134
@@ -32,6 +32,7 @@
|
|||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <lite/lite.h>
|
#include <lite/lite.h>
|
||||||
|
|
||||||
|
#include "cgroup.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
@@ -115,16 +116,166 @@ static int service_timeout_cancel(svc_t *svc)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void redirect_null(void)
|
/*
|
||||||
|
* Redirect stdin to /dev/null => all reads by process = EOF
|
||||||
|
* https://www.freedesktop.org/software/systemd/man/systemd.exec.html#Logging%20and%20Standard%20Input/Output
|
||||||
|
*/
|
||||||
|
static int stdin_redirect(void)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
int fd;
|
||||||
|
|
||||||
fp = fopen("/dev/null", "w");
|
fd = open("/dev/null", O_RDONLY | O_APPEND);
|
||||||
if (fp) {
|
if (-1 != fd) {
|
||||||
dup2(fileno(fp), STDOUT_FILENO);
|
dup2(fd, STDIN_FILENO);
|
||||||
dup2(fileno(fp), STDERR_FILENO);
|
return close(fd);
|
||||||
fclose(fp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Redirect output to a file, e.g., /dev/null, or /dev/console
|
||||||
|
*/
|
||||||
|
static int fredirect(const char *file)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = open(file, O_WRONLY | O_APPEND);
|
||||||
|
if (-1 != fd) {
|
||||||
|
dup2(fd, STDOUT_FILENO);
|
||||||
|
dup2(fd, STDERR_FILENO);
|
||||||
|
return close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef LOGIT_ENABLED
|
||||||
|
/*
|
||||||
|
* Fallback in case we don't even have logger on the system.
|
||||||
|
* XXX: we should parse 'prio' here to get facility.level
|
||||||
|
*/
|
||||||
|
static void fallback_logger(char *ident, char *prio)
|
||||||
|
{
|
||||||
|
int facility = LOG_DAEMON;
|
||||||
|
int level = LOG_NOTICE;
|
||||||
|
char buf[256];
|
||||||
|
|
||||||
|
openlog(ident, LOG_NOWAIT | LOG_PID, facility);
|
||||||
|
while ((fgets(buf, sizeof(buf), stdin)))
|
||||||
|
syslog(level, "%s", buf);
|
||||||
|
|
||||||
|
closelog();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Redirect output to syslog using the command line logit tool
|
||||||
|
*/
|
||||||
|
static int lredirect(svc_t *svc)
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open PTY to connect to logger. A pty isn't buffered
|
||||||
|
* like a pipe, and it eats newlines so they aren't logged
|
||||||
|
*/
|
||||||
|
fd = posix_openpt(O_RDWR);
|
||||||
|
if (fd == -1) {
|
||||||
|
svc->log.enabled = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (grantpt(fd) == -1 || unlockpt(fd) == -1) {
|
||||||
|
close(fd);
|
||||||
|
svc->log.enabled = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dup2(fd, STDOUT_FILENO);
|
||||||
|
dup2(fd, STDERR_FILENO);
|
||||||
|
|
||||||
|
pid = fork();
|
||||||
|
if (pid == 0) {
|
||||||
|
int fds;
|
||||||
|
char *tag = basename(svc->cmd);
|
||||||
|
char *prio = "daemon.info";
|
||||||
|
|
||||||
|
fds = open(ptsname(fd), O_RDONLY);
|
||||||
|
close(fd);
|
||||||
|
if (fds == -1)
|
||||||
|
_exit(0);
|
||||||
|
dup2(fds, STDIN_FILENO);
|
||||||
|
|
||||||
|
/* Reset signals */
|
||||||
|
sig_unblock();
|
||||||
|
|
||||||
|
if (svc->log.file[0] == '/') {
|
||||||
|
#ifdef LOGIT_ENABLED
|
||||||
|
char sz[20], num[3];
|
||||||
|
|
||||||
|
snprintf(sz, sizeof(sz), "%d", logfile_size_max);
|
||||||
|
snprintf(num, sizeof(num), "%d", logfile_count_max);
|
||||||
|
|
||||||
|
execlp("logit", "logit", "-f", svc->log.file, "-n", sz, "-r", num, NULL);
|
||||||
|
_exit(0);
|
||||||
|
#else
|
||||||
|
logit(LOG_INFO, "logit disabled, logging %s to syslog instead", svc->name);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (svc->log.ident[0])
|
||||||
|
tag = svc->log.ident;
|
||||||
|
if (svc->log.prio[0])
|
||||||
|
prio = svc->log.prio;
|
||||||
|
|
||||||
|
#ifdef LOGIT_ENABLED
|
||||||
|
execlp("logit", "logit", "-t", tag, "-p", prio, NULL);
|
||||||
|
#else
|
||||||
|
if (whichp("logger"))
|
||||||
|
execlp("logger", "logger", "-t", tag, "-p", prio, NULL);
|
||||||
|
|
||||||
|
fallback_logger(tag, prio);
|
||||||
|
#endif
|
||||||
|
_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle redirection of process output, if enabled
|
||||||
|
*/
|
||||||
|
static int redirect(svc_t *svc)
|
||||||
|
{
|
||||||
|
/* Redirect inetd socket to stdin for connection */
|
||||||
|
#ifdef INETD_ENABLED
|
||||||
|
if (svc_is_inetd_conn(svc)) {
|
||||||
|
dup2(svc->stdin_fd, STDIN_FILENO);
|
||||||
|
close(svc->stdin_fd);
|
||||||
|
dup2(STDIN_FILENO, STDOUT_FILENO);
|
||||||
|
dup2(STDIN_FILENO, STDERR_FILENO);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
stdin_redirect();
|
||||||
|
|
||||||
|
if (svc->log.enabled) {
|
||||||
|
if (svc->log.null)
|
||||||
|
return fredirect("/dev/null");
|
||||||
|
if (svc->log.console)
|
||||||
|
return fredirect(CONSOLE);
|
||||||
|
|
||||||
|
return lredirect(svc);
|
||||||
|
} else if (log_is_debug())
|
||||||
|
return fredirect(CONSOLE);
|
||||||
|
#ifdef REDIRECT_OUTPUT
|
||||||
|
else
|
||||||
|
return fredirect("/dev/null");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_norespawn(void)
|
static int is_norespawn(void)
|
||||||
@@ -139,7 +290,7 @@ static int is_norespawn(void)
|
|||||||
* @svc: Service to start
|
* @svc: Service to start
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* 0 if the service was successfully started. Non-zero otherwise.
|
* 0 if the service was successfully started. Non-zero otherwise.
|
||||||
*/
|
*/
|
||||||
static int service_start(svc_t *svc)
|
static int service_start(svc_t *svc)
|
||||||
{
|
{
|
||||||
@@ -156,7 +307,7 @@ static int service_start(svc_t *svc)
|
|||||||
|
|
||||||
/* Don't try and start service if it doesn't exist. */
|
/* Don't try and start service if it doesn't exist. */
|
||||||
if (!whichp(svc->cmd) && !svc->inetd.cmd) {
|
if (!whichp(svc->cmd) && !svc->inetd.cmd) {
|
||||||
print(1, "Service %s does not exist!", svc->cmd);
|
print(1, "Service %s does not exist", svc->cmd);
|
||||||
svc_missing(svc);
|
svc_missing(svc);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -165,12 +316,15 @@ static int service_start(svc_t *svc)
|
|||||||
if (svc_is_inetd(svc))
|
if (svc_is_inetd(svc))
|
||||||
return inetd_start(&svc->inetd);
|
return inetd_start(&svc->inetd);
|
||||||
#endif
|
#endif
|
||||||
|
if (svc_is_sysv(svc)) {
|
||||||
|
logit(LOG_CONSOLE | LOG_NOTICE, "Calling '%s start' ...", svc->cmd);
|
||||||
|
}
|
||||||
|
|
||||||
if (!svc->desc[0])
|
if (!svc->desc[0])
|
||||||
do_progress = 0;
|
do_progress = 0;
|
||||||
|
|
||||||
if (do_progress) {
|
if (do_progress) {
|
||||||
if (svc_is_daemon(svc))
|
if (svc_is_daemon(svc) || svc_is_sysv(svc))
|
||||||
print_desc("Starting ", svc->desc);
|
print_desc("Starting ", svc->desc);
|
||||||
else
|
else
|
||||||
print_desc("", svc->desc);
|
print_desc("", svc->desc);
|
||||||
@@ -185,6 +339,8 @@ static int service_start(svc_t *svc)
|
|||||||
sigprocmask(SIG_BLOCK, &nmask, &omask);
|
sigprocmask(SIG_BLOCK, &nmask, &omask);
|
||||||
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
|
cgroup_service(svc->name, svc->id, pid);
|
||||||
|
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
int status;
|
int status;
|
||||||
char *home = NULL;
|
char *home = NULL;
|
||||||
@@ -221,99 +377,31 @@ static int service_start(svc_t *svc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Serve copy of args to process in case it modifies them. */
|
if (!svc_is_sysv(svc)) {
|
||||||
for (i = 0; i < (MAX_NUM_SVC_ARGS - 1) && svc->args[i][0] != 0; i++)
|
for (i = 0; i < (MAX_NUM_SVC_ARGS - 1) && svc->args[i][0] != 0; i++)
|
||||||
args[i] = svc->args[i];
|
args[i] = svc->args[i];
|
||||||
|
} else {
|
||||||
|
i = 0;
|
||||||
|
args[i++] = svc->cmd;
|
||||||
|
args[i++] = "start";
|
||||||
|
}
|
||||||
args[i] = NULL;
|
args[i] = NULL;
|
||||||
|
|
||||||
/* Redirect inetd socket to stdin for connection */
|
/*
|
||||||
#ifdef INETD_ENABLED
|
* The setsid() call is the most humble of all in this
|
||||||
if (svc_is_inetd_conn(svc)) {
|
* function. It takes care to detach the process from
|
||||||
dup2(svc->stdin_fd, STDIN_FILENO);
|
* its controlling terminal, preventing daemons from
|
||||||
close(svc->stdin_fd);
|
* leaking to the console, and allowing us to run such
|
||||||
dup2(STDIN_FILENO, STDOUT_FILENO);
|
* programs like `lxc-start -F` in the foreground to
|
||||||
dup2(STDIN_FILENO, STDERR_FILENO);
|
* properly monitor them.
|
||||||
} else
|
*
|
||||||
#endif
|
* If you find yourself here wanting to fix the output
|
||||||
|
* to the console at boot, for debugging or similar,
|
||||||
|
* have a look at redirect() and log.console instead.
|
||||||
|
*/
|
||||||
|
setsid();
|
||||||
|
|
||||||
if (svc->log.enabled) {
|
redirect(svc);
|
||||||
int fd;
|
|
||||||
|
|
||||||
if (svc->log.null) {
|
|
||||||
redirect_null();
|
|
||||||
goto logit_done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Open PTY to connect to logger. A pty isn't buffered
|
|
||||||
* like a pipe, and it eats newlines so they aren't logged
|
|
||||||
*/
|
|
||||||
fd = posix_openpt(O_RDWR);
|
|
||||||
if (fd == -1) {
|
|
||||||
svc->log.enabled = 0;
|
|
||||||
goto logit_done;
|
|
||||||
}
|
|
||||||
if (grantpt(fd) == -1 || unlockpt(fd) == -1) {
|
|
||||||
close(fd);
|
|
||||||
svc->log.enabled = 0;
|
|
||||||
goto logit_done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* SIGCHLD is still blocked for grantpt() and fork() */
|
|
||||||
sigprocmask(SIG_BLOCK, &nmask, NULL);
|
|
||||||
pid = fork();
|
|
||||||
if (pid == 0) {
|
|
||||||
int fds;
|
|
||||||
char *tag = basename(svc->cmd);
|
|
||||||
char *prio = "daemon.info";
|
|
||||||
|
|
||||||
fds = open(ptsname(fd), O_RDONLY);
|
|
||||||
close(fd);
|
|
||||||
if (fds == -1)
|
|
||||||
_exit(0);
|
|
||||||
dup2(fds, STDIN_FILENO);
|
|
||||||
|
|
||||||
/* Reset signals */
|
|
||||||
sig_unblock();
|
|
||||||
|
|
||||||
if (svc->log.file[0] == '/') {
|
|
||||||
char sz[20], num[3];
|
|
||||||
|
|
||||||
snprintf(sz, sizeof(sz), "%d", logfile_size_max);
|
|
||||||
snprintf(num, sizeof(num), "%d", logfile_count_max);
|
|
||||||
|
|
||||||
execlp("logit", "logit", "-f", svc->log.file, "-n", sz, "-r", num, NULL);
|
|
||||||
_exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (svc->log.ident[0])
|
|
||||||
tag = svc->log.ident;
|
|
||||||
if (svc->log.prio[0])
|
|
||||||
prio = svc->log.prio;
|
|
||||||
|
|
||||||
execlp("logit", "logit", "-t", tag, "-p", prio, NULL);
|
|
||||||
_exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
dup2(fd, STDOUT_FILENO);
|
|
||||||
dup2(fd, STDERR_FILENO);
|
|
||||||
close(fd);
|
|
||||||
} else if (log_is_debug()) {
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
fd = open(CONSOLE, O_WRONLY | O_APPEND);
|
|
||||||
if (-1 != fd) {
|
|
||||||
dup2(fd, STDOUT_FILENO);
|
|
||||||
dup2(fd, STDERR_FILENO);
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef REDIRECT_OUTPUT
|
|
||||||
else
|
|
||||||
redirect_null();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
logit_done:
|
|
||||||
sig_unblock();
|
sig_unblock();
|
||||||
|
|
||||||
if (svc->inetd.cmd)
|
if (svc->inetd.cmd)
|
||||||
@@ -321,7 +409,7 @@ static int service_start(svc_t *svc)
|
|||||||
else if (svc_is_runtask(svc))
|
else if (svc_is_runtask(svc))
|
||||||
status = exec_runtask(svc->cmd, args);
|
status = exec_runtask(svc->cmd, args);
|
||||||
else
|
else
|
||||||
status = execv(svc->cmd, args);
|
status = execvp(svc->cmd, args);
|
||||||
|
|
||||||
#ifdef INETD_ENABLED
|
#ifdef INETD_ENABLED
|
||||||
if (svc_is_inetd_conn(svc)) {
|
if (svc_is_inetd_conn(svc)) {
|
||||||
@@ -332,28 +420,33 @@ static int service_start(svc_t *svc)
|
|||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
if (svc->log.enabled && !svc->log.null)
|
|
||||||
waitpid(pid, NULL, 0);
|
|
||||||
_exit(status);
|
_exit(status);
|
||||||
} else if (log_is_debug()) {
|
} else if (log_is_debug()) {
|
||||||
char buf[CMD_SIZE] = "";
|
char buf[CMD_SIZE] = "";
|
||||||
|
|
||||||
for (i = 0; i < (MAX_NUM_SVC_ARGS - 1) && svc->args[i][0] != 0; i++) {
|
for (i = 0; i < (MAX_NUM_SVC_ARGS - 1) && svc->args[i][0] != 0; i++) {
|
||||||
char arg[MAX_ARG_LEN];
|
char arg[MAX_ARG_LEN + 1];
|
||||||
|
|
||||||
snprintf(arg, sizeof(arg), "%s ", svc->args[i]);
|
snprintf(arg, sizeof(arg), "%s ", svc->args[i]);
|
||||||
if (strlen(arg) < (sizeof(buf) - strlen(buf)))
|
if (strlen(arg) < (sizeof(buf) - strlen(buf)))
|
||||||
strcat(buf, arg);
|
strlcat(buf, arg, sizeof(buf));
|
||||||
}
|
}
|
||||||
_d("Starting %s: %s", svc->cmd, buf);
|
_d("Starting %s: %s", svc->cmd, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logit(LOG_CONSOLE | LOG_NOTICE, "Starting %s:%s, PID: %d",
|
||||||
|
basename(svc->cmd), svc->id, pid);
|
||||||
|
|
||||||
svc->pid = pid;
|
svc->pid = pid;
|
||||||
svc->start_time = jiffies();
|
svc->start_time = jiffies();
|
||||||
|
|
||||||
switch (svc->type) {
|
switch (svc->type) {
|
||||||
case SVC_TYPE_RUN:
|
case SVC_TYPE_RUN:
|
||||||
result = WEXITSTATUS(complete(svc->cmd, pid));
|
svc->status = complete(svc->cmd, pid);
|
||||||
|
if (WIFEXITED(svc->status) && !WEXITSTATUS(svc->status))
|
||||||
|
result = 0;
|
||||||
|
else
|
||||||
|
result = 1;
|
||||||
svc->start_time = svc->pid = 0;
|
svc->start_time = svc->pid = 0;
|
||||||
svc->once++;
|
svc->once++;
|
||||||
svc_set_state(svc, SVC_STOPPING_STATE);
|
svc_set_state(svc, SVC_STOPPING_STATE);
|
||||||
@@ -398,10 +491,12 @@ static void service_kill(svc_t *svc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
_d("%s: Sending SIGKILL to pid:%d", pid_get_name(svc->pid, NULL, 0), svc->pid);
|
_d("%s: Sending SIGKILL to pid:%d", pid_get_name(svc->pid, NULL, 0), svc->pid);
|
||||||
|
logit(LOG_CONSOLE | LOG_NOTICE, "Stopping %s:%s, PID: %d, sending SIGKILL ...",
|
||||||
|
basename(svc->cmd), svc->id, svc->pid);
|
||||||
if (runlevel != 1)
|
if (runlevel != 1)
|
||||||
print_desc("Killing ", svc->desc);
|
print_desc("Killing ", svc->desc);
|
||||||
|
|
||||||
kill(svc->pid, SIGKILL);
|
kill(-svc->pid, SIGKILL);
|
||||||
|
|
||||||
/* Let SIGKILLs stand out, show result as [WARN] */
|
/* Let SIGKILLs stand out, show result as [WARN] */
|
||||||
if (runlevel != 1)
|
if (runlevel != 1)
|
||||||
@@ -443,16 +538,63 @@ static int service_stop(svc_t *svc)
|
|||||||
#endif
|
#endif
|
||||||
service_timeout_cancel(svc);
|
service_timeout_cancel(svc);
|
||||||
|
|
||||||
if (svc->pid <= 1)
|
if (!svc_is_sysv(svc)) {
|
||||||
return 1;
|
if (svc->pid <= 1)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
_d("Sending %s to pid:%d name:%s", sig_name(svc->sighalt),
|
||||||
|
svc->pid, pid_get_name(svc->pid, NULL, 0));
|
||||||
|
logit(LOG_CONSOLE | LOG_NOTICE, "Stopping %s:%s, PID: %d, sending %s ...",
|
||||||
|
basename(svc->cmd), svc->id, svc->pid, sig_name(svc->sighalt));
|
||||||
|
} else {
|
||||||
|
logit(LOG_CONSOLE | LOG_NOTICE, "Calling '%s stop' ...", svc->cmd);
|
||||||
|
}
|
||||||
|
|
||||||
_d("Sending SIGTERM to pid:%d name:%s", svc->pid, pid_get_name(svc->pid, NULL, 0));
|
|
||||||
svc_set_state(svc, SVC_STOPPING_STATE);
|
svc_set_state(svc, SVC_STOPPING_STATE);
|
||||||
|
|
||||||
if (runlevel != 1)
|
if (runlevel != 1)
|
||||||
print_desc("Stopping ", svc->desc);
|
print_desc("Stopping ", svc->desc);
|
||||||
|
|
||||||
res = kill(svc->pid, SIGTERM);
|
if (!svc_is_sysv(svc)) {
|
||||||
|
if (svc->pid <= 1)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
res = kill(-svc->pid, svc->sighalt);
|
||||||
|
|
||||||
|
/* PID lost or forking process never really started */
|
||||||
|
if (res == -1 && ESRCH == errno) {
|
||||||
|
char *fn;
|
||||||
|
|
||||||
|
/* XXX: Same clenup as done by service_monitor(), refactor */
|
||||||
|
cleanup:
|
||||||
|
fn = pid_file(svc);
|
||||||
|
if (remove(fn) && errno != ENOENT)
|
||||||
|
logit(LOG_CRIT, "Failed removing service %s pidfile %s",
|
||||||
|
basename(svc->cmd), fn);
|
||||||
|
|
||||||
|
/* No longer running, update books. */
|
||||||
|
svc->start_time = svc->pid = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
char *args[] = { svc->cmd, "stop", NULL };
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
pid = fork();
|
||||||
|
switch (pid) {
|
||||||
|
case 0:
|
||||||
|
redirect(svc);
|
||||||
|
exec_runtask(svc->cmd, args);
|
||||||
|
_exit(0);
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
_pe("Failed fork() to call sysv script '%s stop'", svc->cmd);
|
||||||
|
res = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
res = WEXITSTATUS(complete(svc->cmd, pid));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (runlevel != 1)
|
if (runlevel != 1)
|
||||||
print_result(res);
|
print_result(res);
|
||||||
@@ -466,7 +608,7 @@ static int service_stop(svc_t *svc)
|
|||||||
*
|
*
|
||||||
* This function does some basic checks of the runtime state of Finit
|
* This function does some basic checks of the runtime state of Finit
|
||||||
* and a sanity check of the @svc before sending %SIGHUP.
|
* and a sanity check of the @svc before sending %SIGHUP.
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* POSIX OK(0) or non-zero on error.
|
* POSIX OK(0) or non-zero on error.
|
||||||
*/
|
*/
|
||||||
@@ -496,6 +638,8 @@ static int service_restart(svc_t *svc)
|
|||||||
print_desc("Restarting ", svc->desc);
|
print_desc("Restarting ", svc->desc);
|
||||||
|
|
||||||
_d("Sending SIGHUP to PID %d", svc->pid);
|
_d("Sending SIGHUP to PID %d", svc->pid);
|
||||||
|
logit(LOG_CONSOLE | LOG_NOTICE, "Restarting %s:%s, PID: %d, sending SIGHUP ...",
|
||||||
|
basename(svc->cmd), svc->id, svc->pid);
|
||||||
rc = kill(svc->pid, SIGHUP);
|
rc = kill(svc->pid, SIGHUP);
|
||||||
|
|
||||||
/* Declare we're waiting for svc to re-assert/touch its pidfile */
|
/* Declare we're waiting for svc to re-assert/touch its pidfile */
|
||||||
@@ -558,6 +702,8 @@ static void parse_log(svc_t *svc, char *arg)
|
|||||||
svc->log.enabled = 1;
|
svc->log.enabled = 1;
|
||||||
else if (!strcmp(tok, "null") || !strcmp(tok, "/dev/null"))
|
else if (!strcmp(tok, "null") || !strcmp(tok, "/dev/null"))
|
||||||
svc->log.null = 1;
|
svc->log.null = 1;
|
||||||
|
else if (!strcmp(tok, "console") || !strcmp(tok, "/dev/console"))
|
||||||
|
svc->log.console = 1;
|
||||||
else if (tok[0] == '/')
|
else if (tok[0] == '/')
|
||||||
strlcpy(svc->log.file, tok, sizeof(svc->log.file));
|
strlcpy(svc->log.file, tok, sizeof(svc->log.file));
|
||||||
else if (!strcmp(tok, "priority") || !strcmp(tok, "prio"))
|
else if (!strcmp(tok, "priority") || !strcmp(tok, "prio"))
|
||||||
@@ -569,6 +715,49 @@ static void parse_log(svc_t *svc, char *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void parse_sighalt(svc_t *svc, char *arg)
|
||||||
|
{
|
||||||
|
int signo;
|
||||||
|
|
||||||
|
signo = sig_num(arg);
|
||||||
|
if (signo == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
svc->sighalt = signo;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_killdelay(svc_t *svc, char *delay)
|
||||||
|
{
|
||||||
|
const char *errstr;
|
||||||
|
long long sec;
|
||||||
|
|
||||||
|
sec = strtonum(delay, 1, 60, &errstr);
|
||||||
|
if (errstr) {
|
||||||
|
_e("%s: killdelay %s is %s (1-60)", svc->cmd, delay, errstr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* convert to msec */
|
||||||
|
svc->killdelay = (int)(sec * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* name:<name>
|
||||||
|
*/
|
||||||
|
static void parse_name(svc_t *svc, char *arg)
|
||||||
|
{
|
||||||
|
char *name = NULL;
|
||||||
|
|
||||||
|
if (arg && !strncasecmp(arg, "name:", 5)) {
|
||||||
|
name = arg + 5;
|
||||||
|
} else {
|
||||||
|
name = strrchr(svc->cmd, '/');
|
||||||
|
name = name ? name + 1 : svc->cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
strlcpy(svc->name, name, sizeof(svc->name));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* parse_cmdline_args - Update the command line args in the svc struct
|
* parse_cmdline_args - Update the command line args in the svc struct
|
||||||
*
|
*
|
||||||
@@ -584,13 +773,17 @@ static void parse_cmdline_args(svc_t *svc, char *cmd)
|
|||||||
|
|
||||||
strlcpy(svc->args[0], cmd, sizeof(svc->args[0]));
|
strlcpy(svc->args[0], cmd, sizeof(svc->args[0]));
|
||||||
|
|
||||||
/* Copy supplied args. Stop at MAX_NUM_SVC_ARGS-1 to allow the args
|
/*
|
||||||
* array to be zero-terminated. */
|
* Copy supplied args. Stop at MAX_NUM_SVC_ARGS-1 to allow the args
|
||||||
for (i=1; (arg = strtok(NULL, " ")) && i < (MAX_NUM_SVC_ARGS-1); i++)
|
* array to be zero-terminated.
|
||||||
|
*/
|
||||||
|
for (i = 1; (arg = strtok(NULL, " ")) && i < (MAX_NUM_SVC_ARGS - 1); i++)
|
||||||
strlcpy(svc->args[i], arg, sizeof(svc->args[0]));
|
strlcpy(svc->args[i], arg, sizeof(svc->args[0]));
|
||||||
|
|
||||||
/* clear remaining args in case they were set earlier.
|
/*
|
||||||
* This also zero-terminates the args array.*/
|
* Clear remaining args in case they were set earlier.
|
||||||
|
* This also zero-terminates the args array.
|
||||||
|
*/
|
||||||
for (; i < MAX_NUM_SVC_ARGS; i++)
|
for (; i < MAX_NUM_SVC_ARGS; i++)
|
||||||
svc->args[i][0] = 0;
|
svc->args[i][0] = 0;
|
||||||
}
|
}
|
||||||
@@ -634,7 +827,8 @@ static void parse_cmdline_args(svc_t *svc, char *cmd)
|
|||||||
*
|
*
|
||||||
* Service conditions can be: svc/<PATH> for PID files, net/<IFNAME>/up
|
* Service conditions can be: svc/<PATH> for PID files, net/<IFNAME>/up
|
||||||
* and net/<IFNAME>/exists. The condition handling is further described
|
* and net/<IFNAME>/exists. The condition handling is further described
|
||||||
* docs/conditions.md.
|
* in doc/conditions.md, but worth mentioning here is that the condition
|
||||||
|
* name itself can be modified using the :ID and name:foo syntax.
|
||||||
*
|
*
|
||||||
* For multiple instances of the same command, e.g. multiple DHCP
|
* For multiple instances of the same command, e.g. multiple DHCP
|
||||||
* clients, the user must enter an ID, using the :ID syntax.
|
* clients, the user must enter an ID, using the :ID syntax.
|
||||||
@@ -650,15 +844,18 @@ static void parse_cmdline_args(svc_t *svc, char *cmd)
|
|||||||
*/
|
*/
|
||||||
int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||||
{
|
{
|
||||||
int id = -1;
|
|
||||||
#ifdef INETD_ENABLED
|
#ifdef INETD_ENABLED
|
||||||
|
char id_str[MAX_ID_LEN];
|
||||||
int forking = 0;
|
int forking = 0;
|
||||||
#endif
|
#endif
|
||||||
int levels = 0;
|
int levels = 0;
|
||||||
|
int manual = 0;
|
||||||
char *line;
|
char *line;
|
||||||
|
char *id = NULL;
|
||||||
char *username = NULL, *log = NULL, *pid = NULL;
|
char *username = NULL, *log = NULL, *pid = NULL;
|
||||||
char *service = NULL, *proto = NULL, *ifaces = NULL;
|
char *service = NULL, *proto = NULL, *ifaces = NULL;
|
||||||
char *cmd, *desc, *runlevels = NULL, *cond = NULL;
|
char *cmd, *desc, *runlevels = NULL, *cond = NULL;
|
||||||
|
char *name = NULL, *halt = NULL, *delay = NULL;
|
||||||
svc_t *svc;
|
svc_t *svc;
|
||||||
plugin_t *plugin = NULL;
|
plugin_t *plugin = NULL;
|
||||||
|
|
||||||
@@ -705,7 +902,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
|||||||
else if (cmd[0] == '<') /* <[!][cond][,cond..]> */
|
else if (cmd[0] == '<') /* <[!][cond][,cond..]> */
|
||||||
cond = &cmd[1];
|
cond = &cmd[1];
|
||||||
else if (cmd[0] == ':') /* :ID */
|
else if (cmd[0] == ':') /* :ID */
|
||||||
id = atoi(&cmd[1]);
|
id = &cmd[1];
|
||||||
#ifdef INETD_ENABLED
|
#ifdef INETD_ENABLED
|
||||||
else if (!strncasecmp(cmd, "nowait", 6))
|
else if (!strncasecmp(cmd, "nowait", 6))
|
||||||
forking = 1;
|
forking = 1;
|
||||||
@@ -716,6 +913,14 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
|||||||
log = cmd;
|
log = cmd;
|
||||||
else if (!strncasecmp(cmd, "pid", 3))
|
else if (!strncasecmp(cmd, "pid", 3))
|
||||||
pid = cmd;
|
pid = cmd;
|
||||||
|
else if (!strncasecmp(cmd, "name:", 5))
|
||||||
|
name = cmd;
|
||||||
|
else if (!strncasecmp(cmd, "manual:yes", 10))
|
||||||
|
manual = 1;
|
||||||
|
else if (!strncasecmp(cmd, "halt:", 5))
|
||||||
|
halt = &cmd[5];
|
||||||
|
else if (!strncasecmp(cmd, "kill:", 5))
|
||||||
|
delay = &cmd[5];
|
||||||
else if (cmd[0] != '/' && strchr(cmd, '/'))
|
else if (cmd[0] != '/' && strchr(cmd, '/'))
|
||||||
service = cmd; /* inetd service/proto */
|
service = cmd; /* inetd service/proto */
|
||||||
else
|
else
|
||||||
@@ -773,24 +978,32 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
|||||||
parse_cmdline_args(svc, cmd);
|
parse_cmdline_args(svc, cmd);
|
||||||
goto inetd_setup;
|
goto inetd_setup;
|
||||||
}
|
}
|
||||||
if (id <= 0)
|
|
||||||
id = svc_next_id(cmd);
|
/* inetd services need a unique ID, so we must always set one. */
|
||||||
|
if (!id) {
|
||||||
|
snprintf(id_str, sizeof(id_str), "%d", svc_next_id_int(cmd));
|
||||||
|
id = id_str;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
recreate:
|
recreate:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (id <= 0)
|
if (!id)
|
||||||
id = 1;
|
id = "";
|
||||||
|
|
||||||
svc = svc_find(cmd, id);
|
svc = svc_find(cmd, id);
|
||||||
if (!svc) {
|
if (!svc) {
|
||||||
_d("Creating new svc for %s id #%d type %d", cmd, id, type);
|
_d("Creating new svc for %s id #%s type %d", cmd, id, type);
|
||||||
svc = svc_new(cmd, id, type);
|
svc = svc_new(cmd, id, type);
|
||||||
if (!svc) {
|
if (!svc) {
|
||||||
_e("Out of memory, cannot register service %s", cmd);
|
_e("Out of memory, cannot register service %s", cmd);
|
||||||
free(line);
|
free(line);
|
||||||
return errno = ENOMEM;
|
return errno = ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type == SVC_TYPE_SERVICE && manual) {
|
||||||
|
svc_stop(svc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#ifdef INETD_ENABLED
|
#ifdef INETD_ENABLED
|
||||||
else {
|
else {
|
||||||
@@ -831,6 +1044,11 @@ recreate:
|
|||||||
|
|
||||||
conf_parse_cond(svc, cond);
|
conf_parse_cond(svc, cond);
|
||||||
|
|
||||||
|
parse_name(svc, name);
|
||||||
|
if (halt)
|
||||||
|
parse_sighalt(svc, halt);
|
||||||
|
if (delay)
|
||||||
|
parse_killdelay(svc, delay);
|
||||||
if (log)
|
if (log)
|
||||||
parse_log(svc, log);
|
parse_log(svc, log);
|
||||||
if (desc)
|
if (desc)
|
||||||
@@ -875,7 +1093,7 @@ recreate:
|
|||||||
svc_mark_clean(svc);
|
svc_mark_clean(svc);
|
||||||
|
|
||||||
if (!file)
|
if (!file)
|
||||||
svc->protected = 1;
|
svc->protect = 1;
|
||||||
|
|
||||||
/* Free duped line, from above */
|
/* Free duped line, from above */
|
||||||
free(line);
|
free(line);
|
||||||
@@ -925,7 +1143,7 @@ void service_unregister(svc_t *svc)
|
|||||||
svc_del(svc);
|
svc_del(svc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void service_monitor(pid_t lost)
|
void service_monitor(pid_t lost, int status)
|
||||||
{
|
{
|
||||||
svc_t *svc;
|
svc_t *svc;
|
||||||
|
|
||||||
@@ -941,7 +1159,13 @@ void service_monitor(pid_t lost)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("collected %s(%d)", svc->cmd, lost);
|
_d("collected %s(%d), normal exit: %d, signaled: %d, exit code: %d",
|
||||||
|
svc->cmd, lost, WIFEXITED(status), WIFSIGNALED(status), WEXITSTATUS(status));
|
||||||
|
svc->status = status;
|
||||||
|
|
||||||
|
/* Forking sysv/services declare themselves with pid:!/path/to/pid.file */
|
||||||
|
if (svc_is_starting(svc) && svc_is_forking(svc))
|
||||||
|
return;
|
||||||
|
|
||||||
/* Try removing PID file (in case service does not clean up after itself) */
|
/* Try removing PID file (in case service does not clean up after itself) */
|
||||||
if (svc_is_daemon(svc)) {
|
if (svc_is_daemon(svc)) {
|
||||||
@@ -950,8 +1174,16 @@ void service_monitor(pid_t lost)
|
|||||||
fn = pid_file(svc);
|
fn = pid_file(svc);
|
||||||
if (remove(fn) && errno != ENOENT)
|
if (remove(fn) && errno != ENOENT)
|
||||||
logit(LOG_CRIT, "Failed removing service %s pidfile %s", basename(svc->cmd), fn);
|
logit(LOG_CRIT, "Failed removing service %s pidfile %s", basename(svc->cmd), fn);
|
||||||
|
} else if (svc_is_runtask(svc)) {
|
||||||
|
if (WIFEXITED(status) && !WEXITSTATUS(status))
|
||||||
|
svc->started = 1;
|
||||||
|
else
|
||||||
|
svc->started = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Terminate any children in the same proess group, e.g. logit */
|
||||||
|
kill(-svc->pid, SIGTERM);
|
||||||
|
|
||||||
/* No longer running, update books. */
|
/* No longer running, update books. */
|
||||||
svc->start_time = svc->pid = 0;
|
svc->start_time = svc->pid = 0;
|
||||||
|
|
||||||
@@ -979,7 +1211,8 @@ static void service_retry(svc_t *svc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (*restart_cnt >= RESPAWN_MAX) {
|
if (*restart_cnt >= RESPAWN_MAX) {
|
||||||
logit(LOG_ERR, "%s keeps crashing, not restarting", svc->cmd);
|
logit(LOG_CONSOLE | LOG_WARNING, "Service %s:%s keeps crashing, not restarting.",
|
||||||
|
basename(svc->cmd), svc->id);
|
||||||
svc_crashing(svc);
|
svc_crashing(svc);
|
||||||
*restart_cnt = 0;
|
*restart_cnt = 0;
|
||||||
service_step(svc);
|
service_step(svc);
|
||||||
@@ -989,6 +1222,8 @@ static void service_retry(svc_t *svc)
|
|||||||
(*restart_cnt)++;
|
(*restart_cnt)++;
|
||||||
|
|
||||||
_d("%s crashed, trying to start it again, attempt %d", svc->cmd, *restart_cnt);
|
_d("%s crashed, trying to start it again, attempt %d", svc->cmd, *restart_cnt);
|
||||||
|
logit(LOG_CONSOLE | LOG_WARNING, "Service %s:%s died, restarting (%d/%d)",
|
||||||
|
basename(svc->cmd), svc->id, *restart_cnt, RESPAWN_MAX);
|
||||||
svc_unblock(svc);
|
svc_unblock(svc);
|
||||||
service_step(svc);
|
service_step(svc);
|
||||||
|
|
||||||
@@ -1005,8 +1240,10 @@ static void svc_set_state(svc_t *svc, svc_state_t new)
|
|||||||
|
|
||||||
/* if PID isn't collected within SVC_TERM_TIMEOUT msec, kill it! */
|
/* if PID isn't collected within SVC_TERM_TIMEOUT msec, kill it! */
|
||||||
if ((*state == SVC_STOPPING_STATE) && !svc_is_inetd(svc)) {
|
if ((*state == SVC_STOPPING_STATE) && !svc_is_inetd(svc)) {
|
||||||
|
_d("%s is stopping, wait %d sec before sending SIGKILL ...",
|
||||||
|
svc->cmd, svc->killdelay / 1000);
|
||||||
service_timeout_cancel(svc);
|
service_timeout_cancel(svc);
|
||||||
service_timeout_after(svc, SVC_TERM_TIMEOUT, service_kill);
|
service_timeout_after(svc, svc->killdelay, service_kill);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1052,6 +1289,7 @@ restart:
|
|||||||
case SVC_STOPPING_STATE:
|
case SVC_STOPPING_STATE:
|
||||||
if (!svc->pid) {
|
if (!svc->pid) {
|
||||||
/* PID was collected normally, no need to kill it */
|
/* PID was collected normally, no need to kill it */
|
||||||
|
_d("%s: Stopped normally, no need to send SIGKILL :)", svc->cmd);
|
||||||
service_timeout_cancel(svc);
|
service_timeout_cancel(svc);
|
||||||
|
|
||||||
switch (svc->type) {
|
switch (svc->type) {
|
||||||
@@ -1063,6 +1301,7 @@ restart:
|
|||||||
case SVC_TYPE_INETD_CONN:
|
case SVC_TYPE_INETD_CONN:
|
||||||
case SVC_TYPE_TASK:
|
case SVC_TYPE_TASK:
|
||||||
case SVC_TYPE_RUN:
|
case SVC_TYPE_RUN:
|
||||||
|
case SVC_TYPE_SYSV:
|
||||||
svc_set_state(svc, SVC_DONE_STATE);
|
svc_set_state(svc, SVC_DONE_STATE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1121,7 +1360,12 @@ restart:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (svc_is_runtask(svc)) {
|
if (svc_is_runtask(svc)) {
|
||||||
svc_set_state(svc, SVC_STOPPING_STATE);
|
if (svc_is_sysv(svc)) {
|
||||||
|
if (!svc->started)
|
||||||
|
svc_set_state(svc, SVC_STOPPING_STATE);
|
||||||
|
} else {
|
||||||
|
svc_set_state(svc, SVC_STOPPING_STATE);
|
||||||
|
}
|
||||||
svc->once++;
|
svc->once++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1179,14 +1423,16 @@ restart:
|
|||||||
svc_set_state(svc, SVC_RUNNING_STATE);
|
svc_set_state(svc, SVC_RUNNING_STATE);
|
||||||
/* Reassert condition if we go from waiting and no change */
|
/* Reassert condition if we go from waiting and no change */
|
||||||
if (!svc_is_changed(svc)) {
|
if (!svc_is_changed(svc)) {
|
||||||
char cond[MAX_COND_LEN];
|
char name[MAX_COND_LEN];
|
||||||
|
|
||||||
mkcond(cond, sizeof(cond), svc->cmd);
|
mkcond(svc, name, sizeof(name));
|
||||||
cond_set_path(cond_path(cond), COND_ON);
|
_d("Reassert condition %s", name);
|
||||||
|
cond_set_path(cond_path(name), COND_ON);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case COND_OFF:
|
case COND_OFF:
|
||||||
|
_d("Condition for %s is off, sending SIGCONT + SIGTERM", svc->name);
|
||||||
kill(svc->pid, SIGCONT);
|
kill(svc->pid, SIGCONT);
|
||||||
service_stop(svc);
|
service_stop(svc);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -98,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);
|
||||||
@@ -316,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");
|
||||||
@@ -324,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);
|
||||||
}
|
}
|
||||||
@@ -368,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_ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -117,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;
|
||||||
|
|
||||||
@@ -150,6 +150,7 @@ 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 */
|
||||||
|
|||||||
+12
-2
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <ctype.h> /* isdigit() */
|
#include <ctype.h> /* isdigit() */
|
||||||
#include <time.h>
|
#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>
|
||||||
@@ -60,7 +61,8 @@ static void svc_gc(void *arg)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
TAILQ_REMOVE(&gc_list, svc, link);
|
TAILQ_REMOVE(&gc_list, svc, link);
|
||||||
cond_clear(mkcond(cond, sizeof(cond), svc->cmd));
|
_d("Cleaning out %s, clearing any conditions ...", svc->name);
|
||||||
|
cond_clear(mkcond(svc, cond, sizeof(cond)));
|
||||||
free(svc);
|
free(svc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,10 +79,9 @@ static void svc_gc(void *arg)
|
|||||||
* 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 */
|
||||||
@@ -99,16 +100,18 @@ 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);
|
||||||
|
|
||||||
@@ -204,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;
|
||||||
@@ -301,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -383,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;
|
||||||
@@ -415,7 +442,7 @@ 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;
|
continue;
|
||||||
if (svc_is_inetd_conn(svc))
|
if (svc_is_inetd_conn(svc))
|
||||||
continue;
|
continue;
|
||||||
@@ -509,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)
|
||||||
@@ -544,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)
|
||||||
@@ -577,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)
|
||||||
@@ -599,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)
|
||||||
@@ -609,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,14 +67,15 @@ 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
|
||||||
|
|
||||||
/* Time after SIGTERM that we SIGKILL stopping processes */
|
/* Default kill delay (msec) after SIGTERM (svc->sighalt) that we SIGKILL processes */
|
||||||
#define SVC_TERM_TIMEOUT 3000
|
#define SVC_TERM_TIMEOUT 3000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -86,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 */
|
||||||
@@ -118,6 +126,7 @@ typedef struct svc {
|
|||||||
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];
|
||||||
@@ -143,13 +152,13 @@ typedef struct svc {
|
|||||||
struct timespec gc;
|
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);
|
||||||
@@ -170,15 +179,17 @@ 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; }
|
||||||
|
|||||||
@@ -153,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;
|
||||||
@@ -184,28 +188,16 @@ 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 */
|
/* Auto-detect serial console, for embedded devices mostly */
|
||||||
if (!strcmp(dev, "@console")) {
|
if (!strcmp(dev, "@console") || !strcmp(dev, "console")) {
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
fp = fopen("/sys/class/tty/console/active", "r");
|
fp = fopen("/sys/class/tty/console/active", "r");
|
||||||
@@ -226,18 +218,24 @@ again:
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
strlcpy(entry->name, dev, sizeof(entry->name));
|
strlcpy(entry->name, dev, sizeof(entry->name));
|
||||||
@@ -257,11 +255,18 @@ again:
|
|||||||
tok = cmd;
|
tok = cmd;
|
||||||
else
|
else
|
||||||
tok++;
|
tok++;
|
||||||
entry->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->args[j++] = strdup(args[i]);
|
char *arg = args[i];
|
||||||
|
|
||||||
|
/* 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;
|
entry->args[++j] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+51
-18
@@ -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_ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in new issue
Block a user