mirror of
https://github.com/troglobit/finit.git
synced 2026-10-12 10:12:32 +00:00
Compare commits
124
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce7d4cebab | ||
|
|
d5a47e2d8b | ||
|
|
020eefe732 | ||
|
|
14336bd407 | ||
|
|
bb841383b8 | ||
|
|
e49763d834 | ||
|
|
57545e1ab0 | ||
|
|
7ad802b092 | ||
|
|
e319a606b8 | ||
|
|
7d434b1eaa | ||
|
|
58d48b54b3 | ||
|
|
7d4603e13b | ||
|
|
d0c5d7be5b | ||
|
|
db840bdc19 | ||
|
|
3df3c51dae | ||
|
|
d37d241647 | ||
|
|
b18b21830a | ||
|
|
06daf2e4a5 | ||
|
|
eb13ccc227 | ||
|
|
0861373d14 | ||
|
|
1b9e69414e | ||
|
|
39f4aa3f2c | ||
|
|
dedb56a9d0 | ||
|
|
a27903c745 | ||
|
|
f24f76fc80 | ||
|
|
d95fc5f790 | ||
|
|
10a1257e47 | ||
|
|
a7b8e1b94d | ||
|
|
da83462731 | ||
|
|
1396177706 | ||
|
|
7cf0a293fd | ||
|
|
d0d9b83b66 | ||
|
|
76f8a18816 | ||
|
|
dc497bcd57 | ||
|
|
0da6bbe4a8 | ||
|
|
91f7a75bee | ||
|
|
f217d493b4 | ||
|
|
77404a2ea0 | ||
|
|
d42a1d438b | ||
|
|
1275f05343 | ||
|
|
61a92aa0b6 | ||
|
|
b38ff0cc79 | ||
|
|
168f5bf1d8 | ||
|
|
ffd00f646c | ||
|
|
5e2e273cad | ||
|
|
33f6697cd5 | ||
|
|
6f0ba22a0f | ||
|
|
ecb690c9ec | ||
|
|
0459bb432a | ||
|
|
2760616c73 | ||
|
|
62ab990129 | ||
|
|
0c2836d747 | ||
|
|
8be7a462e0 | ||
|
|
5993b4bb5d | ||
|
|
2957246092 | ||
|
|
a5710125f6 | ||
|
|
ff95ebeb91 | ||
|
|
1921b3f2c5 | ||
|
|
051ef81e53 | ||
|
|
90993c237a | ||
|
|
b0b4f7b2ba | ||
|
|
4d79d84fb8 | ||
|
|
d318aa00c3 | ||
|
|
9684127eb7 | ||
|
|
8d2cfd69fa | ||
|
|
4f252858e4 | ||
|
|
1ccd1d6926 | ||
|
|
b87c51209d | ||
|
|
6b7478ff43 | ||
|
|
6c4c16cbdb | ||
|
|
e539dbfe37 | ||
|
|
90c6bcd365 | ||
|
|
c9c268f218 | ||
|
|
3feff37ba5 | ||
|
|
c67d15e272 | ||
|
|
8984c655f8 | ||
|
|
1a7b26bac3 | ||
|
|
1f47718012 | ||
|
|
fa13cddc28 | ||
|
|
185a72bd14 | ||
|
|
cd32c623cf | ||
|
|
ac4b9c2f93 | ||
|
|
5e9591d0a8 | ||
|
|
e3bcf9bf16 | ||
|
|
84fd3196b0 | ||
|
|
994e51e34f | ||
|
|
0a7814b391 | ||
|
|
73f72b39cf | ||
|
|
02e0aa7383 | ||
|
|
6528628b5c | ||
|
|
1480657982 | ||
|
|
33e378a345 | ||
|
|
b695b46a9d | ||
|
|
0e61ed727f | ||
|
|
e9d60a6c04 | ||
|
|
5e9edf9deb | ||
|
|
8ed2751ae1 | ||
|
|
7fec66dc09 | ||
|
|
75fa868a4b | ||
|
|
7b321de339 | ||
|
|
1691ebb292 | ||
|
|
c371c10455 | ||
|
|
a23e152f6b | ||
|
|
9210f2851e | ||
|
|
617609cbc5 | ||
|
|
b022916758 | ||
|
|
9a357b7aab | ||
|
|
ffd01b0276 | ||
|
|
2c95f091ee | ||
|
|
b75b107d6d | ||
|
|
1f2c1d2109 | ||
|
|
f328d24d01 | ||
|
|
211293a83d | ||
|
|
446f5bc8b8 | ||
|
|
0c6f748f2c | ||
|
|
a677b94ad9 | ||
|
|
6552cda605 | ||
|
|
3add682be3 | ||
|
|
abac31682d | ||
|
|
cfe915e6d5 | ||
|
|
ecf65ce44b | ||
|
|
0d742d6ae8 | ||
|
|
cf201a43df | ||
|
|
9245869e18 |
@@ -24,7 +24,8 @@ the maintainer(s) and make it easier for them to include your code.
|
|||||||
Coding Style
|
Coding Style
|
||||||
------------
|
------------
|
||||||
|
|
||||||
> **Tip:** Always submit code that follows the style of surrounding code!
|
> [!TIP]
|
||||||
|
> Always submit code that follows the style of surrounding code!
|
||||||
|
|
||||||
First of all, lines are allowed to be longer than 72 characters these
|
First of all, lines are allowed to be longer than 72 characters these
|
||||||
days. In fact, there exist no enforced maximum, but keeping it around
|
days. In fact, there exist no enforced maximum, but keeping it around
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
|
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
|
||||||
--enable-x11-common-plugin --enable-testserv-plugin --with-watchdog \
|
--enable-x11-common-plugin --enable-testserv-plugin --with-watchdog \
|
||||||
--with-keventd
|
--with-keventd \
|
||||||
|
CFLAGS="-fsanitize=address -ggdb"
|
||||||
make -j3 clean
|
make -j3 clean
|
||||||
make -j3 V=1
|
make -j3 V=1
|
||||||
- name: Install to /tmp
|
- name: Install to /tmp
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- 'dev'
|
- 'dev'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
PROJECT_NAME: finit
|
PROJECT_NAME: finit
|
||||||
|
|||||||
+101
-41
@@ -4,7 +4,64 @@ Change Log
|
|||||||
All relevant changes are documented in this file.
|
All relevant changes are documented in this file.
|
||||||
|
|
||||||
|
|
||||||
[4.9][UNRELEASED]
|
[4.12][] - 2025-04-28
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
- Improve notify:s6 readiness compatibility, by Aaron Andersen
|
||||||
|
- Update `runparts` usage text
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Fix variable overloading in urandom plugin
|
||||||
|
- Fix buffer overwrite in urandom plugin, reported by Aaron Andersen
|
||||||
|
|
||||||
|
|
||||||
|
[4.11][] - 2025-03-27
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
- Update documentation regarding transition from runlevel S to 2, how
|
||||||
|
run/tasks must "complete" before Finit can move to the next runlevel
|
||||||
|
- Improve argument handling in bundled getty when launching login
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Fix #432: allow services in `setup` state to be stopped. This fixes
|
||||||
|
a serious blocker introduced in 4.10 that prevented systems from
|
||||||
|
being rebooted when any service was in this state
|
||||||
|
- Fix fallback `SIGKILL` when stopping a service with `SIGTERM` does
|
||||||
|
not work. This fixes a serious issue with services not responding to
|
||||||
|
the default `SIGTERM`
|
||||||
|
- Fix pre/post/ready/cleanup script execution if service has an
|
||||||
|
optional `env:file` (leading `-`)
|
||||||
|
- Fix blocked signals for pre/post/ready/cleanup scripts preventing
|
||||||
|
normal shutdown when a service/sysv is stopped in its setup state
|
||||||
|
- Fix issue where a pre:script creates a PID file in `/run` cause the
|
||||||
|
service to move from setup state to running. Any `svc_t` in setup,
|
||||||
|
teardown, or cleanup state should be ignored in the pidfile plugin
|
||||||
|
|
||||||
|
|
||||||
|
[4.10][] - 2025-03-03
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
- Add support for `cleanup:[0-3600,]script`, runs before service is
|
||||||
|
removed, unlike `post:script` that runs when service is stopped
|
||||||
|
- Improved entropy gathering in tertiary fallback of urandom plugin
|
||||||
|
- Reclassify `sysv` from run/task class to `service`
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Fix #427: using an external getty with custom login program cause
|
||||||
|
Finit to use login program as the getty command
|
||||||
|
- Fix #428: allow `sysctl` path to be set at build time
|
||||||
|
- Fix #429: regression in v4.9 causing Finit to segfault at shutdown
|
||||||
|
- Fix possible memory leak when sourcing a service `env:file`
|
||||||
|
- Finit now waits until all `post:scripts` have run before returning
|
||||||
|
OK to `initctl <reload|runlevel>`. This also applies to the new
|
||||||
|
`cleanup:scripts` introduced in this release
|
||||||
|
- RFC3154 conformance formatting fix for `/dev/kmsg` fallback logging
|
||||||
|
|
||||||
|
|
||||||
|
[4.9][] - 2025-02-15
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
> [!CAUTION]
|
> [!CAUTION]
|
||||||
@@ -29,7 +86,7 @@ All relevant changes are documented in this file.
|
|||||||
does not support SIGHUP. This helps avoid unnecessary restarts of
|
does not support SIGHUP. This helps avoid unnecessary restarts of
|
||||||
services that depend on a service that supports SIGHUP
|
services that depend on a service that supports SIGHUP
|
||||||
- Fix #417: leaking inotify watchers in the cgroup subsystem
|
- Fix #417: leaking inotify watchers in the cgroup subsystem
|
||||||
- Fix #422: honor `notfail` flag in `/etc/fstab`
|
- Fix #421: add support for `nofail` mount option in `/etc/fstab`
|
||||||
- Fix #425: ordering bug in detecting .conf file changes to services
|
- Fix #425: ordering bug in detecting .conf file changes to services
|
||||||
and `initctl reload`, or runlevel changes
|
and `initctl reload`, or runlevel changes
|
||||||
- Fix `initctl touch` of template services, previously marking a
|
- Fix `initctl touch` of template services, previously marking a
|
||||||
@@ -68,7 +125,7 @@ All relevant changes are documented in this file.
|
|||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
- Fix #397: system shutdown/reboot can block on console input if action
|
- Fix #397: system shutdown/reboot can block on console input if action
|
||||||
is started remotely (ssh). Caused by legact TTY screen size probing,
|
is started remotely (ssh). Caused by legacy TTY screen size probing,
|
||||||
removed from both bootstrap and shutdown/reboot
|
removed from both bootstrap and shutdown/reboot
|
||||||
- Fix #400: both `HOOK_MOUNT_ERROR` and `sulogin()` fail to trigger on
|
- Fix #400: both `HOOK_MOUNT_ERROR` and `sulogin()` fail to trigger on
|
||||||
either mount or `fsck` errors. Problem caused by unresolved status
|
either mount or `fsck` errors. Problem caused by unresolved status
|
||||||
@@ -326,7 +383,7 @@ All relevant changes are documented in this file.
|
|||||||
`/etc/finit.conf`.
|
`/etc/finit.conf`.
|
||||||
|
|
||||||
For the complete experience a new top-level configuration file directive
|
For the complete experience a new top-level configuration file directive
|
||||||
`rcsd PATH` has aslo been added. It in turn can be used by `factory.conf`
|
`rcsd PATH` has also been added. It in turn can be used by `factory.conf`
|
||||||
as follows to override `/etc/finit.d`:
|
as follows to override `/etc/finit.d`:
|
||||||
|
|
||||||
rcsd /etc/factory.d
|
rcsd /etc/factory.d
|
||||||
@@ -909,7 +966,7 @@ make sure to read the whole change log when upgrading.
|
|||||||
previously hard-coded in Finit, e.g., starting the bundled watchdogd,
|
previously hard-coded in Finit, e.g., starting the bundled watchdogd,
|
||||||
various distro packed udevd and other hotplugging tools
|
various distro packed udevd and other hotplugging tools
|
||||||
* A proper rescue mode has been added. It is started extremely early
|
* A proper rescue mode has been added. It is started extremely early
|
||||||
and is protected with a bundled `suslogin`. Exiting rescue mode now
|
and is protected with a bundled `sulogin`. Exiting rescue mode now
|
||||||
brings up the system as a normal boot, as one expects
|
brings up the system as a normal boot, as one expects
|
||||||
* Support for `sysv` start/stop scripts as well as monitoring forking
|
* Support for `sysv` start/stop scripts as well as monitoring forking
|
||||||
services, stared using `sysv` or `service` stanza
|
services, stared using `sysv` or `service` stanza
|
||||||
@@ -1740,44 +1797,47 @@ Major bug fix release.
|
|||||||
|
|
||||||
* Initial release
|
* Initial release
|
||||||
|
|
||||||
[UNRELEASED]: https://github.com/troglobit/finit/compare/4.8...HEAD
|
[UNRELEASED]: https://github.com/troglobit/finit/compare/4.11...HEAD
|
||||||
[4.9]: https://github.com/troglobit/finit/compare/4.8...4.9
|
[4.12]: https://github.com/troglobit/finit/compare/4.11...4.12
|
||||||
[4.8]: https://github.com/troglobit/finit/compare/4.7...4.8
|
[4.11]: https://github.com/troglobit/finit/compare/4.10...4.11
|
||||||
[4.7]: https://github.com/troglobit/finit/compare/4.6...4.7
|
[4.10]: https://github.com/troglobit/finit/compare/4.9...4.10
|
||||||
[4.6]: https://github.com/troglobit/finit/compare/4.5...4.6
|
[4.9]: https://github.com/troglobit/finit/compare/4.8...4.9
|
||||||
[4.5]: https://github.com/troglobit/finit/compare/4.4...4.5
|
[4.8]: https://github.com/troglobit/finit/compare/4.7...4.8
|
||||||
[4.4]: https://github.com/troglobit/finit/compare/4.3...4.4
|
[4.7]: https://github.com/troglobit/finit/compare/4.6...4.7
|
||||||
[4.3]: https://github.com/troglobit/finit/compare/4.2...4.3
|
[4.6]: https://github.com/troglobit/finit/compare/4.5...4.6
|
||||||
[4.2]: https://github.com/troglobit/finit/compare/4.1...4.2
|
[4.5]: https://github.com/troglobit/finit/compare/4.4...4.5
|
||||||
[4.1]: https://github.com/troglobit/finit/compare/4.0...4.1
|
[4.4]: https://github.com/troglobit/finit/compare/4.3...4.4
|
||||||
[4.0]: https://github.com/troglobit/finit/compare/3.1...4.0
|
[4.3]: https://github.com/troglobit/finit/compare/4.2...4.3
|
||||||
[3.1]: https://github.com/troglobit/finit/compare/3.0...3.1
|
[4.2]: https://github.com/troglobit/finit/compare/4.1...4.2
|
||||||
[3.0]: https://github.com/troglobit/finit/compare/2.4...3.0
|
[4.1]: https://github.com/troglobit/finit/compare/4.0...4.1
|
||||||
[2.4]: https://github.com/troglobit/finit/compare/2.3...2.4
|
[4.0]: https://github.com/troglobit/finit/compare/3.1...4.0
|
||||||
[2.3]: https://github.com/troglobit/finit/compare/2.2...2.3
|
[3.1]: https://github.com/troglobit/finit/compare/3.0...3.1
|
||||||
[2.2]: https://github.com/troglobit/finit/compare/2.1...2.2
|
[3.0]: https://github.com/troglobit/finit/compare/2.4...3.0
|
||||||
[2.1]: https://github.com/troglobit/finit/compare/2.0...2.1
|
[2.4]: https://github.com/troglobit/finit/compare/2.3...2.4
|
||||||
[2.0]: https://github.com/troglobit/finit/compare/1.12...2.0
|
[2.3]: https://github.com/troglobit/finit/compare/2.2...2.3
|
||||||
|
[2.2]: https://github.com/troglobit/finit/compare/2.1...2.2
|
||||||
|
[2.1]: https://github.com/troglobit/finit/compare/2.0...2.1
|
||||||
|
[2.0]: https://github.com/troglobit/finit/compare/1.12...2.0
|
||||||
[1.12]: https://github.com/troglobit/finit/compare/1.11...1.12
|
[1.12]: https://github.com/troglobit/finit/compare/1.11...1.12
|
||||||
[1.11]: https://github.com/troglobit/finit/compare/1.10...1.11
|
[1.11]: https://github.com/troglobit/finit/compare/1.10...1.11
|
||||||
[1.10]: https://github.com/troglobit/finit/compare/1.9...1.10
|
[1.10]: https://github.com/troglobit/finit/compare/1.9...1.10
|
||||||
[1.9]: https://github.com/troglobit/finit/compare/1.8...1.9
|
[1.9]: https://github.com/troglobit/finit/compare/1.8...1.9
|
||||||
[1.8]: https://github.com/troglobit/finit/compare/1.7...1.8
|
[1.8]: https://github.com/troglobit/finit/compare/1.7...1.8
|
||||||
[1.7]: https://github.com/troglobit/finit/compare/1.6...1.7
|
[1.7]: https://github.com/troglobit/finit/compare/1.6...1.7
|
||||||
[1.6]: https://github.com/troglobit/finit/compare/1.5...1.6
|
[1.6]: https://github.com/troglobit/finit/compare/1.5...1.6
|
||||||
[1.5]: https://github.com/troglobit/finit/compare/1.4...1.5
|
[1.5]: https://github.com/troglobit/finit/compare/1.4...1.5
|
||||||
[1.4]: https://github.com/troglobit/finit/compare/1.3...1.4
|
[1.4]: https://github.com/troglobit/finit/compare/1.3...1.4
|
||||||
[1.3]: https://github.com/troglobit/finit/compare/1.2...1.3
|
[1.3]: https://github.com/troglobit/finit/compare/1.2...1.3
|
||||||
[1.2]: https://github.com/troglobit/finit/compare/1.1...1.2
|
[1.2]: https://github.com/troglobit/finit/compare/1.1...1.2
|
||||||
[1.1]: https://github.com/troglobit/finit/compare/1.0...1.1
|
[1.1]: https://github.com/troglobit/finit/compare/1.0...1.1
|
||||||
[1.0]: https://github.com/troglobit/finit/compare/0.9...1.0
|
[1.0]: https://github.com/troglobit/finit/compare/0.9...1.0
|
||||||
[0.9]: https://github.com/troglobit/finit/compare/0.8...0.9
|
[0.9]: https://github.com/troglobit/finit/compare/0.8...0.9
|
||||||
[0.8]: https://github.com/troglobit/finit/compare/0.7...0.8
|
[0.8]: https://github.com/troglobit/finit/compare/0.7...0.8
|
||||||
[0.7]: https://github.com/troglobit/finit/compare/0.6...0.7
|
[0.7]: https://github.com/troglobit/finit/compare/0.6...0.7
|
||||||
[0.6]: https://github.com/troglobit/finit/compare/0.5...0.6
|
[0.6]: https://github.com/troglobit/finit/compare/0.5...0.6
|
||||||
[0.5]: https://github.com/troglobit/finit/compare/0.4...0.5
|
[0.5]: https://github.com/troglobit/finit/compare/0.4...0.5
|
||||||
[0.4]: https://github.com/troglobit/finit/compare/0.3...0.4
|
[0.4]: https://github.com/troglobit/finit/compare/0.3...0.4
|
||||||
[0.3]: https://github.com/troglobit/finit/compare/0.2...0.3
|
[0.3]: https://github.com/troglobit/finit/compare/0.2...0.3
|
||||||
[0.2]: https://github.com/troglobit/finit/compare/0.1...0.2
|
[0.2]: https://github.com/troglobit/finit/compare/0.1...0.2
|
||||||
[libuEv]: https://github.com/troglobit/libuev
|
[libuEv]: https://github.com/troglobit/libuev
|
||||||
[dea3ae8]: https://github.com/troglobit/finit/commit/dea3ae8
|
[dea3ae8]: https://github.com/troglobit/finit/commit/dea3ae8
|
||||||
|
|||||||
+12
-1
@@ -1,5 +1,5 @@
|
|||||||
ACLOCAL_AMFLAGS = -I m4
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
SUBDIRS = man plugins src system test tmpfiles.d
|
SUBDIRS = man plugins src system tmpfiles.d
|
||||||
doc_DATA = README.md LICENSE contrib/finit.conf
|
doc_DATA = README.md LICENSE contrib/finit.conf
|
||||||
EXTRA_DIST = README.md LICENSE ChangeLog.md contrib/finit.conf
|
EXTRA_DIST = README.md LICENSE ChangeLog.md contrib/finit.conf
|
||||||
|
|
||||||
@@ -9,6 +9,17 @@ endif
|
|||||||
if DOC
|
if DOC
|
||||||
SUBDIRS += doc
|
SUBDIRS += doc
|
||||||
endif
|
endif
|
||||||
|
if LIBSYSTEMD
|
||||||
|
SUBDIRS += libsystemd
|
||||||
|
endif
|
||||||
|
|
||||||
|
if LIBSYSTEMD
|
||||||
|
SUBDIRS += test
|
||||||
|
# Explicit dependency to ensure libsystemd is built before test
|
||||||
|
test: libsystemd
|
||||||
|
else
|
||||||
|
SUBDIRS += test
|
||||||
|
endif
|
||||||
|
|
||||||
if BASH
|
if BASH
|
||||||
bashdir = $(BASH_DIR)
|
bashdir = $(BASH_DIR)
|
||||||
|
|||||||
@@ -61,12 +61,13 @@ distributions:
|
|||||||
* [Alpine Linux](contrib/alpine/), and
|
* [Alpine Linux](contrib/alpine/), and
|
||||||
* [Debian GNU/Linux](contrib/debian/), also works on Ubuntu/Linux Mint
|
* [Debian GNU/Linux](contrib/debian/), also works on Ubuntu/Linux Mint
|
||||||
|
|
||||||
> **Note:** support for various Linux distributions does not mean Finit
|
> [!NOTE]
|
||||||
> installs easily on all architectures. The bundled install scripts are
|
> Support for various Linux distributions does not mean Finit installs
|
||||||
> examples for standard installations, tested on amd64 (x86_64) systems.
|
> easily on all architectures. The bundled install scripts are examples
|
||||||
> Custom setups, e.g., for embedded systems, can be found in any of the
|
> for standard installations, tested on amd64 (x86_64) systems. Custom
|
||||||
> following [Buildroot][] based examples: [myLinux][], [Infix][], or the
|
> setups, e.g., for embedded systems, can be found in the following
|
||||||
> plain [br2-finit-demo](https://github.com/troglobit/br2-finit-demo).
|
> [Buildroot][] based examples: [myLinux][], [Infix][], or the plain
|
||||||
|
> [br2-finit-demo](https://github.com/troglobit/br2-finit-demo).
|
||||||
|
|
||||||
|
|
||||||
Example
|
Example
|
||||||
@@ -78,9 +79,10 @@ be placed in `/etc/finit.d/available` and enabled by an operator using
|
|||||||
the [initctl](#commands--status) tool. See the above mentioned Linux
|
the [initctl](#commands--status) tool. See the above mentioned Linux
|
||||||
distributions, or [myLinux][].
|
distributions, or [myLinux][].
|
||||||
|
|
||||||
> **Note:** as of Finit v4.4, .conf lines can be broken up using the
|
> [!TIP]
|
||||||
> standard UNIX continuation character (`\`), also trailing comments are
|
> As of Finit v4.4, `.conf` lines can be broken up using the standard
|
||||||
> now supported. The latter means you need to escape any hashes used in
|
> UNIX continuation character (`\`), trailing comments are now also
|
||||||
|
> supported. The latter means you need to escape any hashes used in
|
||||||
> directives and descriptions (`\#`). For more on this and examples,
|
> directives and descriptions (`\#`). For more on this and examples,
|
||||||
> see the [finit.conf(5)][] manual or [doc/config.md](doc/config.md).
|
> see the [finit.conf(5)][] manual or [doc/config.md](doc/config.md).
|
||||||
|
|
||||||
@@ -249,7 +251,7 @@ All services in runlevel S) are started first, followed by the desired
|
|||||||
run-time runlevel. Run tasks in runlevel S can be started in sequence
|
run-time runlevel. Run tasks in runlevel S can be started in sequence
|
||||||
by using `run [S] cmd`. Changing runlevels at runtime is done like any
|
by using `run [S] cmd`. Changing runlevels at runtime is done like any
|
||||||
other init, e.g. <kbd>init 4</kbd>, but also using the more advanced
|
other init, e.g. <kbd>init 4</kbd>, but also using the more advanced
|
||||||
`intictl` tool.
|
[`initctl`](#commands--status) tool.
|
||||||
|
|
||||||
|
|
||||||
**Conditions**
|
**Conditions**
|
||||||
@@ -285,6 +287,7 @@ run [S] /path/to/ident --
|
|||||||
task [2] <hw/model/foo> /path/to/foo-init -- Initializing Foo board
|
task [2] <hw/model/foo> /path/to/foo-init -- Initializing Foo board
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
> Notice the trick with an empty description to hide the call to `ident`
|
> Notice the trick with an empty description to hide the call to `ident`
|
||||||
> in the Finit progress output.
|
> in the Finit progress output.
|
||||||
|
|
||||||
@@ -367,9 +370,10 @@ The `initctl` tool has three commands to help debug and optimize the
|
|||||||
setup and monitoring of cgroups. See the `ps`, `top`, and `cgroup`
|
setup and monitoring of cgroups. See the `ps`, `top`, and `cgroup`
|
||||||
commands for details.
|
commands for details.
|
||||||
|
|
||||||
> **Note:** systems that do not support cgroups, specifically version 2,
|
> [!NOTE]
|
||||||
> are automatically detected. On such systems the above functionality
|
> Systems that do not support cgroups, specifically version 2, are
|
||||||
> is disabled early at boot.
|
> automatically detected. On such systems the above functionality is
|
||||||
|
> disabled early at boot.
|
||||||
|
|
||||||
|
|
||||||
Runparts & /etc/rc.local
|
Runparts & /etc/rc.local
|
||||||
@@ -573,9 +577,10 @@ file must be used to tell Finit to stop and start it on `reload` and
|
|||||||
`runlevel` changes. If `<>` holds more [conditions](doc/conditions.md),
|
`runlevel` changes. If `<>` holds more [conditions](doc/conditions.md),
|
||||||
these will also affect how a service is maintained.
|
these will also affect how a service is maintained.
|
||||||
|
|
||||||
> **Note:** even though it is possible to start services not belonging in
|
> [!NOTE]
|
||||||
> the current runlevel these services will not be respawned automatically
|
> Even though it is possible to start services not belonging in the
|
||||||
> by Finit if they exit (crash). Hence, if the runlevel is 2, the below
|
> current runlevel these services will not be respawned automatically by
|
||||||
|
> Finit if they exit (crash). Hence, if the runlevel is 2, the below
|
||||||
> Dropbear SSH service will not be restarted if it is killed or exits.
|
> Dropbear SSH service will not be restarted if it is killed or exits.
|
||||||
|
|
||||||
The `status` command is the default, it displays a quick overview of all
|
The `status` command is the default, it displays a quick overview of all
|
||||||
|
|||||||
@@ -1,7 +1,33 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# Run test suite with the correct configure params
|
# Run test suite with the correct configure params
|
||||||
|
run_make=1
|
||||||
|
jobs=17
|
||||||
|
|
||||||
make distclean
|
while [ $# -gt 0 ]; do
|
||||||
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
|
case "$1" in
|
||||||
--enable-x11-common-plugin --with-watchdog --with-keventd
|
-n|--no-make)
|
||||||
make -j17 clean check
|
run_make=0
|
||||||
|
;;
|
||||||
|
-j|--jobs)
|
||||||
|
shift
|
||||||
|
jobs="$1"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: $0 [--no-make] [-j N]"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$run_make" -eq 1 ]; then
|
||||||
|
make distclean
|
||||||
|
fi
|
||||||
|
|
||||||
|
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
|
||||||
|
--enable-x11-common-plugin --with-watchdog --with-keventd \
|
||||||
|
CFLAGS='-fsanitize=address -ggdb'
|
||||||
|
|
||||||
|
if [ "$run_make" -eq 1 ]; then
|
||||||
|
make -j"$jobs" clean check
|
||||||
|
fi
|
||||||
|
|||||||
+19
-9
@@ -1,4 +1,4 @@
|
|||||||
AC_INIT([Finit], [4.9-rc1], [https://github.com/troglobit/finit/issues],
|
AC_INIT([Finit], [4.13-pre], [https://github.com/troglobit/finit/issues],
|
||||||
[finit], [https://troglobit.com/projects/finit/])
|
[finit], [https://troglobit.com/projects/finit/])
|
||||||
AC_CONFIG_AUX_DIR(aux)
|
AC_CONFIG_AUX_DIR(aux)
|
||||||
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
|
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
|
||||||
@@ -12,6 +12,7 @@ AC_CONFIG_FILES([Makefile
|
|||||||
contrib/debian/Makefile contrib/debian/finit.d/Makefile contrib/debian/finit.d/available/Makefile
|
contrib/debian/Makefile contrib/debian/finit.d/Makefile contrib/debian/finit.d/available/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
|
||||||
doc/Makefile
|
doc/Makefile
|
||||||
|
libsystemd/Makefile libsystemd/libsystemd.pc
|
||||||
man/Makefile
|
man/Makefile
|
||||||
plugins/Makefile
|
plugins/Makefile
|
||||||
src/Makefile
|
src/Makefile
|
||||||
@@ -168,6 +169,10 @@ AC_ARG_WITH(watchdog,
|
|||||||
AS_HELP_STRING([--with-watchdog@<:@=DEV@:>@], [Enable built-in watchdog, default: /dev/watchdog]),
|
AS_HELP_STRING([--with-watchdog@<:@=DEV@:>@], [Enable built-in watchdog, default: /dev/watchdog]),
|
||||||
[watchdog=$withval], [with_watchdog=no watchdog=])
|
[watchdog=$withval], [with_watchdog=no watchdog=])
|
||||||
|
|
||||||
|
AC_ARG_WITH(libsystemd,
|
||||||
|
AS_HELP_STRING([--with-libsystemd], [Build replacement libsystemd library, default: yes]),
|
||||||
|
[with_libsystemd=$withval], [with_libsystemd=yes])
|
||||||
|
|
||||||
AC_ARG_WITH(hook-scripts-path,
|
AC_ARG_WITH(hook-scripts-path,
|
||||||
AS_HELP_STRING([--with-hook-scripts-path=DIR], [Base directory for hook scripts, default $libexecdir/finit/hook]),
|
AS_HELP_STRING([--with-hook-scripts-path=DIR], [Base directory for hook scripts, default $libexecdir/finit/hook]),
|
||||||
[hook_scripts_path=$withval], [hook_scripts_path=yes])
|
[hook_scripts_path=$withval], [hook_scripts_path=yes])
|
||||||
@@ -308,6 +313,9 @@ AS_IF([test "x$with_watchdog" != "xno"], [
|
|||||||
AC_DEFINE_UNQUOTED(WDT_DEVNODE, "$watchdog", [Built-in watchdog device node])], [
|
AC_DEFINE_UNQUOTED(WDT_DEVNODE, "$watchdog", [Built-in watchdog device node])], [
|
||||||
watchdog=])
|
watchdog=])
|
||||||
|
|
||||||
|
AS_IF([test "x$with_libsystemd" != "xno"], [
|
||||||
|
AC_DEFINE(HAVE_LIBSYSTEMD, 1, [Build replacement libsystemd library support])])
|
||||||
|
|
||||||
AS_IF([test "x$enable_hook_scripts_plugin" != "xno"], [
|
AS_IF([test "x$enable_hook_scripts_plugin" != "xno"], [
|
||||||
AS_IF([test "x$hook_scripts_path" = "xyes"], [hook_scripts_path=$libexecdir/finit/hook])
|
AS_IF([test "x$hook_scripts_path" = "xyes"], [hook_scripts_path=$libexecdir/finit/hook])
|
||||||
AC_EXPAND_DIR(hook_scripts_path, "$hook_scripts_path")
|
AC_EXPAND_DIR(hook_scripts_path, "$hook_scripts_path")
|
||||||
@@ -319,14 +327,15 @@ AS_IF([test "x$with_plugin_path" != "xno"], [
|
|||||||
AC_DEFINE_UNQUOTED(EXTERNAL_PLUGIN_PATH, "$plugin_path", [Built-in default: /usr/lib/finit/plugins:/usr/local/lib/finit/plugins])])
|
AC_DEFINE_UNQUOTED(EXTERNAL_PLUGIN_PATH, "$plugin_path", [Built-in default: /usr/lib/finit/plugins:/usr/local/lib/finit/plugins])])
|
||||||
|
|
||||||
# Control build with automake flags
|
# Control build with automake flags
|
||||||
AM_CONDITIONAL(BASH, [test "x$bash_dir" != "xno"])
|
AM_CONDITIONAL(BASH, [test "x$bash_dir" != "xno"])
|
||||||
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
||||||
AM_CONDITIONAL(KEVENTD, [test "x$with_keventd" != "xno"])
|
AM_CONDITIONAL(KEVENTD, [test "x$with_keventd" != "xno"])
|
||||||
AM_CONDITIONAL(SULOGIN, [test "x$with_sulogin" != "xno"])
|
AM_CONDITIONAL(SULOGIN, [test "x$with_sulogin" != "xno"])
|
||||||
AM_CONDITIONAL(WATCHDOGD, [test "x$with_watchdog" != "xno"])
|
AM_CONDITIONAL(WATCHDOGD, [test "x$with_watchdog" != "xno"])
|
||||||
AM_CONDITIONAL(DOC, [test "x$enable_doc" = "xyes"])
|
AM_CONDITIONAL(LIBSYSTEMD, [test "x$with_libsystemd" != "xno"])
|
||||||
AM_CONDITIONAL(CONTRIB, [test "x$enable_contrib" = "xyes"])
|
AM_CONDITIONAL(DOC, [test "x$enable_doc" = "xyes"])
|
||||||
AM_CONDITIONAL(TESTSERV, [test "x$enable_testserv_plugin" = "xyes"])
|
AM_CONDITIONAL(CONTRIB, [test "x$enable_contrib" = "xyes"])
|
||||||
|
AM_CONDITIONAL(TESTSERV, [test "x$enable_testserv_plugin" = "xyes"])
|
||||||
|
|
||||||
# Workaround for as-of-yet unreleased runstatedir support, planned for
|
# Workaround for as-of-yet unreleased runstatedir support, planned for
|
||||||
# autoconf 2.70, which some major distros have backported.
|
# autoconf 2.70, which some major distros have backported.
|
||||||
@@ -408,6 +417,7 @@ Optional features:
|
|||||||
Built-in sulogin......: $with_sulogin $sulogin
|
Built-in sulogin......: $with_sulogin $sulogin
|
||||||
Built-in watchdogd....: $with_watchdog $watchdog
|
Built-in watchdogd....: $with_watchdog $watchdog
|
||||||
Built-in logrotate....: $enable_logrotate
|
Built-in logrotate....: $enable_logrotate
|
||||||
|
Replacement libsystemd: $with_libsystemd
|
||||||
Use cgroup v2.........: $enable_cgroup
|
Use cgroup v2.........: $enable_cgroup
|
||||||
Parse kernel cmdline..: $enable_kernel_cmdline
|
Parse kernel cmdline..: $enable_kernel_cmdline
|
||||||
Keep kernel logging...: $enable_kernel_logging
|
Keep kernel logging...: $enable_kernel_logging
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
HowTo: Finit on Alpine Linux 3.4...3.19
|
HowTo: Finit on Alpine Linux 3.4...3.19
|
||||||
=======================================
|
=======================================
|
||||||
|
|
||||||
> **Blog** https://troglobit.com/post/2021-02-12-alpine-linux-with-finit/
|
> [!TIP]
|
||||||
|
> https://troglobit.com/post/2021-02-12-alpine-linux-with-finit/
|
||||||
|
|
||||||
HowTo use Finit to boot an [Alpine Linux][] system. It is assumed that
|
HowTo use Finit to boot an [Alpine Linux][] system. It is assumed that
|
||||||
the user has already installed make, a compiler, C library header files,
|
the user has already installed make, a compiler, C library header files,
|
||||||
|
|||||||
@@ -20,8 +20,9 @@ tools pre-systemd work as intended.
|
|||||||
|
|
||||||
root@debian:~# apt install initscripts console-setup
|
root@debian:~# apt install initscripts console-setup
|
||||||
|
|
||||||
> **Note:** as of Debian 11 (Bullseye), libuev and libite are part of
|
> [!TIP]
|
||||||
> the main section of Debian. So just install the -dev packages :)
|
> As of Debian 11 (Bullseye), libuev and libite are part of the main
|
||||||
|
> section of Debian. So just install the -dev packages :)
|
||||||
|
|
||||||
The following script can then be used to configure, build, install and
|
The following script can then be used to configure, build, install and
|
||||||
set up your system to run Finit:
|
set up your system to run Finit:
|
||||||
@@ -47,7 +48,8 @@ comands to `initctl`, followed by `reload` to activate your changes.
|
|||||||
You can also use a standard [/etc/rc.local](rc.local) for one-shot tasks
|
You can also use a standard [/etc/rc.local](rc.local) for one-shot tasks
|
||||||
and initialization like keyboard language etc.
|
and initialization like keyboard language etc.
|
||||||
|
|
||||||
> **NOTE:** X Window system, you may need to `sudo apt install elogind`
|
> [!NOTE]
|
||||||
|
> For the X Window system, you may need to `sudo apt install elogind`
|
||||||
> (Bullseye and later), followed by `initctl reload` to activate it (it
|
> (Bullseye and later), followed by `initctl reload` to activate it (it
|
||||||
> is enabled by default), and logout/login again. The elogind daemon
|
> is enabled by default), and logout/login again. The elogind daemon
|
||||||
> ensures a regular non-root user can start and interact with an X
|
> ensures a regular non-root user can start and interact with an X
|
||||||
|
|||||||
+30
-24
@@ -1,5 +1,5 @@
|
|||||||
Building
|
Building Finit
|
||||||
========
|
==============
|
||||||
|
|
||||||
* [Introduction](#introduction)
|
* [Introduction](#introduction)
|
||||||
* [Configure](#configure)
|
* [Configure](#configure)
|
||||||
@@ -17,14 +17,15 @@ optional plugins to enable. It depends on two external libraries:
|
|||||||
- [libuEv][], the event loop
|
- [libuEv][], the event loop
|
||||||
- [libite][] (-lite), much needed frog DNA
|
- [libite][] (-lite), much needed frog DNA
|
||||||
|
|
||||||
**NOTE:** Most free/open source software that uses `configure` default
|
> [!IMPORTANT]
|
||||||
to install to `/usr/local`. However, some Linux distributions do no
|
> Most free/open source software packages that use `configure` default
|
||||||
longer search that path for installed software, e.g. Fedora and Alpine
|
> to install to `/usr/local`. However, some Linux distributions do no
|
||||||
Linux. To get finit's configure script to find its dependencies you
|
> longer search that path for installed software, e.g. Fedora and Alpine
|
||||||
have to help the `pkg-config` tool a bit if you do not change the
|
> Linux. To get finit's configure script to find its dependencies you
|
||||||
default prefix path:
|
> have to help the `pkg-config` tool a bit if you do not change the
|
||||||
|
> default prefix path:
|
||||||
PKG_CONFIG_LIBDIR=/usr/local/lib/pkgconfig ./configure
|
>
|
||||||
|
> PKG_CONFIG_LIBDIR=/usr/local/lib/pkgconfig ./configure
|
||||||
|
|
||||||
The configure script checks for all dependencies, including the correct
|
The configure script checks for all dependencies, including the correct
|
||||||
version of the above mentioned libraries. Currently required versions:
|
version of the above mentioned libraries. Currently required versions:
|
||||||
@@ -71,12 +72,13 @@ Below are a few of the main switches to configure:
|
|||||||
|
|
||||||
For more configure flags, see <kbd>./configure --help</kbd>
|
For more configure flags, see <kbd>./configure --help</kbd>
|
||||||
|
|
||||||
> **Note:** the configure script is not available in the GIT sources. It is
|
> [!NOTE]
|
||||||
> however included in (officially supported) released tarballs. The
|
> The configure script is not available in the GIT sources. It is
|
||||||
> idea is that you should not need GNU autotools to build, only the
|
> however included in (officially supported) released tarballs. The
|
||||||
> above mentioned dependencies, a POSIX shell, a C compiler and make.
|
> idea is that you should not need GNU autotools to build, only the
|
||||||
> Any contributing to Finit can generate it from `configure.ac` using
|
> above mentioned dependencies, a POSIX shell, a C compiler and make.
|
||||||
> the `autogen.sh` script.
|
> Any contributing to Finit can generate it from `configure.ac` using
|
||||||
|
> the `autogen.sh` script.
|
||||||
|
|
||||||
|
|
||||||
Example
|
Example
|
||||||
@@ -115,10 +117,11 @@ Linux config to:
|
|||||||
|
|
||||||
CONFIG_UEVENT_HELPER_PATH="/sbin/mdev"
|
CONFIG_UEVENT_HELPER_PATH="/sbin/mdev"
|
||||||
|
|
||||||
**Note:** If you run into problems starting Finit, take a look at
|
> [!TIP]
|
||||||
`finit.c`. One of the most common problems is a custom Linux kernel
|
> If you run into problems starting Finit, take a look at `finit.c`.
|
||||||
build that lack `CONFIG_DEVTMPFS`. Another is too much cruft in the
|
> One of the most common problems is a custom Linux kernel build that
|
||||||
system `/etc/fstab`.
|
> lack `CONFIG_DEVTMPFS`. Another is too much cruft in the system
|
||||||
|
> `/etc/fstab`.
|
||||||
|
|
||||||
|
|
||||||
Running
|
Running
|
||||||
@@ -157,8 +160,10 @@ enabled. The default Finit rescue mode configuration is installed into
|
|||||||
|
|
||||||
By default the a root shell, without login, is started.
|
By default the a root shell, without login, is started.
|
||||||
|
|
||||||
> **Note:** in this mode `initctl` will not work. Use the `-f` flag to
|
> [!IMPORTANT]
|
||||||
> force `reboot`, `shutdown`, or `poweroff`.
|
> In rescue mode `initctl` will not work, the same goes for `reboot`,
|
||||||
|
> `shutdown`, and `poweroff` commands, provided they are the Finit
|
||||||
|
> versions of these commands. Use the `-f` flag to force the action.
|
||||||
|
|
||||||
|
|
||||||
Debugging
|
Debugging
|
||||||
@@ -187,8 +192,9 @@ kernel usually reboots: `configure --enable-emergency-shell`. However,
|
|||||||
the behavior of Finit is severely limited when this is enabled, so use
|
the behavior of Finit is severely limited when this is enabled, so use
|
||||||
it only for debugging start up issues when Finit crashes.
|
it only for debugging start up issues when Finit crashes.
|
||||||
|
|
||||||
**NOTE:** Neither of these options should be enabled on production
|
> [!CAUTION]
|
||||||
systems since they can potentially give a user root access.
|
> None of these options should be enabled on production systems since
|
||||||
|
> they can potentially give a user root access.
|
||||||
|
|
||||||
|
|
||||||
[1]: ftp://troglobit.com/finit/finit-4.3.tar.gz
|
[1]: ftp://troglobit.com/finit/finit-4.3.tar.gz
|
||||||
|
|||||||
+6
-4
@@ -4,10 +4,11 @@ Tips & Tricks with the kernel cmdline
|
|||||||
This document summarizes the different boot parameters that can be
|
This document summarizes the different boot parameters that can be
|
||||||
passed on the Linux kernel command line. Not limited to Finit.
|
passed on the Linux kernel command line. Not limited to Finit.
|
||||||
|
|
||||||
The `bool` setting is one of `on, off, true false, 1, 0`.
|
> [!IMPORTANT]
|
||||||
|
> Remember to use `--` to separate kernel parameters from parameters to
|
||||||
|
> init. E.g., `init=/sbin/finit -- finit.debug rescue`
|
||||||
|
|
||||||
> **NOTE:** remember to use `--` to separate kernel parameters from
|
The `bool` setting is one of `on, off, true false, 1, 0`.
|
||||||
> parameters to init. E.g., `init=/sbin/finit -- finit.debug rescue`
|
|
||||||
|
|
||||||
* `debug`: Enable kernel debug. Debug messages are printed to the
|
* `debug`: Enable kernel debug. Debug messages are printed to the
|
||||||
console until Finit starts up, unless `loglevel=7` (below) is used.
|
console until Finit starts up, unless `loglevel=7` (below) is used.
|
||||||
@@ -30,7 +31,8 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
|
|||||||
Very useful for selecting different boot modes, e.g. manufacturing test,
|
Very useful for selecting different boot modes, e.g. manufacturing test,
|
||||||
firmware upgrade, or rescue mode.
|
firmware upgrade, or rescue mode.
|
||||||
|
|
||||||
> Note: `<boot/...>` conditions cannot be cleared with `initctl`!
|
> [!NOTE]
|
||||||
|
> `<boot/...>` conditions cannot be cleared with `initctl`!
|
||||||
|
|
||||||
* `finit.config=/path/to/alternative/finit.conf`: override the
|
* `finit.config=/path/to/alternative/finit.conf`: override the
|
||||||
compile-time bootstrap config file, default:
|
compile-time bootstrap config file, default:
|
||||||
|
|||||||
+19
-11
@@ -47,9 +47,10 @@ both the `pid/setupd` *and* `pid/zebra` conditions are satisfied. A
|
|||||||
`pid/` condition is satisfied by the corresponding service's PID file
|
`pid/` condition is satisfied by the corresponding service's PID file
|
||||||
being created, i.e., the service's default readiness notification.
|
being created, i.e., the service's default readiness notification.
|
||||||
|
|
||||||
**NOTE:** Conditions also stop services when a condition is no longer
|
> [!IMPORTANT]
|
||||||
asserted. I.e., if the Zebra process above stops or restarts, netd
|
> Conditions also stop services when a condition is no longer asserted.
|
||||||
will also stop or restart.
|
> I.e., if the `zebra` process above stops or restarts, `netd` will also
|
||||||
|
> stop or restart.
|
||||||
|
|
||||||
Another example is `dropbear`, it does not support `SIGHUP`, but we can
|
Another example is `dropbear`, it does not support `SIGHUP`, but we can
|
||||||
also see optional sourcing of arguments from an environment file:
|
also see optional sourcing of arguments from an environment file:
|
||||||
@@ -106,11 +107,16 @@ on this, see [Internals](#internals).) Thus, after a reconfiguration it
|
|||||||
is up to the "owner" of the condition to convey the new (or possibly
|
is up to the "owner" of the condition to convey the new (or possibly
|
||||||
unchanged) state of it.
|
unchanged) state of it.
|
||||||
|
|
||||||
> **Note:** For `pid/` conditions it is expected that services "touch"
|
|
||||||
> or recreate their PID file on `SIGHUP`.
|
|
||||||
|
|
||||||
Static (one-shot) conditions, like `usr/`, never enter the `flux` state.
|
Static (one-shot) conditions, like `usr/`, never enter the `flux` state.
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> For `pid/` conditions it is expected that the service reassert, i.e.,
|
||||||
|
> "touch" or recreate, their PID file on `SIGHUP`. This can be done by
|
||||||
|
> calling `utimensat()` on the PID file. Provided, of course, that the
|
||||||
|
> service supports reloading on `SIGHUP`, otherwise it will be restarted
|
||||||
|
> by Finit when they instead exit on the signal. For such services, use
|
||||||
|
> `<!>` to tell Finit the service does not support `SIGHUP`.
|
||||||
|
|
||||||
|
|
||||||
Built-in Conditions
|
Built-in Conditions
|
||||||
-------------------
|
-------------------
|
||||||
@@ -171,9 +177,10 @@ Built-in conditions:
|
|||||||
- `boot/arg`
|
- `boot/arg`
|
||||||
- `dev/node` and `dev/dir/node`
|
- `dev/node` and `dev/dir/node`
|
||||||
|
|
||||||
**Note:** `up` means administratively up, the interface flag `IFF_UP`.
|
> [!NOTE]
|
||||||
`running` is the `IFF_RUNNING` flag, meaning operatively up. The
|
> Here, `up` means administratively up, the interface flag `IFF_UP`.
|
||||||
difference is that `running` tells if the NIC has link.
|
> `running` is the `IFF_RUNNING` flag, meaning operatively up. The
|
||||||
|
> difference is that `running` tells if the NIC has link.
|
||||||
|
|
||||||
|
|
||||||
Composition
|
Composition
|
||||||
@@ -205,8 +212,9 @@ the service stanza for the daemon. It is far from optimal since any
|
|||||||
synchronization of depending services may fail due to the daemon not
|
synchronization of depending services may fail due to the daemon not
|
||||||
having reinitialized/created their IPC sockets, or similar.
|
having reinitialized/created their IPC sockets, or similar.
|
||||||
|
|
||||||
> **Note:** in versions of Finit prior to v4, the PID conditions were
|
> [!NOTE]
|
||||||
> called 'svc' conditions, and they were far more complex.
|
> In versions of Finit prior to v4, the PID conditions were called 'svc'
|
||||||
|
> conditions, and they were far more complex.
|
||||||
|
|
||||||
|
|
||||||
Debugging
|
Debugging
|
||||||
|
|||||||
+148
-99
@@ -18,8 +18,8 @@ Finit Configuration
|
|||||||
* [Alternate rcS.d/](#alternate-rcs-d-)
|
* [Alternate rcS.d/](#alternate-rcs-d-)
|
||||||
* [Resource Limits](#resource-limits)
|
* [Resource Limits](#resource-limits)
|
||||||
* [Runlevels](#runlevels)
|
* [Runlevels](#runlevels)
|
||||||
* [One-shot Commands (sequence)](#one-shot-commands--sequence-)
|
* [One-shot Commands (sequence)](#one-shot-commands-sequence)
|
||||||
* [One-shot Commands (parallel)](#one-shot-commands--parallel-)
|
* [One-shot Commands (parallel)](#one-shot-commands-parallel)
|
||||||
* [SysV Init Scripts](#sysv-init-scripts)
|
* [SysV Init Scripts](#sysv-init-scripts)
|
||||||
* [Services](#services)
|
* [Services](#services)
|
||||||
* [Run-parts Scripts](#run-parts-scripts)
|
* [Run-parts Scripts](#run-parts-scripts)
|
||||||
@@ -46,8 +46,9 @@ Plugins start at [hook points](plugins.md#hooks) and can run various set
|
|||||||
up, or install event handlers that later provide runtime services, e.g.,
|
up, or install event handlers that later provide runtime services, e.g.,
|
||||||
PID file monitoring, or [conditions](conditions.md).
|
PID file monitoring, or [conditions](conditions.md).
|
||||||
|
|
||||||
> **Tip:** see [SysV Init Compatibility](#sysv-init-compatibility) for
|
> [!TIP]
|
||||||
> help to quickly get going with an existing SysV or BusyBox init setup.
|
> See [SysV Init Compatibility](#sysv-init-compatibility) for help to
|
||||||
|
> quickly get going with an existing SysV or BusyBox init setup.
|
||||||
|
|
||||||
|
|
||||||
### Configuration Files
|
### Configuration Files
|
||||||
@@ -127,8 +128,9 @@ properties of the `run` statement. For an example on the relation of
|
|||||||
`service` and `run` statements, and dependency handling between them,
|
`service` and `run` statements, and dependency handling between them,
|
||||||
see [Conditional Loading](#conditional-loading), below.
|
see [Conditional Loading](#conditional-loading), below.
|
||||||
|
|
||||||
> **Note:** the `finit.conf` and `finit.d/` names are only defaults.
|
> [!NOTE]
|
||||||
> They can be changed at compile-time with two `configure` options:
|
> The names `finit.conf` and `finit.d/` are only defaults. They can be
|
||||||
|
> changed at compile-time with two `configure` options:
|
||||||
> `--with-config=/etc/foo.conf` and `--with-rcsd=/var/foo.d`.
|
> `--with-config=/etc/foo.conf` and `--with-rcsd=/var/foo.d`.
|
||||||
>
|
>
|
||||||
> They can also be overridden from the [kernel command line](cmdline.md)
|
> They can also be overridden from the [kernel command line](cmdline.md)
|
||||||
@@ -187,8 +189,9 @@ above, provided their respective mount point exists.
|
|||||||
|
|
||||||
With all filesystems mounted, Finit calls `swapon`.
|
With all filesystems mounted, Finit calls `swapon`.
|
||||||
|
|
||||||
> **Tip:** to see what happens when all filesystems are mounted, have a
|
> [!TIP]
|
||||||
> look at the [`bootmisc.so` plugin](plugins.md).
|
> To see what happens when all filesystems are mounted, have a look at
|
||||||
|
> the [`bootmisc.so` plugin](plugins.md).
|
||||||
|
|
||||||
At shutdown, and after having stopped all services and other lingering
|
At shutdown, and after having stopped all services and other lingering
|
||||||
processes have been killed, filesystems are unmounted in the reverse
|
processes have been killed, filesystems are unmounted in the reverse
|
||||||
@@ -198,6 +201,18 @@ order, and `swapoff` is called.
|
|||||||
|
|
||||||
### Runlevels
|
### Runlevels
|
||||||
|
|
||||||
|
Finit supports runlevels, but unlike other init systems runlevels are
|
||||||
|
declared per service/run/task/sysv command. When booting up a system
|
||||||
|
Finit pass through three phases:
|
||||||
|
|
||||||
|
1. Setting up the console, parsing any command line options, and other
|
||||||
|
housekeeping tasks like mounting all filesystems, and calling `fsck`
|
||||||
|
2. Starting all run/task/services in runlevel S, then waiting for all
|
||||||
|
services to have started, and all run/tasks to have completed
|
||||||
|
3. Go to runlevel 2, or whatever the user has set in the configuration
|
||||||
|
|
||||||
|
Available runlevels:
|
||||||
|
|
||||||
- ` S`: bootStrap
|
- ` S`: bootStrap
|
||||||
- ` 1`: Single user mode
|
- ` 1`: Single user mode
|
||||||
- `2-5`: traditional multi-user mode
|
- `2-5`: traditional multi-user mode
|
||||||
@@ -205,37 +220,40 @@ order, and `swapoff` is called.
|
|||||||
- `7-9`: multi-user mode (extra)
|
- `7-9`: multi-user mode (extra)
|
||||||
- ` 0`: shutdown
|
- ` 0`: shutdown
|
||||||
|
|
||||||
Runlevels are declared per service/run/task/sysv command. Starting in
|
Runlevel S (bootStrap), is for tasks supposed to run once at boot, and
|
||||||
runlevel S (bootStrap), usually only for tasks supposed to run once at
|
services like `syslogd`, which need to start early and run throughout
|
||||||
boot, and services like `syslogd`, which you need to start and run
|
the lifetime of your system.
|
||||||
throughout the whole time your system is up.
|
|
||||||
|
|
||||||
Before `S` is started, however, Finit performs a lot of housekeeping
|
Example:
|
||||||
tasks like mounting all filesystems, calling `fsck` if needed, and
|
|
||||||
making sure the everything is OK.
|
|
||||||
|
|
||||||
task [S] /lib/console-setup/console-setup.sh
|
task [S] /lib/console-setup/console-setup.sh
|
||||||
service [S12345] env:-/etc/default/rsyslog rsyslogd -n $RSYSLOGD_ARGS
|
service [S12345] env:-/etc/default/rsyslog rsyslogd -n $RSYSLOGD_ARGS
|
||||||
|
|
||||||
After runlevel S, Finit proceeds to runlevel 2. This can be changed in
|
When bootstrap has completed, Finit moves to runlevel 2. This can be
|
||||||
`/etc/finit.conf` using the `runlevel N` directive, or by a script
|
changed in `/etc/finit.conf` using the `runlevel N` directive, or by a
|
||||||
running in runlevel S that calls, e.g., `initctl runlevel 9`. The
|
script running in runlevel S that calls, e.g., `initctl runlevel 9`.
|
||||||
latter is useful if startup scripts detect problems outside of Finit's
|
The latter is useful if startup scripts detect problems outside of
|
||||||
control, e.g., critical services/devices missing or hardware problems.
|
Finit's control, e.g., critical services/devices missing or hardware
|
||||||
|
problems.
|
||||||
|
|
||||||
Before starting the services in runlevel 2, Finit first stops everything
|
Each runlevel must be allowed to "complete". Meaning, all services in
|
||||||
that is not allowed to run in 2, and then brings up networking.
|
runlevel S must have started and all run/tasks have been started and
|
||||||
Networking is expected to be available in all runlevels except: S, 1
|
collected (exited). Finit waits 120 seconds for all run/tasks in S to
|
||||||
(single user level), 6, and 0. Networking is enabled either by the
|
complete before proceeding to 2.
|
||||||
`network script` directive, or if you have an `/etc/network/interfaces`
|
|
||||||
file, Finit calls `ifup -a` -- at the very least the loopback interface
|
|
||||||
is brought up.
|
|
||||||
|
|
||||||
> **Note:** when moving from runlevel S to 2, all run/task/services that
|
Finit first stops everything that is not allowed to run in 2, and then
|
||||||
> were constrained to runlevel S only are dropped from bookkeeping. So
|
brings up networking. Networking is expected to be available in all
|
||||||
> when reaching the prompt, `initctl` will not show these run/tasks.
|
runlevels except: S, 1 (single user level), 6, and 0. Networking is
|
||||||
> This is a safety mechanism to prevent bootstrap-only tasks from
|
enabled either by the `network script` directive, or if you have an
|
||||||
> accidentally being run again. E.g., `console-setup.sh` above.
|
`/etc/network/interfaces` file, Finit calls `ifup -a` -- at the very
|
||||||
|
least the loopback interface is brought up.
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> When moving from runlevel S to 2, all run/task/services that were
|
||||||
|
> constrained to runlevel S only are dropped from bookkeeping. So when
|
||||||
|
> reaching the prompt, `initctl` will not show these run/tasks. This is
|
||||||
|
> a safety mechanism to prevent bootstrap-only tasks from accidentally
|
||||||
|
> being run again. E.g., `console-setup.sh` above.
|
||||||
|
|
||||||
|
|
||||||
### Managing Services
|
### Managing Services
|
||||||
@@ -322,7 +340,8 @@ the `ps` command we can see that the process is started with:
|
|||||||
|
|
||||||
foo -n --extra-arg=bar -s -x
|
foo -n --extra-arg=bar -s -x
|
||||||
|
|
||||||
> **Note:** the leading `-` determines if Finit should treat a missing
|
> [!NOTE]
|
||||||
|
> The leading `-` in `env:` determines if Finit should treat a missing
|
||||||
> environment file as blocking the start of the service or not. When
|
> environment file as blocking the start of the service or not. When
|
||||||
> `-` is used, a missing environment file does *not* block the start.
|
> `-` is used, a missing environment file does *not* block the start.
|
||||||
|
|
||||||
@@ -374,7 +393,7 @@ like this:
|
|||||||
|
|
||||||
The `notify:none` syntax is for completeness in systems which run in
|
The `notify:none` syntax is for completeness in systems which run in
|
||||||
`readiness pid` mode (default). Services declared with `notify:none`
|
`readiness pid` mode (default). Services declared with `notify:none`
|
||||||
will assert ready condition as soon as Finit has started them, e.g.,
|
will transition to ready as soon as Finit has started them, e.g.,
|
||||||
`service/qux/ready`.
|
`service/qux/ready`.
|
||||||
|
|
||||||
To synchronize two services the following condition can be used:
|
To synchronize two services the following condition can be used:
|
||||||
@@ -384,22 +403,23 @@ To synchronize two services the following condition can be used:
|
|||||||
|
|
||||||
For details on the syntax and options, see below.
|
For details on the syntax and options, see below.
|
||||||
|
|
||||||
> **Note:** on `initctl reload` conditions are normally set in "flux",
|
> [!NOTE]
|
||||||
> while figuring out which to stop, start or restart. Services that
|
> On `initctl reload` conditions are set in "flux", while figuring out
|
||||||
> need to be restarted have their `ready` condition removed prior to
|
> which services to stop, start or restart. Services that need to be
|
||||||
> Finit sending them SIGHUP (if they support that), or stop-starting
|
> restarted have their `ready` condition removed before Finit issue a
|
||||||
> them. A daemon is expected to reassert its readiness, e.g. systemd
|
> SIGHUP (if they support that), or stop-starting them. A daemon is
|
||||||
> style daemons to write `READY=1\n`.
|
> expected to reassert its readiness, e.g. systemd style daemons to
|
||||||
|
> write `READY=1\n`.
|
||||||
>
|
>
|
||||||
> However, the s6 notify mode does not support this because in s6 you
|
> However, the s6 notify mode does not support this because in s6 you
|
||||||
> are expected to close your notify descriptor after having written
|
> are expected to close your notify descriptor after having written
|
||||||
> `\n`. This means s6 style daemons currently must be stop-started.
|
> `\n`. This means s6 style daemons currently must be stop-started.
|
||||||
> (Declare the service with `<!>` in its condition statement.)
|
> (Declare the service with `<!>` in its condition statement.)
|
||||||
>
|
>
|
||||||
> For native PID file style readiness notification a daemon is expected
|
> For default, PID file style readiness notification, daemons are
|
||||||
> to either create its PID file, if it does not exist yet, or touch it
|
> expected to either create their PID files, or touch it using
|
||||||
> using `utimensat()` or similar. This triggers both the `<pid/>` and
|
> `utimensat()` to reassert readiness. Triggering both the `<pid/>`
|
||||||
> `<.../ready>` conditions.
|
> and `<.../ready>` conditions.
|
||||||
|
|
||||||
|
|
||||||
Service Wrapper Scripts
|
Service Wrapper Scripts
|
||||||
@@ -429,9 +449,10 @@ example employs a wrapper script in `/etc/start.d`.
|
|||||||
# Execute the program
|
# Execute the program
|
||||||
exec /usr/bin/program $OPTIONS
|
exec /usr/bin/program $OPTIONS
|
||||||
|
|
||||||
> **Note:** the example sets `<!>` to denote that it doesn't support
|
> [!NOTE]
|
||||||
> `SIGHUP`. That way Finit will stop/start the service
|
> The example sets `<!>` to denote that it doesn't support `SIGHUP`.
|
||||||
> instead of sending SIGHUP at restart/reload events.
|
> That way Finit will stop/start the service instead of sending SIGHUP
|
||||||
|
> at restart/reload events.
|
||||||
|
|
||||||
|
|
||||||
Templating
|
Templating
|
||||||
@@ -514,6 +535,7 @@ A daemon using `SCHED_RR` currently need to run outside the default cgroups.
|
|||||||
|
|
||||||
service [...] <...> cgroup.root /path/to/daemon arg -- Real-Time process
|
service [...] <...> cgroup.root /path/to/daemon arg -- Real-Time process
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
> Linux cgroups and details surrounding values are not explained in the
|
> Linux cgroups and details surrounding values are not explained in the
|
||||||
> Finit documentation. The Linux admin-guide cover this well:
|
> Finit documentation. The Linux admin-guide cover this well:
|
||||||
> <https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html>
|
> <https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html>
|
||||||
@@ -539,12 +561,9 @@ service name:sysklogd [S123456789] \
|
|||||||
```
|
```
|
||||||
|
|
||||||
The .conf files `/etc/finit.conf` and `/etc/finit.d/*` support the
|
The .conf files `/etc/finit.conf` and `/etc/finit.d/*` support the
|
||||||
following directives:
|
following directives. Some directives have restrictions, e.g., only
|
||||||
|
available at bootstrap, runlevel `S`, see [Limitations](#limitations)
|
||||||
|
below for details.
|
||||||
> **Note:** not all directives are available in `/etc/finit.d/*.conf`
|
|
||||||
> and some directives are only available at bootstrap, runlevel `S`,
|
|
||||||
> see [Limitations](#limitations) below for details.
|
|
||||||
|
|
||||||
|
|
||||||
### Hostname
|
### Hostname
|
||||||
@@ -556,7 +575,8 @@ the contents of that file is used.
|
|||||||
|
|
||||||
Deprecated. We recommend using `/etc/hostname` instead.
|
Deprecated. We recommend using `/etc/hostname` instead.
|
||||||
|
|
||||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
> [!NOTE]
|
||||||
|
> Only read and executed in runlevel S (bootstrap).
|
||||||
|
|
||||||
|
|
||||||
### Kernel Modules
|
### Kernel Modules
|
||||||
@@ -574,7 +594,8 @@ BusyBox mdev tool, add to `/etc/mdev.conf`:
|
|||||||
|
|
||||||
$MODALIAS=.* root:root 0660 @modprobe -b "$MODALIAS"
|
$MODALIAS=.* root:root 0660 @modprobe -b "$MODALIAS"
|
||||||
|
|
||||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
> [!NOTE]
|
||||||
|
> Only read and executed in runlevel S (bootstrap).
|
||||||
|
|
||||||
|
|
||||||
### Networking
|
### Networking
|
||||||
@@ -587,7 +608,8 @@ Deprecated. We recommend using dedicated task/run stanzas per runlevel,
|
|||||||
or `/etc/network/interfaces` if you have a system with `ifupdown`, like
|
or `/etc/network/interfaces` if you have a system with `ifupdown`, like
|
||||||
Debian, Ubuntu, Linux Mint, or an embedded BusyBox system.
|
Debian, Ubuntu, Linux Mint, or an embedded BusyBox system.
|
||||||
|
|
||||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
> [!NOTE]
|
||||||
|
> Only read and executed in runlevel S (bootstrap).
|
||||||
|
|
||||||
|
|
||||||
### Alternate finit.d/
|
### Alternate finit.d/
|
||||||
@@ -608,8 +630,9 @@ another set of .conf files, e.g.:
|
|||||||
|
|
||||||
rcsd /etc/factory.d
|
rcsd /etc/factory.d
|
||||||
|
|
||||||
> **Note:** this directive is only available from the top-level
|
> [!NOTE]
|
||||||
> bootstrap .conf file.
|
> This directive is only available from the top-level bootstrap .conf
|
||||||
|
> file, usually `/etc/finit.conf`.
|
||||||
|
|
||||||
### Resource Limits
|
### Resource Limits
|
||||||
|
|
||||||
@@ -642,16 +665,18 @@ stanzas can share the same rlimits if they are in the same .conf.
|
|||||||
|
|
||||||
**Syntax:** `runlevel <N>`
|
**Syntax:** `runlevel <N>`
|
||||||
|
|
||||||
The system runlevel to go to after bootstrap (S) has completed. `N`
|
The system runlevel to go to after bootstrap (S) has completed. `N` is
|
||||||
is the runlevel number 0-9, where 6 is reserved for reboot and 0 for
|
the runlevel number 0-9, where 6 is reserved for reboot and 0 for halt.
|
||||||
halt.
|
Completed in this context means all services have been started and all
|
||||||
|
run/tasks have been started and collected.
|
||||||
|
|
||||||
It is recommended to keep runlevel 1 as single-user mode, because
|
It is recommended to keep runlevel 1 as single-user mode, because
|
||||||
Finit disables networking in this mode.
|
Finit disables networking in this mode.
|
||||||
|
|
||||||
*Default:* 2
|
*Default:* 2
|
||||||
|
|
||||||
> **Note:** only read and executed in runlevel S (bootstrap).
|
> [!NOTE]
|
||||||
|
> Only read and executed in runlevel S (bootstrap).
|
||||||
|
|
||||||
|
|
||||||
### One-shot Commands (sequence)
|
### One-shot Commands (sequence)
|
||||||
@@ -665,10 +690,11 @@ optional arguments and description. `run` commands are guaranteed to be
|
|||||||
completed before running the next command. Useful when serialization is
|
completed before running the next command. Useful when serialization is
|
||||||
required.
|
required.
|
||||||
|
|
||||||
> **Warning:** try to avoid the `run` command. It blocks much of the
|
> [!WARNING]
|
||||||
> functionality in Finit, like (re)starting other (perhaps crashing)
|
> Try to avoid the `run` command. It blocks much of the functionality
|
||||||
> services while a `run` task is executing. Use other synchronization
|
> in Finit, like (re)starting other (perhaps crashing) services while a
|
||||||
> mechanisms instead, like conditions.
|
> `run` task is executing. Use other synchronization mechanisms
|
||||||
|
> instead, like conditions.
|
||||||
|
|
||||||
Incomplete list of unsupported `initctl` commands in `run` tasks:
|
Incomplete list of unsupported `initctl` commands in `run` tasks:
|
||||||
|
|
||||||
@@ -708,7 +734,7 @@ non-trivial constructs are better placed in a separate shell script.
|
|||||||
|
|
||||||
Similar to `task` is the `sysv` stanza, which can be used to call SysV
|
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
|
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.
|
reuse much of existing setup and init scripts in Linux distributions.
|
||||||
|
|
||||||
When entering an allowed runlevel, Finit calls `init-script start`, when
|
When entering an allowed runlevel, Finit calls `init-script start`, when
|
||||||
entering a disallowed runlevel, Finit calls `init-script stop`, and if
|
entering a disallowed runlevel, Finit calls `init-script stop`, and if
|
||||||
@@ -723,7 +749,8 @@ file, but rather watch that file for the resulting forked-off PID. This
|
|||||||
syntax also works for forking daemons that do not have a command line
|
syntax also works for forking daemons that do not have a command line
|
||||||
option to run it in the foreground, more on this below in `service`.
|
option to run it in the foreground, more on this below in `service`.
|
||||||
|
|
||||||
> **Tip:** see also [SysV Init Compatibility](#sysv-init-compatibility).
|
> [!TIP]
|
||||||
|
> See also [SysV Init Compatibility](#sysv-init-compatibility).
|
||||||
|
|
||||||
|
|
||||||
### Services
|
### Services
|
||||||
@@ -731,13 +758,13 @@ option to run it in the foreground, more on this below in `service`.
|
|||||||
**Syntax:** `service [LVLS] <COND> /path/to/daemon ARGS -- Optional description`
|
**Syntax:** `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. Finit tries to restart services that die, by
|
exits prematurely. Finit tries to restart services that die, by default
|
||||||
default 10 times before giving up and marking them as *crashed*.
|
10 times before giving up and marking them as *crashed*. After which
|
||||||
After which they have to be manually restarted with `initctl restart
|
they have to be manually restarted with `initctl restart NAME`. The
|
||||||
NAME`. The limits controling this are configurable, see the options
|
limits controlling this are configurable, see the options below.
|
||||||
below.
|
|
||||||
|
|
||||||
> **Tip:** to allow endless restarts, see below option `respawn`
|
> [!TIP]
|
||||||
|
> To allow endless restarts, see below option `respawn`
|
||||||
|
|
||||||
For daemons that support it, we recommend appending `--foreground`,
|
For daemons that support it, we recommend appending `--foreground`,
|
||||||
`--no-background`, `-n`, `-F`, or similar command line argument to
|
`--no-background`, `-n`, `-F`, or similar command line argument to
|
||||||
@@ -886,9 +913,20 @@ configurable with the following options:
|
|||||||
endless restarts. Useful in many use-cases, but not what `service`
|
endless restarts. Useful in many use-cases, but not what `service`
|
||||||
was originally designed for so not the default behavior
|
was originally designed for so not the default behavior
|
||||||
* `oncrash:reboot` -- when all retries have failed, and the service
|
* `oncrash:reboot` -- when all retries have failed, and the service
|
||||||
has *crashed*, if this option is set the system is rebooted.
|
has *crashed*, if this option is set the system is rebooted
|
||||||
* `oncrash:script` -- similarly, but instead of rebooting, call the
|
* `oncrash:script` -- similarly, but instead of rebooting, call the
|
||||||
`post:script` action if set, see below.
|
`post:script` action with exit code `crashed`, see below
|
||||||
|
* `reload:script [args]` -- some services do not support `SIGHUP` but
|
||||||
|
may have other ways to update the configuration of a running daemon.
|
||||||
|
When `reload:script` is defined it is preferred over `SIGHUP`
|
||||||
|
* `stop:script [args]` -- some services may require alternate methods
|
||||||
|
to be stopped. When `stop:script` is defined it is preferred over
|
||||||
|
`SIGTERM` and `stop`, for `service` and `sysv` stanzas, respectively
|
||||||
|
|
||||||
|
> [!CAUTION]
|
||||||
|
> Both `reload:script` and `stop:script` are called as PID 1, without
|
||||||
|
> any timeout! Meaning, it is up to you to ensure the script is not
|
||||||
|
> blocking for seconds at a time or never terminates.
|
||||||
|
|
||||||
When stopping a service (run/task/sysv/service), either manually or when
|
When stopping a service (run/task/sysv/service), either manually or when
|
||||||
moving to another runlevel, Finit starts by sending `SIGTERM`, to allow
|
moving to another runlevel, Finit starts by sending `SIGTERM`, to allow
|
||||||
@@ -899,32 +937,39 @@ e.g., `halt:SIGPWR`. To change the delay between the stop signal and
|
|||||||
KILL, use the option `kill:<1-60>`, e.g., `kill:10` to wait 10 seconds
|
KILL, use the option `kill:<1-60>`, e.g., `kill:10` to wait 10 seconds
|
||||||
before sending `SIGKILL`.
|
before sending `SIGKILL`.
|
||||||
|
|
||||||
Services, including the `sysv` variant, support pre/post/ready scripts:
|
Services, including the `sysv` variant, support pre/post/ready and
|
||||||
|
cleanup scripts:
|
||||||
|
|
||||||
* `pre:[0-3600,]script`
|
* `pre:[0-3600,]script` -- called before the sysv/service is stated
|
||||||
* `post:[0-3600,]script`
|
* `post:[0-3600,]script` -- called after the sysv/service has stopped
|
||||||
* `ready:[0-3600,]script`
|
* `ready:[0-3600,]script` -- called when the sysv/service is ready
|
||||||
|
* `cleanup:[0-3600,]script` -- called when run/task/sysv/service is removed
|
||||||
|
|
||||||
The optional number (0-3600) is the timeout before Finit kills the
|
The optional number (0-3600) is the timeout before Finit kills the
|
||||||
script, it defaults to the kill delay value and can be disabled by
|
script, it defaults to the kill delay value and can be disabled by
|
||||||
setting it to zero. These scripts run as the same `@USER:GROUP` as the
|
setting it to zero. These scripts run as the same `@USER:GROUP` as the
|
||||||
service itself, with any `env:file` sourced. The scripts must use an
|
service itself, with any `env:file` sourced. The scripts are executed
|
||||||
absolute path, but are executed from the `$HOME` of the given user. The
|
from the `$HOME` of the given user. The scripts are not called with any
|
||||||
scripts are not called with any argument, but get a set of environment
|
argument, but get a set of environment variables:
|
||||||
variables:
|
|
||||||
|
|
||||||
* `SERVICE_IDENT=foo:1`
|
* `SERVICE_IDENT=foo:1`
|
||||||
* `SERVICE_NAME=foo`
|
* `SERVICE_NAME=foo`
|
||||||
* `SERVICE_ID=1`
|
* `SERVICE_ID=1`
|
||||||
|
|
||||||
The `post:script` is called with an additional set of environment
|
The `post:script` is called with an additional set of environment
|
||||||
variables:
|
variables. Yes, the text is correct, the naming was an accident:
|
||||||
|
|
||||||
- `EXIT_CODE=[exited,signal]`: set to one of `exited` or `signal`
|
- `EXIT_CODE=[exited,signal,crashed]`: normal exit, signaled, or
|
||||||
|
crashed
|
||||||
- `EXIT_STATUS=[num,SIGNAME]`: set to one of exit status code from
|
- `EXIT_STATUS=[num,SIGNAME]`: set to one of exit status code from
|
||||||
the program, if it exited normally, or the signal name (`HUP`,
|
the program, if it exited normally, or the signal name (`HUP`,
|
||||||
`TERM`, etc.) if it exited due to signal
|
`TERM`, etc.) if it exited due to signal
|
||||||
|
|
||||||
|
When a run/task/sys/service is removed (disable + reload) it is first
|
||||||
|
stopped and then removed from the runlevel. The `post:script` always
|
||||||
|
runs when the process has stopped, and the `cleanup:script` runs when
|
||||||
|
the the stanza has been removed from the runlevel.
|
||||||
|
|
||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
> These script actions are intended for setup, cleanup, and readiness
|
> These script actions are intended for setup, cleanup, and readiness
|
||||||
> notification. It is up to the user to ensure the scripts terminate.
|
> notification. It is up to the user to ensure the scripts terminate.
|
||||||
@@ -1027,8 +1072,9 @@ before continuing. None of them can issue commands to start, stop, or
|
|||||||
restart other services. Also, ensure all your services and programs
|
restart other services. Also, ensure all your services and programs
|
||||||
either terminate or start in the background or you will block Finit.
|
either terminate or start in the background or you will block Finit.
|
||||||
|
|
||||||
> **Note:** `runparts` scrips are only read and executed in runlevel S.
|
> [!NOTE]
|
||||||
> See [hook scripts](plugins.md#hooks) for other ways to run scripts at
|
> `runparts` scripts are only read and executed in runlevel S. See
|
||||||
|
> [hook scripts](plugins.md#hooks) for other ways to run scripts at
|
||||||
> certain points during the complete lifetime of the system.
|
> certain points during the complete lifetime of the system.
|
||||||
|
|
||||||
**Recommendations:**
|
**Recommendations:**
|
||||||
@@ -1301,8 +1347,9 @@ This rescue mode can be disabled at configure time using:
|
|||||||
|
|
||||||
The rescue mode comes in two flavors; *traditional* and *fallback*.
|
The rescue mode comes in two flavors; *traditional* and *fallback*.
|
||||||
|
|
||||||
> **Note:** in this mode `initctl` will not work. Use the `-f` flag to
|
> [!NOTE]
|
||||||
> force `reboot`, `shutdown`, or `poweroff`.
|
> In this mode `initctl` will not work. Use the `-f` flag to force
|
||||||
|
> `reboot`, `shutdown`, or `poweroff`.
|
||||||
|
|
||||||
|
|
||||||
### Traditional
|
### Traditional
|
||||||
@@ -1314,11 +1361,12 @@ program is used instead. If a successful login is made, or if the user
|
|||||||
exits (Ctrl-D), the rescue mode is ended and the system boots up
|
exits (Ctrl-D), the rescue mode is ended and the system boots up
|
||||||
normally.
|
normally.
|
||||||
|
|
||||||
> **Note:** the bundled sulogin in Finit can at configure time be given
|
> [!WARNING]
|
||||||
> another user than the default (root). If the sulogin user does not
|
> The bundled sulogin in Finit can at configure time be given another
|
||||||
> have a password, or __the account is locked__, the user is presented
|
> user than the default (root). If the sulogin user does not have a
|
||||||
> with a password-less `"Press enter to enter maintenance mode."`,
|
> password, or __the account is locked__, the user is presented with a
|
||||||
> prompt which opens up a root shell.
|
> prompt: `"Press enter to enter maintenance mode."`, which will open
|
||||||
|
> up a root shell *without prompting for password*!
|
||||||
|
|
||||||
|
|
||||||
### Fallback
|
### Fallback
|
||||||
@@ -1366,10 +1414,11 @@ These can now also be set in any `.conf` file in `/etc/finit.d`.
|
|||||||
There is, however, nothing preventing you from having all configuration
|
There is, however, nothing preventing you from having all configuration
|
||||||
settings in `/etc/finit.conf`.
|
settings in `/etc/finit.conf`.
|
||||||
|
|
||||||
> **Note:** The `/etc/finit.d` directory was previously the default
|
> [!IMPORTANT]
|
||||||
> Finit [runparts](#run-parts-scripts) directory. Finit >=v4.0
|
> The default `rcsd`, i.e., `/etc/finit.d`, was previously the Finit
|
||||||
> no longer has a default `runparts` directory, make sure to
|
> [runparts](#run-parts-scripts) directory. Finit >=v4.0 no longer has
|
||||||
> update your setup, or the finit configuration, accordingly.
|
> a default `runparts` directory, make sure to update your setup, or the
|
||||||
|
> finit configuration, accordingly.
|
||||||
|
|
||||||
|
|
||||||
Watchdog
|
Watchdog
|
||||||
|
|||||||
+3
-2
@@ -34,8 +34,9 @@ build time:
|
|||||||
./configure --with-rcsd=/etc/init.d --with-config=/etc/init.d/init.conf
|
./configure --with-rcsd=/etc/init.d --with-config=/etc/init.d/init.conf
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Note:** remember `--prefix` et al as well, the default is likely
|
> [!IMPORTANT]
|
||||||
> *not* what you want. See the [build docs][1] for details.
|
> Remember `--prefix` et al as well, the default is likely *not* what
|
||||||
|
> you want. See the [build docs][1] for details.
|
||||||
|
|
||||||
The resulting directory structure is depicted below. Please notice how
|
The resulting directory structure is depicted below. Please notice how
|
||||||
`/etc/finit.conf` now resides in the same sub-directory as a non-symlink
|
`/etc/finit.conf` now resides in the same sub-directory as a non-symlink
|
||||||
|
|||||||
+21
-16
@@ -35,9 +35,10 @@ For your convenience a set of *optional* plugins are available:
|
|||||||
files distributed with Finit. It is read first but can be overridden
|
files distributed with Finit. It is read first but can be overridden
|
||||||
by any of the standard tmpfiles.d directories, e.g. `/etc/tmpfiles.d`.
|
by any of the standard tmpfiles.d directories, e.g. `/etc/tmpfiles.d`.
|
||||||
|
|
||||||
> **Note:** On an embedded system both `/var` and `/run` can be `tmpfs`
|
> [!NOTE]
|
||||||
> RAM disks and `/dev` is usually a `devtmpfs`. This must be defined
|
> On an embedded system both `/var` and `/run` can be `tmpfs` RAM
|
||||||
> in the `/etc/fstab` file and in the Linux kernel config.
|
> disks and `/dev` is usually a `devtmpfs`. This must be defined in
|
||||||
|
> the `/etc/fstab` file and in the Linux kernel config.
|
||||||
|
|
||||||
* *dbus.so*: Setup and start system message bus, D-Bus, at boot.
|
* *dbus.so*: Setup and start system message bus, D-Bus, at boot.
|
||||||
_Optional plugin._
|
_Optional plugin._
|
||||||
@@ -63,8 +64,9 @@ For your convenience a set of *optional* plugins are available:
|
|||||||
|
|
||||||
Enabled by default.
|
Enabled by default.
|
||||||
|
|
||||||
> See the [Services](config.md#services) section in the configuration
|
> [!TIP]
|
||||||
> guide for an example how to run `mdevd`, alternative to plain mdev.
|
> See the [Services](config.md#services) section in the configuration
|
||||||
|
> guide for an example how to run `mdevd`, alternative to plain mdev.
|
||||||
|
|
||||||
* *rtc.so*: Restore and save system clock from/to RTC on boot/halt.
|
* *rtc.so*: Restore and save system clock from/to RTC on boot/halt.
|
||||||
Enabled by default.
|
Enabled by default.
|
||||||
@@ -89,16 +91,17 @@ For your convenience a set of *optional* plugins are available:
|
|||||||
|
|
||||||
set index 1234
|
set index 1234
|
||||||
|
|
||||||
**Note:** unlike the traditional .conf `module` directive, which load
|
Since these tasks run in the background, they return `[ OK ]` at boot,
|
||||||
any listed module immediately, this plugin creates a background `task`
|
unless the modprobe tool does not exist. Check syslog for warnings
|
||||||
which load the module(s) in the background. The program is modprobe,
|
and the actual status of the operation using `initctl`.
|
||||||
`/sbin/modprobe`, which you can override per .conf file:
|
|
||||||
|
|
||||||
set modprobe /path/to/maybe-a-modprobe-wrapper
|
> [!IMPORTANT]
|
||||||
|
> Unlike the traditional .conf `module` directive, which load any listed
|
||||||
Since these tasks run in the background, they usually return `[ OK ]`
|
> module immediately, this plugin creates a background `task` which load
|
||||||
at boot, unless the modprobe tool does not exist. Check syslog for
|
> the module(s) in the background. The program is modprobe,
|
||||||
warnings and the actual status of the operation using `initctl`.
|
> `/sbin/modprobe`, which you can override per .conf file:
|
||||||
|
>
|
||||||
|
> set modprobe /path/to/maybe-a-modprobe-wrapper
|
||||||
|
|
||||||
* *netlink.so*: Listens to Linux kernel Netlink events for gateway and
|
* *netlink.so*: Listens to Linux kernel Netlink events for gateway and
|
||||||
interfaces. These events are then sent to the Finit service monitor
|
interfaces. These events are then sent to the Finit service monitor
|
||||||
@@ -158,8 +161,10 @@ hook points:
|
|||||||
EOF
|
EOF
|
||||||
$ chmod +x /libexec/finit/hook/sys/down/foo.sh
|
$ chmod +x /libexec/finit/hook/sys/down/foo.sh
|
||||||
|
|
||||||
> **Note:** to use hook scripts, even for pre-bootstrap and pre-shutdown
|
> [!IMPORTANT]
|
||||||
> tasks, you must build with `configure --enable-hook-scripts-plugin`.
|
> To use hook scripts, even for pre-bootstrap and pre-shutdown tasks,
|
||||||
|
> you must build with `configure --enable-hook-scripts-plugin`.
|
||||||
|
|
||||||
|
|
||||||
### Bootstrap Hooks
|
### Bootstrap Hooks
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -22,8 +22,9 @@ Finit can *not* start and monitor a daemon that:
|
|||||||
| ✔ | No | No | Yes, optionally |
|
| ✔ | No | No | Yes, optionally |
|
||||||
| ✘ | Yes | No | No |
|
| ✘ | Yes | No | No |
|
||||||
|
|
||||||
> **Note:** PID files is one mechanism used to assert conditions to
|
> [!NOTE]
|
||||||
> synchronize the start and stop of other, dependent, services.
|
> PID files is one mechanism used to assert conditions to synchronize
|
||||||
|
> the start and stop of other, dependent, services.
|
||||||
|
|
||||||
### Forks to Background w/ PID File
|
### Forks to Background w/ PID File
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 230 KiB After Width: | Height: | Size: 320 KiB |
+2
-2
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 164 KiB After Width: | Height: | Size: 814 KiB |
@@ -0,0 +1,7 @@
|
|||||||
|
.deps/*
|
||||||
|
.libs/*
|
||||||
|
.dirstamp
|
||||||
|
*.lo
|
||||||
|
libsystemd.*
|
||||||
|
Makefile
|
||||||
|
Makefile.in
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# libsystemd replacement library
|
||||||
|
lib_LTLIBRARIES = libsystemd.la
|
||||||
|
libsystemd_la_SOURCES = sd-daemon.c sd-daemon.h
|
||||||
|
libsystemd_la_LDFLAGS = -version-info 0:0:0
|
||||||
|
|
||||||
|
# pkg-config support
|
||||||
|
pkgconfigdir = $(libdir)/pkgconfig
|
||||||
|
pkgconfig_DATA = libsystemd.pc
|
||||||
|
|
||||||
|
# Install header to systemd/ subdirectory
|
||||||
|
systemddir = $(includedir)/systemd
|
||||||
|
systemd_HEADERS = sd-daemon.h
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
prefix=@prefix@
|
||||||
|
exec_prefix=@exec_prefix@
|
||||||
|
libdir=@libdir@
|
||||||
|
includedir=@includedir@
|
||||||
|
|
||||||
|
Name: libsystemd
|
||||||
|
Description: Finit replacement for systemd notification library
|
||||||
|
Version: @PACKAGE_VERSION@
|
||||||
|
Libs: -L${libdir} -lsystemd
|
||||||
|
Cflags: -I${includedir}
|
||||||
@@ -0,0 +1,217 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT-0 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* systemd notify protocol, supporting readiness notification on startup
|
||||||
|
* and reloading, according to the protocol defined at:
|
||||||
|
* https://www.freedesktop.org/software/systemd/man/latest/sd_notify.html
|
||||||
|
*
|
||||||
|
* This protocol is guaranteed to be stable as per:
|
||||||
|
* https://systemd.io/PORTABILITY_AND_STABILITY/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE 1
|
||||||
|
#include <errno.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "sd-daemon.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTE: As per spec., this function does not return POSIX OK(0) but
|
||||||
|
* rather "a positive value", i.e., 1.
|
||||||
|
*/
|
||||||
|
int sd_notify(int unset_environment, const char *state)
|
||||||
|
{
|
||||||
|
struct sockaddr_un sun = {
|
||||||
|
.sun_family = AF_UNIX,
|
||||||
|
};
|
||||||
|
size_t len, sun_len;
|
||||||
|
const char *path;
|
||||||
|
ssize_t written;
|
||||||
|
int sd;
|
||||||
|
|
||||||
|
if (!state)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
len = strlen(state);
|
||||||
|
if (len == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* If the variable is not set, the protocol is a noop */
|
||||||
|
path = getenv("NOTIFY_SOCKET");
|
||||||
|
if (!path)
|
||||||
|
return 0; /* Not set? Nothing to do */
|
||||||
|
|
||||||
|
/* Only AF_UNIX is supported, with path or abstract sockets */
|
||||||
|
if (path[0] != '/' && path[0] != '@')
|
||||||
|
return -EAFNOSUPPORT;
|
||||||
|
|
||||||
|
/* Ensure there is room for NUL byte */
|
||||||
|
sun_len = strlen(path);
|
||||||
|
if (sun_len >= sizeof(sun.sun_path))
|
||||||
|
return -E2BIG;
|
||||||
|
|
||||||
|
strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
|
||||||
|
if (sun.sun_path[0] == '@')
|
||||||
|
sun.sun_path[0] = 0;
|
||||||
|
|
||||||
|
sd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
|
||||||
|
if (sd == -1)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
if (connect(sd, (struct sockaddr *)&sun, offsetof(struct sockaddr_un, sun_path) + sun_len) == -1) {
|
||||||
|
close(sd);
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unset_environment)
|
||||||
|
unsetenv("NOTIFY_SOCKET");
|
||||||
|
|
||||||
|
written = write(sd, state, len);
|
||||||
|
if (written != (ssize_t) len) {
|
||||||
|
close(sd);
|
||||||
|
return written < 0 ? -errno : -EPROTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Printf-style notification function
|
||||||
|
*/
|
||||||
|
int sd_notifyf(int unset_environment, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
char *state;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!format)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
ret = vasprintf(&state, format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ret = sd_notify(unset_environment, state);
|
||||||
|
free(state);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PID-specific notification function
|
||||||
|
*/
|
||||||
|
int sd_pid_notify(pid_t pid, int unset_environment, const char *state)
|
||||||
|
{
|
||||||
|
char path[256], *env;
|
||||||
|
size_t len;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!state)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
len = strlen(state);
|
||||||
|
if (len == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (pid == 0)
|
||||||
|
pid = getpid();
|
||||||
|
|
||||||
|
env = getenv("NOTIFY_SOCKET");
|
||||||
|
if (env) {
|
||||||
|
env = strdup(env);
|
||||||
|
if (!env)
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "@run/finit/notify/%d", pid);
|
||||||
|
setenv("NOTIFY_SOCKET", path, 1);
|
||||||
|
|
||||||
|
ret = sd_notify(unset_environment, state);
|
||||||
|
|
||||||
|
if (env) {
|
||||||
|
setenv("NOTIFY_SOCKET", env, 1);
|
||||||
|
free(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PID-specific printf-style notification function
|
||||||
|
*/
|
||||||
|
int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
char *state;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!format)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
ret = vasprintf(&state, format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ret = sd_pid_notify(pid, unset_environment, state);
|
||||||
|
free(state);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Socket activation stub - Finit doesn't support socket activation yet
|
||||||
|
* Returns 0 (no file descriptors passed)
|
||||||
|
*/
|
||||||
|
int sd_listen_fds(int unset_environment)
|
||||||
|
{
|
||||||
|
if (unset_environment) {
|
||||||
|
unsetenv("LISTEN_PID");
|
||||||
|
unsetenv("LISTEN_FDS");
|
||||||
|
unsetenv("LISTEN_FDNAMES");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Watchdog stub - Finit doesn't support watchdog yet
|
||||||
|
* Returns 0 (no watchdog enabled)
|
||||||
|
*/
|
||||||
|
int sd_watchdog_enabled(int unset_environment, uint64_t *usec)
|
||||||
|
{
|
||||||
|
if (unset_environment) {
|
||||||
|
unsetenv("WATCHDOG_PID");
|
||||||
|
unsetenv("WATCHDOG_USEC");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (usec)
|
||||||
|
*usec = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* System detection function
|
||||||
|
* Returns 1 to indicate systemd compatibility (trick applications)
|
||||||
|
*/
|
||||||
|
int sd_booted(void)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
#ifndef SD_DAEMON_H_
|
||||||
|
#define SD_DAEMON_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#define SD_LISTEN_FDS_START 3
|
||||||
|
|
||||||
|
/* systemd logging defines for stderr parsing by Finit */
|
||||||
|
#define SD_EMERG "<0>" /* system is unusable */
|
||||||
|
#define SD_ALERT "<1>" /* action must be taken immediately */
|
||||||
|
#define SD_CRIT "<2>" /* critical conditions */
|
||||||
|
#define SD_ERR "<3>" /* error conditions */
|
||||||
|
#define SD_WARNING "<4>" /* warning conditions */
|
||||||
|
#define SD_NOTICE "<5>" /* normal but significant condition */
|
||||||
|
#define SD_INFO "<6>" /* informational */
|
||||||
|
#define SD_DEBUG "<7>" /* debug-level messages */
|
||||||
|
|
||||||
|
/* Basic notification function */
|
||||||
|
int sd_notify(int unset_environment, const char *state);
|
||||||
|
|
||||||
|
/* Printf-style notification functions */
|
||||||
|
int sd_notifyf(int unset_environment, const char *format, ...);
|
||||||
|
|
||||||
|
/* PID-specific notification functions */
|
||||||
|
int sd_pid_notify(pid_t pid, int unset_environment, const char *state);
|
||||||
|
int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...);
|
||||||
|
|
||||||
|
/* Socket activation stubs */
|
||||||
|
int sd_listen_fds(int unset_environment);
|
||||||
|
|
||||||
|
/* Watchdog stub */
|
||||||
|
int sd_watchdog_enabled(int unset_environment, uint64_t *usec);
|
||||||
|
|
||||||
|
/* System detection */
|
||||||
|
int sd_booted(void);
|
||||||
|
|
||||||
|
#endif /* SD_DAEMON_H_ */
|
||||||
+39
-25
@@ -175,13 +175,13 @@ task [s] echo "foo" | cat >/tmp/bar
|
|||||||
.Ed
|
.Ed
|
||||||
.It Cm sysv Oo LVLS Oc Ao COND Ac Ar /path/to/script ARGS Op -- Optional description
|
.It Cm sysv Oo LVLS Oc Ao COND Ac Ar /path/to/script ARGS Op -- Optional description
|
||||||
Similar to
|
Similar to
|
||||||
.Cm task
|
.Cm service
|
||||||
is the
|
is the
|
||||||
.Cm sysv
|
.Cm sysv
|
||||||
stanza, which can be used to call SysV style start/stop scripts. The
|
stanza, which can be used to call SysV style start/stop scripts. The
|
||||||
primary intention for this command is to be able to re-use much of
|
primary intention for this command is to be able to re-use traditional
|
||||||
existing setup and init scripts in Linux distributions.
|
SysV init scripts in Linux distributions.
|
||||||
.Pp
|
.Pp
|
||||||
When entering an allowed runlevel, Finit calls
|
When entering an allowed runlevel, Finit calls
|
||||||
.Cm init-script start ,
|
.Cm init-script start ,
|
||||||
when entering a disallowed runlevel, Finit calls
|
when entering a disallowed runlevel, Finit calls
|
||||||
@@ -434,30 +434,42 @@ e.g.,
|
|||||||
.Cm kill:10
|
.Cm kill:10
|
||||||
to wait 10 seconds before sending SIGKILL.
|
to wait 10 seconds before sending SIGKILL.
|
||||||
.Pp
|
.Pp
|
||||||
Services support the
|
Services, including the
|
||||||
.Cm pre:script
|
.Cm sysv
|
||||||
and
|
variant, support pre/post/ready and cleanup scripts:
|
||||||
.Cm post:script
|
.Bl -tag -width 1n
|
||||||
command actions as well. These run as the same
|
.It Cm pre:[0-3600,]script
|
||||||
|
called before the sysv/service is stated
|
||||||
|
.It Cm post:[0-3600,]script
|
||||||
|
called after the sysv/service has stopped
|
||||||
|
.It Cm ready:[0-3600,]script
|
||||||
|
called when the sysv/service is ready
|
||||||
|
.It Cm cleanup:[0-3600,]script
|
||||||
|
called when run/task/sysv/service is removed
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
The optional number (0-3600) is the timeout before Finit kills the
|
||||||
|
script, it defaults to the kill delay value and can be disabled by
|
||||||
|
setting it to zero. These scripts run as the same
|
||||||
.Cm @USER:GROUP
|
.Cm @USER:GROUP
|
||||||
as the service itself, with any
|
as the service itself, with any
|
||||||
.Cm env:file
|
.Cm env:file
|
||||||
sourced. The scripts must use an absolute path, but are executed from
|
sourced. The scripts must use an absolute path, but are executed from
|
||||||
the
|
the
|
||||||
.Cm $HOME
|
.Cm $HOME
|
||||||
of the given user. The scripts are not called with any argument
|
of the given user. The scripts are not called with any argument, but
|
||||||
(currently), but both get the
|
both get a set of environment variables:
|
||||||
.Cm SERVICE_IDENT=foo
|
.Pp
|
||||||
environment variable set. Here
|
.Bl -tag -width 1n -compact
|
||||||
.Cm foo
|
.It Cm SERVICE_IDENT=foo:1
|
||||||
denotes the identity of the service, which if there are multiple
|
.It Cm SERVICE_NAME=foo
|
||||||
services named
|
.It Cm SERVICE_ID=1
|
||||||
.Cm foo ,
|
.El
|
||||||
may be
|
.Pp
|
||||||
.Cm foo:1 ,
|
The
|
||||||
or any unique identifier specified in the .conf file. The
|
|
||||||
.Cm post:script
|
.Cm post:script
|
||||||
is called with an additional set of environment variables:
|
is called with an additional set of environment variables, and yes the
|
||||||
|
naming looks like it should be swapped:
|
||||||
.Bl -tag -offset indent -width 1n
|
.Bl -tag -offset indent -width 1n
|
||||||
.It Cm EXIT_CODE=[exited,signal,crashed]
|
.It Cm EXIT_CODE=[exited,signal,crashed]
|
||||||
set to one of
|
set to one of
|
||||||
@@ -471,10 +483,12 @@ set to one of exit status code from the program, if it exited normally,
|
|||||||
or the signal name (HUP, TERM, etc.) if it exited due to signal
|
or the signal name (HUP, TERM, etc.) if it exited due to signal
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
The scripts have a default execution time of 3 seconds before they are
|
When a run/task/sys/service is removed (disable + reload) it is first
|
||||||
SIGKILLed, this can be adjusted using the
|
stopped and then removed from the runlevel. The
|
||||||
.Cm kill:SEC
|
.Cm post:script
|
||||||
modifier syntax.
|
always runs when the process has stopped, and the
|
||||||
|
.Cm cleanup:script
|
||||||
|
runs when the the stanza has been removed from the runlevel.
|
||||||
.It Cm runparts Aq DIR
|
.It Cm runparts Aq DIR
|
||||||
Call
|
Call
|
||||||
.Xr run-parts 8
|
.Xr run-parts 8
|
||||||
|
|||||||
@@ -65,12 +65,12 @@ static plugin_t plugin = {
|
|||||||
.hook[HOOK_SHUTDOWN] = { .cb = save }
|
.hook[HOOK_SHUTDOWN] = { .cb = save }
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(__init)
|
||||||
{
|
{
|
||||||
plugin_register(&plugin);
|
plugin_register(&plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(__exit)
|
||||||
{
|
{
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-4
@@ -38,7 +38,6 @@
|
|||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
#include "tmpfiles.h"
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "utmp-api.h"
|
#include "utmp-api.h"
|
||||||
|
|
||||||
@@ -163,7 +162,7 @@ static void setup(void *arg)
|
|||||||
kernel_links();
|
kernel_links();
|
||||||
|
|
||||||
/* Create all system tmpfiles.d(5) */
|
/* Create all system tmpfiles.d(5) */
|
||||||
tmpfilesd();
|
run_interactive(_PATH_TMPFILES " --create", "Creating required directories and files");
|
||||||
|
|
||||||
/* Set BOOT_TIME UTMP entry */
|
/* Set BOOT_TIME UTMP entry */
|
||||||
utmp_set_boot();
|
utmp_set_boot();
|
||||||
@@ -178,12 +177,12 @@ static plugin_t plugin = {
|
|||||||
.depends = { "pidfile" },
|
.depends = { "pidfile" },
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(__init)
|
||||||
{
|
{
|
||||||
plugin_register(&plugin);
|
plugin_register(&plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(__exit)
|
||||||
{
|
{
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -166,12 +166,12 @@ static plugin_t plugin = {
|
|||||||
.hook[HOOK_SVC_PLUGIN] = { .cb = setup },
|
.hook[HOOK_SVC_PLUGIN] = { .cb = setup },
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(__init)
|
||||||
{
|
{
|
||||||
plugin_register(&plugin);
|
plugin_register(&plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(__exit)
|
||||||
{
|
{
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,12 +99,12 @@ static plugin_t plugin = {
|
|||||||
*/
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(__init)
|
||||||
{
|
{
|
||||||
plugin_register(&plugin);
|
plugin_register(&plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(__exit)
|
||||||
{
|
{
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -232,12 +232,12 @@ static plugin_t plugin = {
|
|||||||
.depends = { "bootmisc", }
|
.depends = { "bootmisc", }
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(__init)
|
||||||
{
|
{
|
||||||
plugin_register(&plugin);
|
plugin_register(&plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(__exit)
|
||||||
{
|
{
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
*
|
*
|
||||||
* Please note, the :ID is there for your benefit, it ensures that tasks
|
* Please note, the :ID is there for your benefit, it ensures that tasks
|
||||||
* in Finit are unique. If you have two tasks with the same name and ID
|
* in Finit are unique. If you have two tasks with the same name and ID
|
||||||
* (or no ID), the last one read replaces any preceeding one!
|
* (or no ID), the last one read replaces any preceding one!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -216,12 +216,12 @@ static plugin_t plugin = {
|
|||||||
.hook[HOOK_SVC_PLUGIN] = { .cb = load },
|
.hook[HOOK_SVC_PLUGIN] = { .cb = load },
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(__init)
|
||||||
{
|
{
|
||||||
plugin_register(&plugin);
|
plugin_register(&plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(__exit)
|
||||||
{
|
{
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
|
#include "log.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
@@ -414,7 +415,7 @@ static plugin_t plugin = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(__init)
|
||||||
{
|
{
|
||||||
struct sockaddr_nl sa;
|
struct sockaddr_nl sa;
|
||||||
int sd;
|
int sd;
|
||||||
@@ -447,7 +448,7 @@ PLUGIN_INIT(plugin_init)
|
|||||||
plugin_register(&plugin);
|
plugin_register(&plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(__exit)
|
||||||
{
|
{
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
close(plugin.io.fd);
|
close(plugin.io.fd);
|
||||||
|
|||||||
+19
-2
@@ -80,6 +80,23 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (svc->state) {
|
||||||
|
case SVC_TEARDOWN_STATE:
|
||||||
|
case SVC_CLEANUP_STATE:
|
||||||
|
case SVC_SETUP_STATE:
|
||||||
|
/*
|
||||||
|
* E.g., a setup script for a container may run in lieu
|
||||||
|
* of crun, trying to fetch a container image from the
|
||||||
|
* network. This script may want to advertise its PID
|
||||||
|
* to the system for clean and swift reboots.
|
||||||
|
*/
|
||||||
|
dbg("%s[%d]: ignoring any PID file changes in CLEANUP/TEARDOWN/SETUP",
|
||||||
|
svc_ident(svc, NULL, 0), svc->pid);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Service condistion to set/clear */
|
/* Service condistion to set/clear */
|
||||||
mkcond(svc, cond, sizeof(cond));
|
mkcond(svc, cond, sizeof(cond));
|
||||||
|
|
||||||
@@ -321,7 +338,7 @@ static plugin_t plugin = {
|
|||||||
.depends = { "netlink" }, /* bootmisc depends on us */
|
.depends = { "netlink" }, /* bootmisc depends on us */
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(__init)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
@@ -336,7 +353,7 @@ PLUGIN_INIT(plugin_init)
|
|||||||
plugin_register(&plugin);
|
plugin_register(&plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(__exit)
|
||||||
{
|
{
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
iwatch_exit(&iw_pidfile);
|
iwatch_exit(&iw_pidfile);
|
||||||
|
|||||||
+9
-3
@@ -31,6 +31,12 @@
|
|||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
#include "conf.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#ifndef SYSCTL_PATH
|
||||||
|
#define SYSCTL_PATH "/sbin/sysctl"
|
||||||
|
#endif
|
||||||
|
|
||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
{
|
{
|
||||||
@@ -54,7 +60,7 @@ static void setup(void *arg)
|
|||||||
for (i = 0; i < gl.gl_pathc; i++) {
|
for (i = 0; i < gl.gl_pathc; i++) {
|
||||||
char cmd[160];
|
char cmd[160];
|
||||||
|
|
||||||
snprintf(cmd, sizeof(cmd), "/sbin/sysctl -e -p %s >/dev/null", gl.gl_pathv[i]);
|
snprintf(cmd, sizeof(cmd), "%s -e -p %s >/dev/null", SYSCTL_PATH, gl.gl_pathv[i]);
|
||||||
run(cmd, "sysctl");
|
run(cmd, "sysctl");
|
||||||
}
|
}
|
||||||
globfree(&gl);
|
globfree(&gl);
|
||||||
@@ -70,12 +76,12 @@ static plugin_t plugin = {
|
|||||||
.depends = { "bootmisc", },
|
.depends = { "bootmisc", },
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(__init)
|
||||||
{
|
{
|
||||||
plugin_register(&plugin);
|
plugin_register(&plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(__exit)
|
||||||
{
|
{
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,12 +57,12 @@ static plugin_t plugin = {
|
|||||||
.depends = { "bootmisc", },
|
.depends = { "bootmisc", },
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(__init)
|
||||||
{
|
{
|
||||||
plugin_register(&plugin);
|
plugin_register(&plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(__exit)
|
||||||
{
|
{
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-2
@@ -35,6 +35,9 @@
|
|||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
#include "private.h"
|
||||||
|
#include "conf.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Kernel RTC driver validates against this date for sanity check. The
|
* Kernel RTC driver validates against this date for sanity check. The
|
||||||
@@ -320,7 +323,7 @@ static plugin_t plugin = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(__init)
|
||||||
{
|
{
|
||||||
struct tm tm = { 0 };
|
struct tm tm = { 0 };
|
||||||
|
|
||||||
@@ -336,8 +339,9 @@ PLUGIN_INIT(plugin_init)
|
|||||||
plugin_register(&plugin);
|
plugin_register(&plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(__exit)
|
||||||
{
|
{
|
||||||
|
uev_timer_stop(&rtc_timer);
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -184,7 +184,7 @@ static plugin_t plugin = {
|
|||||||
.depends = { "bootmisc", },
|
.depends = { "bootmisc", },
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(__init)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
@@ -199,7 +199,7 @@ PLUGIN_INIT(plugin_init)
|
|||||||
plugin_register(&plugin);
|
plugin_register(&plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(__exit)
|
||||||
{
|
{
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
iwatch_exit(&iw_sys);
|
iwatch_exit(&iw_sys);
|
||||||
|
|||||||
+3
-2
@@ -38,6 +38,7 @@
|
|||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
static void tty_watcher(void *arg, int fd, int events);
|
static void tty_watcher(void *arg, int fd, int events);
|
||||||
|
|
||||||
@@ -108,13 +109,13 @@ static void tty_watcher(void *arg, int fd, int events)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(__init)
|
||||||
{
|
{
|
||||||
setup();
|
setup();
|
||||||
plugin_register(&plugin);
|
plugin_register(&plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(__exit)
|
||||||
{
|
{
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
if (plugin.io.fd)
|
if (plugin.io.fd)
|
||||||
|
|||||||
+28
-8
@@ -26,6 +26,7 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/time.h> /* gettimeofday() */
|
#include <sys/time.h> /* gettimeofday() */
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/resource.h> /* getrusage() */
|
||||||
#ifdef _LIBITE_LITE
|
#ifdef _LIBITE_LITE
|
||||||
# include <libite/lite.h>
|
# include <libite/lite.h>
|
||||||
#else
|
#else
|
||||||
@@ -37,19 +38,35 @@
|
|||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
#include "conf.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
#ifndef RANDOM_BYTES
|
#ifndef RANDOM_BYTES
|
||||||
#define RANDOM_BYTES (32*1024)
|
#define RANDOM_BYTES (32*1024)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef RANDOMSEED
|
#ifdef RANDOMSEED
|
||||||
|
/*
|
||||||
|
* This is the fallback seed function, please make sure you have drivers
|
||||||
|
* enabling /dev/hwrng instead.
|
||||||
|
*/
|
||||||
static void fallback(FILE *fp)
|
static void fallback(FILE *fp)
|
||||||
{
|
{
|
||||||
|
unsigned long seed;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
struct rusage ru;
|
||||||
int iter = 128;
|
int iter = 128;
|
||||||
|
|
||||||
gettimeofday(&tv, NULL);
|
gettimeofday(&tv, NULL);
|
||||||
srandom(tv.tv_sec % 3600);
|
getrusage(RUSAGE_SELF, &ru);
|
||||||
|
|
||||||
|
/* Mix multiple sources of "randomness" */
|
||||||
|
seed = tv.tv_sec ^ (tv.tv_usec << 16);
|
||||||
|
seed ^= ru.ru_utime.tv_sec ^ (ru.ru_utime.tv_usec << 16);
|
||||||
|
seed ^= ru.ru_stime.tv_sec ^ (ru.ru_stime.tv_usec << 16);
|
||||||
|
seed ^= getpid() << 8;
|
||||||
|
|
||||||
|
srandom(seed);
|
||||||
while (iter--) {
|
while (iter--) {
|
||||||
uint32_t i, prng = random();
|
uint32_t i, prng = random();
|
||||||
|
|
||||||
@@ -63,6 +80,7 @@ static void setup(void *arg)
|
|||||||
{
|
{
|
||||||
#ifdef RANDOMSEED
|
#ifdef RANDOMSEED
|
||||||
struct rand_pool_info *rpi;
|
struct rand_pool_info *rpi;
|
||||||
|
unsigned char *rpi_buf;
|
||||||
ssize_t len = 0;
|
ssize_t len = 0;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int rc = -1;
|
int rc = -1;
|
||||||
@@ -88,13 +106,14 @@ static void setup(void *arg)
|
|||||||
hw = fopen(hwrng, "r");
|
hw = fopen(hwrng, "r");
|
||||||
if (hw) {
|
if (hw) {
|
||||||
char buf[512];
|
char buf[512];
|
||||||
size_t len;
|
size_t num;
|
||||||
|
|
||||||
len = fread(buf, sizeof(buf[0]), sizeof(buf), hw);
|
num = fread(buf, sizeof(buf[0]), sizeof(buf), hw);
|
||||||
if (len == 0)
|
if (num == 0)
|
||||||
fallback(fp);
|
fallback(fp);
|
||||||
else
|
else
|
||||||
len = fwrite(buf, sizeof(buf[0]), len, fp);
|
fwrite(buf, sizeof(buf[0]), num, fp);
|
||||||
|
|
||||||
fclose(hw);
|
fclose(hw);
|
||||||
} else {
|
} else {
|
||||||
fallback(fp);
|
fallback(fp);
|
||||||
@@ -122,10 +141,11 @@ static void setup(void *arg)
|
|||||||
goto fallback;
|
goto fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpi_buf = (unsigned char *)rpi->buf;
|
||||||
do {
|
do {
|
||||||
ssize_t num;
|
ssize_t num;
|
||||||
|
|
||||||
num = read(fd, &rpi->buf[len], RANDOM_BYTES - len);
|
num = read(fd, &rpi_buf[len], RANDOM_BYTES - len);
|
||||||
if (num <= 0) {
|
if (num <= 0) {
|
||||||
if (num == -1 && errno == EINTR)
|
if (num == -1 && errno == EINTR)
|
||||||
continue;
|
continue;
|
||||||
@@ -188,12 +208,12 @@ static plugin_t plugin = {
|
|||||||
.depends = { "bootmisc", }
|
.depends = { "bootmisc", }
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(__init)
|
||||||
{
|
{
|
||||||
plugin_register(&plugin);
|
plugin_register(&plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(__exit)
|
||||||
{
|
{
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -108,7 +108,7 @@ static plugin_t plugin = {
|
|||||||
.depends = { "bootmisc", },
|
.depends = { "bootmisc", },
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(__init)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ PLUGIN_INIT(plugin_init)
|
|||||||
plugin_register(&plugin);
|
plugin_register(&plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(__exit)
|
||||||
{
|
{
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
iwatch_exit(&iw_usr);
|
iwatch_exit(&iw_usr);
|
||||||
|
|||||||
@@ -33,6 +33,8 @@
|
|||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
#include "conf.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
{
|
{
|
||||||
@@ -50,12 +52,12 @@ static plugin_t plugin = {
|
|||||||
.hook[HOOK_SVC_PLUGIN] = { .cb = setup },
|
.hook[HOOK_SVC_PLUGIN] = { .cb = setup },
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(__init)
|
||||||
{
|
{
|
||||||
plugin_register(&plugin);
|
plugin_register(&plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(__exit)
|
||||||
{
|
{
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ logit
|
|||||||
reboot
|
reboot
|
||||||
runparts
|
runparts
|
||||||
sulogin
|
sulogin
|
||||||
|
tmpfiles
|
||||||
watchdogd
|
watchdogd
|
||||||
Makefile
|
Makefile
|
||||||
Makefile.in
|
Makefile.in
|
||||||
|
|||||||
+7
-2
@@ -8,7 +8,8 @@ AM_LDFLAGS = -export-dynamic
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
sbin_PROGRAMS = finit initctl
|
sbin_PROGRAMS = finit initctl
|
||||||
pkglibexec_PROGRAMS = getty logit runparts
|
pkglibexec_PROGRAMS = getty logit runparts tmpfiles
|
||||||
|
|
||||||
if SULOGIN
|
if SULOGIN
|
||||||
pkglibexec_PROGRAMS += sulogin
|
pkglibexec_PROGRAMS += sulogin
|
||||||
endif
|
endif
|
||||||
@@ -43,6 +44,11 @@ sulogin_SOURCES = sulogin.c
|
|||||||
sulogin_CFLAGS = -W -Wall -Wextra -std=gnu99
|
sulogin_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||||
sulogin_LDADD = -lcrypt
|
sulogin_LDADD = -lcrypt
|
||||||
|
|
||||||
|
tmpfiles_SOURCES = tmpfiles.c util.c util.h log.h
|
||||||
|
tmpfiles_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||||
|
tmpfiles_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
|
||||||
|
tmpfiles_LDADD = $(lite_LIBS) $(uev_LIBS)
|
||||||
|
|
||||||
logit_SOURCES = logit.c logrotate.c
|
logit_SOURCES = logit.c logrotate.c
|
||||||
logit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
logit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||||
logit_CFLAGS += $(lite_CFLAGS)
|
logit_CFLAGS += $(lite_CFLAGS)
|
||||||
@@ -66,7 +72,6 @@ finit_SOURCES = api.c cgroup.c cgroup.h \
|
|||||||
sig.c sig.h \
|
sig.c sig.h \
|
||||||
sm.c sm.h \
|
sm.c sm.h \
|
||||||
svc.c svc.h \
|
svc.c svc.h \
|
||||||
tmpfiles.c tmpfiles.h \
|
|
||||||
tty.c tty.h \
|
tty.c tty.h \
|
||||||
util.c util.h \
|
util.c util.h \
|
||||||
utmp-api.c utmp-api.h
|
utmp-api.c utmp-api.h
|
||||||
|
|||||||
@@ -47,6 +47,7 @@
|
|||||||
#include "private.h"
|
#include "private.h"
|
||||||
#include "schedule.h"
|
#include "schedule.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
|
#include "sm.h"
|
||||||
#include "sig.h"
|
#include "sig.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
@@ -59,6 +60,8 @@ static int call(int (*action)(svc_t *, void *), char *buf, size_t len)
|
|||||||
|
|
||||||
static int stop(svc_t *svc, void *user_data)
|
static int stop(svc_t *svc, void *user_data)
|
||||||
{
|
{
|
||||||
|
(void)user_data;
|
||||||
|
|
||||||
if (!svc)
|
if (!svc)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@@ -72,6 +75,8 @@ static int stop(svc_t *svc, void *user_data)
|
|||||||
|
|
||||||
static int start(svc_t *svc, void *user_data)
|
static int start(svc_t *svc, void *user_data)
|
||||||
{
|
{
|
||||||
|
(void)user_data;
|
||||||
|
|
||||||
if (!svc)
|
if (!svc)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@@ -105,6 +110,8 @@ static int restart(svc_t *svc, void *user_data)
|
|||||||
|
|
||||||
static int reload(svc_t *svc, void *user_data)
|
static int reload(svc_t *svc, void *user_data)
|
||||||
{
|
{
|
||||||
|
(void)user_data;
|
||||||
|
|
||||||
if (!svc)
|
if (!svc)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@@ -149,6 +156,8 @@ static int missing(char *job, char *id, void *user_data)
|
|||||||
{
|
{
|
||||||
char buf[20];
|
char buf[20];
|
||||||
|
|
||||||
|
(void)user_data;
|
||||||
|
|
||||||
if (!job)
|
if (!job)
|
||||||
job = "";
|
job = "";
|
||||||
if (!id)
|
if (!id)
|
||||||
@@ -228,6 +237,8 @@ struct wq emergency = { .cb = bypass_shutdown };
|
|||||||
|
|
||||||
static void bypass_shutdown(void *unused)
|
static void bypass_shutdown(void *unused)
|
||||||
{
|
{
|
||||||
|
(void)unused;
|
||||||
|
|
||||||
cprintf("TIMEOUT TIMEOUT SHUTTING DOWN NOW!!\n");
|
cprintf("TIMEOUT TIMEOUT SHUTTING DOWN NOW!!\n");
|
||||||
do_shutdown(halt);
|
do_shutdown(halt);
|
||||||
}
|
}
|
||||||
@@ -265,19 +276,19 @@ static int do_reboot(int cmd, int timeout, char *buf, size_t len)
|
|||||||
case INIT_CMD_REBOOT:
|
case INIT_CMD_REBOOT:
|
||||||
dbg("reboot");
|
dbg("reboot");
|
||||||
halt = SHUT_REBOOT;
|
halt = SHUT_REBOOT;
|
||||||
service_runlevel(6);
|
sm_runlevel(6);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_HALT:
|
case INIT_CMD_HALT:
|
||||||
dbg("halt");
|
dbg("halt");
|
||||||
halt = SHUT_HALT;
|
halt = SHUT_HALT;
|
||||||
service_runlevel(0);
|
sm_runlevel(0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_POWEROFF:
|
case INIT_CMD_POWEROFF:
|
||||||
dbg("poweroff");
|
dbg("poweroff");
|
||||||
halt = SHUT_OFF;
|
halt = SHUT_OFF;
|
||||||
service_runlevel(0);
|
sm_runlevel(0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_SUSPEND:
|
case INIT_CMD_SUSPEND:
|
||||||
@@ -306,7 +317,7 @@ typedef struct {
|
|||||||
} ev_t;
|
} ev_t;
|
||||||
|
|
||||||
ev_t ev_list[] = {
|
ev_t ev_list[] = {
|
||||||
{ "RELOAD", service_reload_dynamic },
|
{ "RELOAD", sm_reload },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -332,6 +343,19 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
int sd, lvl;
|
int sd, lvl;
|
||||||
svc_t *svc;
|
svc_t *svc;
|
||||||
|
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
if (UEV_ERROR == events) {
|
||||||
|
dbg("%s(): api socket %d invalid.", __func__, w->fd);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: refactor to use accept4() and a new uev handler for the
|
||||||
|
* client socket instead of risking blocking PID 1 if the client
|
||||||
|
* is misbehaving.
|
||||||
|
*/
|
||||||
|
// sd = accept4(w->fd, NULL, NULL, SOCK_NONBLOCK);
|
||||||
sd = accept(w->fd, NULL, NULL);
|
sd = accept(w->fd, NULL, NULL);
|
||||||
if (sd < 0) {
|
if (sd < 0) {
|
||||||
err(1, "Failed serving API request");
|
err(1, "Failed serving API request");
|
||||||
@@ -414,7 +438,7 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
if (runlevel == INIT_LEVEL)
|
if (runlevel == INIT_LEVEL)
|
||||||
cfglevel = lvl;
|
cfglevel = lvl;
|
||||||
else
|
else
|
||||||
service_runlevel(lvl);
|
sm_runlevel(lvl);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -430,7 +454,7 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
|
|
||||||
case INIT_CMD_RELOAD: /* 'init q' and 'initctl reload' */
|
case INIT_CMD_RELOAD: /* 'init q' and 'initctl reload' */
|
||||||
dbg("reload");
|
dbg("reload");
|
||||||
service_reload_dynamic();
|
sm_reload();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_START_SVC:
|
case INIT_CMD_START_SVC:
|
||||||
@@ -548,20 +572,6 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
result = do_signal(rq.data, sizeof(rq.data), rq.runlevel);
|
result = do_signal(rq.data, sizeof(rq.data), rq.runlevel);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_NOTIFY_SOCKET:
|
|
||||||
svc = svc_find_by_pid(rq.runlevel);
|
|
||||||
if (!svc) {
|
|
||||||
errx(1, "Unknown PID, cannot register notify socket");
|
|
||||||
result = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uev_io_init(ctx, &svc->notify_watcher, service_notify_cb, svc, sd, UEV_READ)) {
|
|
||||||
err(1, "Falied initializing %s readiness notifier", svc_ident(svc, NULL, 0));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return; /* Don't close sd, used for notify */
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
dbg("Unsupported cmd: %d", rq.cmd);
|
dbg("Unsupported cmd: %d", rq.cmd);
|
||||||
break;
|
break;
|
||||||
@@ -578,8 +588,6 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
|
|
||||||
leave:
|
leave:
|
||||||
close(sd);
|
close(sd);
|
||||||
if (UEV_ERROR == events)
|
|
||||||
goto error;
|
|
||||||
return;
|
return;
|
||||||
error:
|
error:
|
||||||
api_exit();
|
api_exit();
|
||||||
@@ -598,7 +606,7 @@ int api_init(uev_ctx_t *ctx)
|
|||||||
int sd;
|
int sd;
|
||||||
|
|
||||||
dbg("Setting up external API socket ...");
|
dbg("Setting up external API socket ...");
|
||||||
sd = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
|
sd = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
|
||||||
if (-1 == sd) {
|
if (-1 == sd) {
|
||||||
err(1, "Failed starting external API socket");
|
err(1, "Failed starting external API socket");
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
+16
-2
@@ -37,6 +37,8 @@
|
|||||||
#include "cgroup.h"
|
#include "cgroup.h"
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "iwatch.h"
|
#include "iwatch.h"
|
||||||
|
#include "conf.h"
|
||||||
|
#include "service.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
@@ -86,6 +88,12 @@ static void cgset(const char *path, char *ctrl, char *prop)
|
|||||||
}
|
}
|
||||||
*val++ = 0;
|
*val++ = 0;
|
||||||
|
|
||||||
|
/* unquote value, if quoted */
|
||||||
|
if (unquote(&val, NULL)) {
|
||||||
|
errx(1, "Syntax error, unterminated quote in %s/%s.%s=%s", path, ctrl, prop, val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* disallow sneaky relative paths */
|
/* disallow sneaky relative paths */
|
||||||
if (strstr(ctrl, "..") || strstr(prop, "..")) {
|
if (strstr(ctrl, "..") || strstr(prop, "..")) {
|
||||||
errx(1, "Possible security violation; '..' not allowed in cgroup config!");
|
errx(1, "Possible security violation; '..' not allowed in cgroup config!");
|
||||||
@@ -259,6 +267,12 @@ static void cgroup_events_cb(uev_t *w, void *arg, int events)
|
|||||||
ssize_t sz;
|
ssize_t sz;
|
||||||
size_t off;
|
size_t off;
|
||||||
|
|
||||||
|
(void)arg;
|
||||||
|
if (UEV_ERROR == events) {
|
||||||
|
dbg("%s(): inotify socket %d invalid.", __func__, w->fd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
sz = read(w->fd, ev_buf, sizeof(ev_buf) - 1);
|
sz = read(w->fd, ev_buf, sizeof(ev_buf) - 1);
|
||||||
if (sz <= 0) {
|
if (sz <= 0) {
|
||||||
err(1, "invalid inotify event");
|
err(1, "invalid inotify event");
|
||||||
@@ -289,7 +303,7 @@ static void cgroup_events_cb(uev_t *w, void *arg, int events)
|
|||||||
|
|
||||||
#ifdef AUTO_RELOAD
|
#ifdef AUTO_RELOAD
|
||||||
if (conf_any_change())
|
if (conf_any_change())
|
||||||
service_reload_dynamic();
|
sm_reload();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -471,7 +485,7 @@ void cgroup_init(uev_ctx_t *ctx)
|
|||||||
if (mount("none", FINIT_CGPATH, "cgroup2", opts, NULL)) {
|
if (mount("none", FINIT_CGPATH, "cgroup2", opts, NULL)) {
|
||||||
if (errno == ENOENT)
|
if (errno == ENOENT)
|
||||||
logit(LOG_INFO, "Kernel does not support cgroups v2, disabling.");
|
logit(LOG_INFO, "Kernel does not support cgroups v2, disabling.");
|
||||||
else if (errno == EPERM) /* Probably inside an unpriviliged container */
|
else if (errno == EPERM) /* Probably inside an unprivileged container */
|
||||||
logit(LOG_INFO, "Not allowed to mount cgroups v2, disabling.");
|
logit(LOG_INFO, "Not allowed to mount cgroups v2, disabling.");
|
||||||
else
|
else
|
||||||
err(1, "Failed mounting cgroup v2");
|
err(1, "Failed mounting cgroup v2");
|
||||||
|
|||||||
+64
-45
@@ -58,73 +58,90 @@ int cgroup_avail(void)
|
|||||||
return fismnt(FINIT_CGPATH);
|
return fismnt(FINIT_CGPATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *pid_cmdline(int pid, char *buf, size_t len)
|
static size_t flen(FILE *fp)
|
||||||
{
|
{
|
||||||
size_t i, sz;
|
size_t total = 0, sz;
|
||||||
char *ptr;
|
char buf[512];
|
||||||
|
|
||||||
|
while ((sz = fread(buf, 1, sizeof(buf), fp)) > 0)
|
||||||
|
total += sz;
|
||||||
|
rewind(fp);
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *pid_cmdline(int pid)
|
||||||
|
{
|
||||||
|
size_t i, len;
|
||||||
|
char *buf;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
fp = fopenf("r", "/proc/%d/cmdline", pid);
|
fp = fopenf("r", "/proc/%d/cmdline", pid);
|
||||||
if (!fp) {
|
if (!fp)
|
||||||
buf[0] = 0;
|
return strdup(""); /* regular process */
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
sz = fread(buf, sizeof(buf[0]), len - 1, fp);
|
len = flen(fp);
|
||||||
fclose(fp);
|
if (len == 0) {
|
||||||
if (!sz)
|
fail:
|
||||||
|
fclose(fp);
|
||||||
return NULL; /* kernel thread */
|
return NULL; /* kernel thread */
|
||||||
|
|
||||||
buf[sz] = 0;
|
|
||||||
|
|
||||||
ptr = strchr(buf, 0);
|
|
||||||
if (ptr && ptr != buf) {
|
|
||||||
ptr++;
|
|
||||||
sz -= ptr - buf;
|
|
||||||
memmove(buf, ptr, sz + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < sz; i++) {
|
buf = calloc(len + 1, 1);
|
||||||
if (buf[i] == 0)
|
if (!buf)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (fread(buf, 1, len, fp) < len) {
|
||||||
|
free(buf);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* replace all NUL chars with space */
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
if (buf[i] == '\0')
|
||||||
buf[i] = ' ';
|
buf[i] = ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *pid_comm(int pid, char *buf, size_t len)
|
char *pid_cgroup(int pid)
|
||||||
{
|
{
|
||||||
char *ptr = NULL;
|
char *buf, *ptr = NULL;
|
||||||
FILE *fp;
|
size_t len;
|
||||||
|
|
||||||
fp = fopenf("r", "/proc/%d/comm", pid);
|
|
||||||
if (!fp)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (fgets(buf, len, fp))
|
|
||||||
ptr = chomp(buf);
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *pid_cgroup(int pid, char *buf, size_t len)
|
|
||||||
{
|
|
||||||
char *ptr = NULL;
|
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
fp = fopenf("r", "/proc/%d/cgroup", pid);
|
fp = fopenf("r", "/proc/%d/cgroup", pid);
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
len = flen(fp);
|
||||||
|
if (len == 0) {
|
||||||
|
fclose(fp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
len++;
|
||||||
|
|
||||||
|
buf = calloc(1, len);
|
||||||
|
if (!buf) {
|
||||||
|
fclose(fp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (fgets(buf, len, fp))
|
if (fgets(buf, len, fp))
|
||||||
ptr = chomp(buf);
|
ptr = chomp(buf);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
if (ptr)
|
if (ptr) {
|
||||||
ptr = strchr(buf, '/');
|
ptr = strchr(ptr, '/');
|
||||||
|
if (ptr) {
|
||||||
|
memmove(buf, ptr, strlen(ptr) + 1);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ptr;
|
free(buf);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *cgroup_val(char *path, char *file, char *buf, size_t len)
|
static char *cgroup_val(char *path, char *file, char *buf, size_t len)
|
||||||
@@ -423,7 +440,7 @@ int cgroup_tree(char *path, char *pfx, int mode, int pos)
|
|||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
while (fgets(buf, sizeof(buf), fp)) {
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
char comm[80] = { 0 };
|
char *cmdline;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
pid = atoi(chomp(buf));
|
pid = atoi(chomp(buf));
|
||||||
@@ -431,8 +448,8 @@ int cgroup_tree(char *path, char *pfx, int mode, int pos)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* skip kernel threads for now (no cmdline) */
|
/* skip kernel threads for now (no cmdline) */
|
||||||
pid_comm(pid, comm, sizeof(comm));
|
cmdline = pid_cmdline(pid);
|
||||||
if (pid_cmdline(pid, buf, sizeof(buf))) {
|
if (cmdline) {
|
||||||
char proc[ttcols];
|
char proc[ttcols];
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
@@ -450,7 +467,7 @@ int cgroup_tree(char *path, char *pfx, int mode, int pos)
|
|||||||
strlcat(row, pfx, rplen);
|
strlcat(row, pfx, rplen);
|
||||||
strlcat(row, ++i == num ? END : FORK, rlen);
|
strlcat(row, ++i == num ? END : FORK, rlen);
|
||||||
|
|
||||||
snprintf(proc, sizeof(proc), " %d %s %s", pid, comm, buf);
|
snprintf(proc, sizeof(proc), " %d %s", pid, cmdline);
|
||||||
|
|
||||||
if (plain) {
|
if (plain) {
|
||||||
strlcat(row, proc, rplen);
|
strlcat(row, proc, rplen);
|
||||||
@@ -468,6 +485,8 @@ int cgroup_tree(char *path, char *pfx, int mode, int pos)
|
|||||||
}
|
}
|
||||||
|
|
||||||
puts(row);
|
puts(row);
|
||||||
|
|
||||||
|
free(cmdline);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode == 1) {
|
if (mode == 1) {
|
||||||
|
|||||||
+2
-3
@@ -54,9 +54,8 @@ struct cg {
|
|||||||
|
|
||||||
int cgroup_avail(void);
|
int cgroup_avail(void);
|
||||||
|
|
||||||
char *pid_cmdline (int pid, char *buf, size_t len);
|
char *pid_cmdline (int pid);
|
||||||
char *pid_comm (int pid, char *buf, size_t len);
|
char *pid_cgroup (int pid);
|
||||||
char *pid_cgroup (int pid, char *buf, size_t len);
|
|
||||||
|
|
||||||
uint64_t cgroup_memory(char *group);
|
uint64_t cgroup_memory(char *group);
|
||||||
|
|
||||||
|
|||||||
@@ -97,16 +97,6 @@ int client_request(struct init_request *rq, ssize_t len)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Exception, only command that don't need to wait for a
|
|
||||||
* response from Finit. Registers the client socket as a
|
|
||||||
* readiness notification socket with Finit
|
|
||||||
*/
|
|
||||||
if (rq->cmd == INIT_CMD_NOTIFY_SOCKET) {
|
|
||||||
rq->cmd = INIT_CMD_ACK;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pfd.fd = sd;
|
pfd.fd = sd;
|
||||||
pfd.events = POLLIN | POLLERR | POLLHUP;
|
pfd.events = POLLIN | POLLERR | POLLHUP;
|
||||||
if ((rc = poll(&pfd, 1, REQUEST_TIMEOUT)) <= 0) {
|
if ((rc = poll(&pfd, 1, REQUEST_TIMEOUT)) <= 0) {
|
||||||
|
|||||||
+7
-2
@@ -113,7 +113,7 @@ static void cond_boot_strap(void)
|
|||||||
*
|
*
|
||||||
* => 'pid/' + 'teamd' + '' = condition <pid/teamd>
|
* => 'pid/' + 'teamd' + '' = condition <pid/teamd>
|
||||||
*
|
*
|
||||||
* When you add a second aggrate you need to tell Finit it's a different
|
* When you add a second aggregate you need to tell Finit it's a different
|
||||||
* instance usugin the :ID syntax:
|
* instance usugin the :ID syntax:
|
||||||
*
|
*
|
||||||
* service :lag2 teamd -f /etc/teamd/lag2.conf -- Aggregate lag2
|
* service :lag2 teamd -f /etc/teamd/lag2.conf -- Aggregate lag2
|
||||||
@@ -202,6 +202,9 @@ static int do_delete(const char *fpath, const struct stat *sb, int tflag, struct
|
|||||||
{
|
{
|
||||||
const char *cond, *ptr;
|
const char *cond, *ptr;
|
||||||
|
|
||||||
|
(void)sb;
|
||||||
|
(void)tflag;
|
||||||
|
|
||||||
if (ftw->level == 0)
|
if (ftw->level == 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@@ -215,7 +218,7 @@ static int do_delete(const char *fpath, const struct stat *sb, int tflag, struct
|
|||||||
err(1, "Failed removing condition %s", fpath);
|
err(1, "Failed removing condition %s", fpath);
|
||||||
|
|
||||||
cond = ptr + strlen(COND_BASE) + 1;
|
cond = ptr + strlen(COND_BASE) + 1;
|
||||||
if (sm_is_in_teardown(&sm))
|
if (sm_in_reload())
|
||||||
cond_clear_noupdate(cond);
|
cond_clear_noupdate(cond);
|
||||||
else
|
else
|
||||||
cond_update(cond);
|
cond_update(cond);
|
||||||
@@ -390,6 +393,8 @@ static int do_assert(const char *fpath, const struct stat *sb, int tflg, struct
|
|||||||
{
|
{
|
||||||
char *nm;
|
char *nm;
|
||||||
|
|
||||||
|
(void)sb;
|
||||||
|
|
||||||
if (ftw->level == 0)
|
if (ftw->level == 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
|||||||
+7
-7
@@ -96,16 +96,16 @@ 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)
|
||||||
{
|
{
|
||||||
static char conds[MAX_COND_LEN];
|
|
||||||
enum cond_state s = COND_ON;
|
enum cond_state s = COND_ON;
|
||||||
char *cond;
|
|
||||||
|
|
||||||
if (!names)
|
if (names) {
|
||||||
return COND_ON;
|
char conds[strlen(names) + 1];
|
||||||
|
const char *cond;
|
||||||
|
|
||||||
strlcpy(conds, names, sizeof(conds));
|
strlcpy(conds, names, sizeof(conds));
|
||||||
for (cond = strtok(conds, ","); s && cond; cond = strtok(NULL, ","))
|
for (cond = strtok(conds, ","); s && cond; cond = strtok(NULL, ","))
|
||||||
s = min(s, cond_get(cond));
|
s = min(s, cond_get(cond));
|
||||||
|
}
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|||||||
+72
-25
@@ -50,6 +50,25 @@
|
|||||||
|
|
||||||
#define BOOTSTRAP (runlevel == INIT_LEVEL)
|
#define BOOTSTRAP (runlevel == INIT_LEVEL)
|
||||||
|
|
||||||
|
int runlevel = INIT_LEVEL; /* Bootstrap 'S' */
|
||||||
|
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
|
||||||
|
int cmdlevel = 0; /* runlevel override from cmdline */
|
||||||
|
int prevlevel = -1;
|
||||||
|
int debug = 0; /* debug mode from kernel cmdline */
|
||||||
|
int rescue = 0; /* rescue mode from kernel cmdline */
|
||||||
|
int single = 0; /* single user mode from kernel cmdline */
|
||||||
|
int bootstrap = 1; /* set while bootstrapping (for TTYs) */
|
||||||
|
int kerndebug = 0; /* set if /proc/sys/kernel/printk > 7 */
|
||||||
|
int syncsec = 0; /* reboot delay */
|
||||||
|
int readiness = SVC_NOTIFY_PID;
|
||||||
|
char *finit_conf= NULL;
|
||||||
|
char *finit_rcsd= NULL;
|
||||||
|
char *fstab = NULL;
|
||||||
|
char *sdown = NULL;
|
||||||
|
char *network = NULL;
|
||||||
|
char *hostname = NULL;
|
||||||
|
char *osheading = NULL;
|
||||||
|
|
||||||
int logfile_size_max = 200000; /* 200 kB */
|
int logfile_size_max = 200000; /* 200 kB */
|
||||||
int logfile_count_max = 5;
|
int logfile_count_max = 5;
|
||||||
|
|
||||||
@@ -490,14 +509,16 @@ void conf_save_service(int type, char *cfg, char *file)
|
|||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Sets, and makes a note of, all KEY=VALUE lines in a given .conf line
|
* conf_parse_env - Parse a key=value line
|
||||||
* from finit.conf, or other .conf file. Note, PATH is always reset in
|
* @line: Line buffer without newline
|
||||||
* the conf_reset_env() function.
|
* @value: Whitespace trimmed value
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* %NULL on error, otherwise a whitespace trimmed key.
|
||||||
*/
|
*/
|
||||||
static void parse_env(char *line)
|
char *conf_parse_env(char *line, char **value)
|
||||||
{
|
{
|
||||||
struct env_entry *node;
|
|
||||||
char *key, *val, *end;
|
char *key, *val, *end;
|
||||||
|
|
||||||
/* skip any leading whitespace */
|
/* skip any leading whitespace */
|
||||||
@@ -519,7 +540,7 @@ static void parse_env(char *line)
|
|||||||
|
|
||||||
val = strchr(key, '=');
|
val = strchr(key, '=');
|
||||||
if (!val)
|
if (!val)
|
||||||
return;
|
return NULL;
|
||||||
*val++ = 0;
|
*val++ = 0;
|
||||||
|
|
||||||
/* strip leading whitespace from value */
|
/* strip leading whitespace from value */
|
||||||
@@ -527,14 +548,8 @@ static void parse_env(char *line)
|
|||||||
val++;
|
val++;
|
||||||
|
|
||||||
/* unquote value, if quoted */
|
/* unquote value, if quoted */
|
||||||
if (val[0] == '"' || val[0] == '\'') {
|
unquote(&val, end);
|
||||||
char q = val[0];
|
*value = val;
|
||||||
|
|
||||||
if (*end == q) {
|
|
||||||
val = &val[1];
|
|
||||||
*end = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* find end of key */
|
/* find end of key */
|
||||||
end = key;
|
end = key;
|
||||||
@@ -561,18 +576,42 @@ static void parse_env(char *line)
|
|||||||
end++;
|
end++;
|
||||||
if (*end != 0) {
|
if (*end != 0) {
|
||||||
warnx("'%s=%s': not a valid identifier", key, val);
|
warnx("'%s=%s': not a valid identifier", key, val);
|
||||||
return; /* invalid key */
|
return NULL; /* invalid key */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sets, and makes a note of, all KEY=VALUE lines in a given .conf line
|
||||||
|
* from finit.conf, or other .conf file. Note, PATH is always reset in
|
||||||
|
* the conf_reset_env() function.
|
||||||
|
*/
|
||||||
|
static void parse_env(char *line)
|
||||||
|
{
|
||||||
|
struct env_entry *node;
|
||||||
|
char *key, *val;
|
||||||
|
|
||||||
|
key = conf_parse_env(line, &val);
|
||||||
|
if (!key)
|
||||||
|
return;
|
||||||
|
|
||||||
dbg("Global env '%s'='%s'", key, val);
|
dbg("Global env '%s'='%s'", key, val);
|
||||||
setenv(key, val, 1);
|
setenv(key, val, 1);
|
||||||
|
|
||||||
node = malloc(sizeof(*node));
|
node = malloc(sizeof(*node));
|
||||||
if (!node) {
|
if (!node) {
|
||||||
|
nomem:
|
||||||
err(1, "Out of memory cannot track env vars");
|
err(1, "Out of memory cannot track env vars");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
node->name = strdup(key);
|
node->name = strdup(key);
|
||||||
|
if (!node->name) {
|
||||||
|
free(node);
|
||||||
|
goto nomem;
|
||||||
|
}
|
||||||
|
|
||||||
TAILQ_INSERT_HEAD(&env_list, node, link);
|
TAILQ_INSERT_HEAD(&env_list, node, link);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1542,6 +1581,13 @@ static int conf_iwatch_read(int fd)
|
|||||||
|
|
||||||
static void conf_cb(uev_t *w, void *arg, int events)
|
static void conf_cb(uev_t *w, void *arg, int events)
|
||||||
{
|
{
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
if (UEV_ERROR == events) {
|
||||||
|
dbg("%s(): iwatch socket %d invalid.", __func__, w->fd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (conf_iwatch_read(w->fd)) {
|
if (conf_iwatch_read(w->fd)) {
|
||||||
err(1, "invalid inotify event");
|
err(1, "invalid inotify event");
|
||||||
return;
|
return;
|
||||||
@@ -1550,7 +1596,7 @@ static void conf_cb(uev_t *w, void *arg, int events)
|
|||||||
|
|
||||||
#ifdef AUTO_RELOAD
|
#ifdef AUTO_RELOAD
|
||||||
if (conf_any_change())
|
if (conf_any_change())
|
||||||
service_reload_dynamic();
|
sm_reload();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1574,25 +1620,26 @@ int conf_monitor(void)
|
|||||||
* have or not have symlinks in place. We need to monitor for
|
* have or not have symlinks in place. We need to monitor for
|
||||||
* changes to either symlink or target.
|
* changes to either symlink or target.
|
||||||
*/
|
*/
|
||||||
rc += iwatch_add(&iw_conf, finit_rcsd, IN_ONLYDIR);
|
rc |= iwatch_add(&iw_conf, finit_rcsd, IN_ONLYDIR);
|
||||||
snprintf(path, sizeof(path), "%s/available/", finit_rcsd);
|
snprintf(path, sizeof(path), "%s/available/", finit_rcsd);
|
||||||
rc += iwatch_add(&iw_conf, path, IN_ONLYDIR | IN_DONT_FOLLOW);
|
rc |= iwatch_add(&iw_conf, path, IN_ONLYDIR | IN_DONT_FOLLOW);
|
||||||
snprintf(path, sizeof(path), "%s/enabled/", finit_rcsd);
|
snprintf(path, sizeof(path), "%s/enabled/", finit_rcsd);
|
||||||
rc += iwatch_add(&iw_conf, path, IN_ONLYDIR | IN_DONT_FOLLOW);
|
rc |= iwatch_add(&iw_conf, path, IN_ONLYDIR | IN_DONT_FOLLOW);
|
||||||
rc += iwatch_add(&iw_conf, finit_conf, 0);
|
rc |= iwatch_add(&iw_conf, finit_conf, 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Systems with /etc/default, /etc/conf.d, or similar, can also
|
* Systems with /etc/default, /etc/conf.d, or similar, can also
|
||||||
* monitor changes in env files sourced by .conf files (above)
|
* monitor changes in env files sourced by .conf files (above)
|
||||||
* define your own with --with-sysconfig=/path/to/envfiles
|
* define your own with --with-sysconfig=/path/to/envfiles
|
||||||
*/
|
*/
|
||||||
rc += iwatch_add(&iw_conf, "/etc/default/", IN_ONLYDIR);
|
rc |= iwatch_add(&iw_conf, "/etc/default/", IN_ONLYDIR);
|
||||||
rc += iwatch_add(&iw_conf, "/etc/conf.d/", IN_ONLYDIR);
|
rc |= iwatch_add(&iw_conf, "/etc/conf.d/", IN_ONLYDIR);
|
||||||
#ifdef FINIT_SYSCONFIG
|
#ifdef FINIT_SYSCONFIG
|
||||||
rc += iwatch_add(&iw_conf, FINIT_SYSCONFIG, IN_ONLYDIR);
|
rc |= iwatch_add(&iw_conf, FINIT_SYSCONFIG, IN_ONLYDIR);
|
||||||
#endif
|
#endif
|
||||||
|
rc |= conf_reload();
|
||||||
|
|
||||||
return rc + conf_reload();
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
+19
@@ -27,6 +27,24 @@
|
|||||||
#include "cgroup.h"
|
#include "cgroup.h"
|
||||||
#include "svc.h"
|
#include "svc.h"
|
||||||
|
|
||||||
|
extern int runlevel;
|
||||||
|
extern int cfglevel;
|
||||||
|
extern int cmdlevel;
|
||||||
|
extern int prevlevel;
|
||||||
|
extern int debug;
|
||||||
|
extern int rescue;
|
||||||
|
extern int single;
|
||||||
|
extern int bootstrap;
|
||||||
|
extern int kerndebug;
|
||||||
|
extern int syncsec;
|
||||||
|
extern int readiness;
|
||||||
|
extern char *fstab;
|
||||||
|
extern char *sdown;
|
||||||
|
extern char *network;
|
||||||
|
extern char *hostname;
|
||||||
|
extern char *runparts;
|
||||||
|
extern char *osheading;
|
||||||
|
|
||||||
extern int logfile_size_max;
|
extern int logfile_size_max;
|
||||||
extern int logfile_count_max;
|
extern int logfile_count_max;
|
||||||
|
|
||||||
@@ -47,6 +65,7 @@ void conf_saverc (void);
|
|||||||
void conf_save_exec_order (svc_t *svc, char *cmdline, int result);
|
void conf_save_exec_order (svc_t *svc, char *cmdline, int result);
|
||||||
void conf_save_service (int type, char *cfg, char *file);
|
void conf_save_service (int type, char *cfg, char *file);
|
||||||
void conf_parse_cmdline (int argc, char *argv[]);
|
void conf_parse_cmdline (int argc, char *argv[]);
|
||||||
|
char *conf_parse_env (char *line, char **val);
|
||||||
int conf_parse_runlevels (char *runlevels);
|
int conf_parse_runlevels (char *runlevels);
|
||||||
void conf_parse_cond (svc_t *svc, char *cond);
|
void conf_parse_cond (svc_t *svc, char *cond);
|
||||||
|
|
||||||
|
|||||||
+10
-1
@@ -77,7 +77,7 @@ void devmon_add_cond(const char *cond)
|
|||||||
struct dev_node *node;
|
struct dev_node *node;
|
||||||
|
|
||||||
if (!cond || strncmp(cond, "dev/", 4)) {
|
if (!cond || strncmp(cond, "dev/", 4)) {
|
||||||
dbg("no match");
|
// dbg("no match %s", cond ?: "<NIL>");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,6 +164,8 @@ static void devmon_scandir(struct iwatch *iw, char *dir, int len)
|
|||||||
size_t i;
|
size_t i;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
(void)iw;
|
||||||
|
|
||||||
snprintf(path, sizeof(path), "%s/*", dir);
|
snprintf(path, sizeof(path), "%s/*", dir);
|
||||||
rc = glob(path, GLOB_NOSORT, NULL, &gl);
|
rc = glob(path, GLOB_NOSORT, NULL, &gl);
|
||||||
if (rc && rc != GLOB_NOMATCH)
|
if (rc && rc != GLOB_NOMATCH)
|
||||||
@@ -207,6 +209,13 @@ static void devmon_cb(uev_t *w, void *arg, int events)
|
|||||||
ssize_t sz;
|
ssize_t sz;
|
||||||
size_t off;
|
size_t off;
|
||||||
|
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
if (UEV_ERROR == events) {
|
||||||
|
errx(1, "Unrecoverable error in devmon watcher");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
sz = read(w->fd, ev_buf, sizeof(ev_buf) - 1);
|
sz = read(w->fd, ev_buf, sizeof(ev_buf) - 1);
|
||||||
if (sz <= 0) {
|
if (sz <= 0) {
|
||||||
err(1, "invalid inotify event");
|
err(1, "invalid inotify event");
|
||||||
|
|||||||
+3
-3
@@ -199,7 +199,6 @@ int run(char *cmd, char *log)
|
|||||||
int run_interactive(char *cmd, char *fmt, ...)
|
int run_interactive(char *cmd, char *fmt, ...)
|
||||||
{
|
{
|
||||||
int status, oldout = 1, olderr = 2;
|
int status, oldout = 1, olderr = 2;
|
||||||
char line[LINE_SIZE];
|
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
if (!cmd) {
|
if (!cmd) {
|
||||||
@@ -244,6 +243,7 @@ int run_interactive(char *cmd, char *fmt, ...)
|
|||||||
|
|
||||||
/* Dump any results of cmd on stderr after we've printed [ OK ] or [FAIL] */
|
/* Dump any results of cmd on stderr after we've printed [ OK ] or [FAIL] */
|
||||||
if (fp && !debug) {
|
if (fp && !debug) {
|
||||||
|
char line[LINE_SIZE];
|
||||||
size_t len, written;
|
size_t len, written;
|
||||||
|
|
||||||
rewind(fp);
|
rewind(fp);
|
||||||
@@ -281,7 +281,7 @@ int exec_runtask(char *cmd, char *args[])
|
|||||||
return execvp(_PATH_BSHELL, argv);
|
return execvp(_PATH_BSHELL, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit rlimit[])
|
static void prepare_tty(char *tty, speed_t speed, const char *procname, struct rlimit rlimit[])
|
||||||
{
|
{
|
||||||
char name[80];
|
char name[80];
|
||||||
int fd, dummy;
|
int fd, dummy;
|
||||||
@@ -351,7 +351,7 @@ static int activate_console(int noclear, int nowait)
|
|||||||
dprint(STDERR_FILENO, clr, strlen(clr));
|
dprint(STDERR_FILENO, clr, strlen(clr));
|
||||||
dprint(STDERR_FILENO, msg, strlen(msg));
|
dprint(STDERR_FILENO, msg, strlen(msg));
|
||||||
while ((rc = read(STDIN_FILENO, &ch, 1)) > 0 && ch != '\r' && ch != '\n')
|
while ((rc = read(STDIN_FILENO, &ch, 1)) > 0 && ch != '\r' && ch != '\n')
|
||||||
continue;
|
;
|
||||||
|
|
||||||
/* On any error (likely EINTR), we avoid starting getty */
|
/* On any error (likely EINTR), we avoid starting getty */
|
||||||
if (rc == -1)
|
if (rc == -1)
|
||||||
|
|||||||
+3
-22
@@ -59,25 +59,6 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "utmp-api.h"
|
#include "utmp-api.h"
|
||||||
|
|
||||||
int runlevel = INIT_LEVEL; /* Bootstrap 'S' */
|
|
||||||
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
|
|
||||||
int cmdlevel = 0; /* runlevel override from cmdline */
|
|
||||||
int prevlevel = -1;
|
|
||||||
int debug = 0; /* debug mode from kernel cmdline */
|
|
||||||
int rescue = 0; /* rescue mode from kernel cmdline */
|
|
||||||
int single = 0; /* single user mode from kernel cmdline */
|
|
||||||
int bootstrap = 1; /* set while bootrapping (for TTYs) */
|
|
||||||
int kerndebug = 0; /* set if /proc/sys/kernel/printk > 7 */
|
|
||||||
int syncsec = 0; /* reboot delay */
|
|
||||||
int readiness = SVC_NOTIFY_PID;
|
|
||||||
char *finit_conf= NULL;
|
|
||||||
char *finit_rcsd= NULL;
|
|
||||||
char *fstab = NULL;
|
|
||||||
char *sdown = NULL;
|
|
||||||
char *network = NULL;
|
|
||||||
char *hostname = NULL;
|
|
||||||
char *osheading = NULL;
|
|
||||||
|
|
||||||
uev_ctx_t *ctx = NULL; /* Main loop context */
|
uev_ctx_t *ctx = NULL; /* Main loop context */
|
||||||
svc_t *wdog = NULL; /* No watchdog by default */
|
svc_t *wdog = NULL; /* No watchdog by default */
|
||||||
|
|
||||||
@@ -280,7 +261,7 @@ static int fsck(int pass)
|
|||||||
sulogin(1);
|
sulogin(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rc += fsck_rc;
|
rc |= fsck_rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
endmntent(fp);
|
endmntent(fp);
|
||||||
@@ -745,8 +726,8 @@ int main(int argc, char *argv[])
|
|||||||
* Initialize state machine and start all bootstrap tasks
|
* Initialize state machine and start all bootstrap tasks
|
||||||
* NOTE: no network available!
|
* NOTE: no network available!
|
||||||
*/
|
*/
|
||||||
sm_init(&sm);
|
sm_init();
|
||||||
sm_step(&sm);
|
sm_step();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enter main loop to monitor /dev/initctl and services
|
* Enter main loop to monitor /dev/initctl and services
|
||||||
|
|||||||
+6
-20
@@ -54,11 +54,17 @@
|
|||||||
#define FINIT_CGPATH "/sys/fs/cgroup"
|
#define FINIT_CGPATH "/sys/fs/cgroup"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Prevent users from logging in at critical stages */
|
||||||
|
#ifndef FINIT_NOLOGIN_PATH
|
||||||
|
#define FINIT_NOLOGIN_PATH _PATH_NOLOGIN
|
||||||
|
#endif
|
||||||
|
|
||||||
/* To use these, include config.h, or define FINIT_EXECPATH_ */
|
/* To use these, include config.h, or define FINIT_EXECPATH_ */
|
||||||
#define _PATH_LOGIT FINIT_EXECPATH_ "/logit"
|
#define _PATH_LOGIT FINIT_EXECPATH_ "/logit"
|
||||||
#define _PATH_RUNPARTS FINIT_EXECPATH_ "/runparts"
|
#define _PATH_RUNPARTS FINIT_EXECPATH_ "/runparts"
|
||||||
#define _PATH_SULOGIN FINIT_EXECPATH_ "/sulogin"
|
#define _PATH_SULOGIN FINIT_EXECPATH_ "/sulogin"
|
||||||
#define _PATH_GETTY FINIT_EXECPATH_ "/getty"
|
#define _PATH_GETTY FINIT_EXECPATH_ "/getty"
|
||||||
|
#define _PATH_TMPFILES FINIT_EXECPATH_ "/tmpfiles"
|
||||||
|
|
||||||
#define CMD_SIZE 1024
|
#define CMD_SIZE 1024
|
||||||
#define LINE_SIZE 1024
|
#define LINE_SIZE 1024
|
||||||
@@ -98,7 +104,6 @@
|
|||||||
#define INIT_CMD_SVC_FIND 131
|
#define INIT_CMD_SVC_FIND 131
|
||||||
#define INIT_CMD_SVC_FIND_BYC 132
|
#define INIT_CMD_SVC_FIND_BYC 132
|
||||||
#define INIT_CMD_SIGNAL 133
|
#define INIT_CMD_SIGNAL 133
|
||||||
#define INIT_CMD_NOTIFY_SOCKET 200 /* For readiness notification socket */
|
|
||||||
#define INIT_CMD_NACK 254
|
#define INIT_CMD_NACK 254
|
||||||
#define INIT_CMD_ACK 255
|
#define INIT_CMD_ACK 255
|
||||||
|
|
||||||
@@ -111,25 +116,6 @@ struct init_request {
|
|||||||
char data[368];
|
char data[368];
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int runlevel;
|
|
||||||
extern int cfglevel;
|
|
||||||
extern int cmdlevel;
|
|
||||||
extern int prevlevel;
|
|
||||||
extern int debug;
|
|
||||||
extern int rescue;
|
|
||||||
extern int single;
|
|
||||||
extern int bootstrap;
|
|
||||||
extern int kerndebug;
|
|
||||||
extern int syncsec;
|
|
||||||
extern int readiness;
|
|
||||||
extern char *fstab;
|
|
||||||
extern char *sdown;
|
|
||||||
extern char *network;
|
|
||||||
extern char *hostname;
|
|
||||||
extern char *runparts;
|
|
||||||
extern char *osheading;
|
|
||||||
extern uev_ctx_t *ctx;
|
|
||||||
|
|
||||||
#endif /* FINIT_H_ */
|
#endif /* FINIT_H_ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+2
-2
@@ -312,9 +312,9 @@ static int exec_login(char *name)
|
|||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if (passenv)
|
if (passenv)
|
||||||
execl(_PATH_LOGIN, _PATH_LOGIN, "-p", name, NULL);
|
execl(_PATH_LOGIN, _PATH_LOGIN, "-p", "--", name, NULL);
|
||||||
else
|
else
|
||||||
execl(_PATH_LOGIN, _PATH_LOGIN, name, NULL);
|
execl(_PATH_LOGIN, _PATH_LOGIN, "--", name, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Failed to exec login, should not happen on normal systems.
|
* Failed to exec login, should not happen on normal systems.
|
||||||
|
|||||||
+4
-95
@@ -26,8 +26,6 @@
|
|||||||
|
|
||||||
#include <ctype.h> /* isblank() */
|
#include <ctype.h> /* isblank() */
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <grp.h>
|
|
||||||
#include <pwd.h>
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
@@ -42,6 +40,7 @@
|
|||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
#include "conf.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "private.h"
|
#include "private.h"
|
||||||
#include "sig.h"
|
#include "sig.h"
|
||||||
@@ -87,7 +86,7 @@ void console_init(void)
|
|||||||
/* Enable line wrap, if disabled previously, e.g., qemu */
|
/* Enable line wrap, if disabled previously, e.g., qemu */
|
||||||
dprint(STDOUT_FILENO, "\033[?7h", 5);
|
dprint(STDOUT_FILENO, "\033[?7h", 5);
|
||||||
|
|
||||||
/* Reset atttributes, background and foreground color */
|
/* Reset attributes, background and foreground color */
|
||||||
dprint(STDOUT_FILENO, "\033[49m\033[39m\e[2J", 14);
|
dprint(STDOUT_FILENO, "\033[49m\033[39m\e[2J", 14);
|
||||||
|
|
||||||
log_init();
|
log_init();
|
||||||
@@ -293,6 +292,8 @@ static size_t print_timestamp(char *buf, size_t len)
|
|||||||
sscanf(buf, "%f %f", &stamp, &dummy);
|
sscanf(buf, "%f %f", &stamp, &dummy);
|
||||||
return snprintf(buf, len, "[ %.6f ]", stamp);
|
return snprintf(buf, len, "[ %.6f ]", stamp);
|
||||||
#else
|
#else
|
||||||
|
(void)buf;
|
||||||
|
(void)len;
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -370,98 +371,6 @@ int print_result(int fail)
|
|||||||
return fail;
|
return fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getuser(char *username, char **home)
|
|
||||||
{
|
|
||||||
#ifdef ENABLE_STATIC
|
|
||||||
if (home)
|
|
||||||
*home = "/"; /* XXX: Fixme */
|
|
||||||
return fgetint("/etc/passwd", "x:\n", username);
|
|
||||||
#else
|
|
||||||
struct passwd *usr;
|
|
||||||
|
|
||||||
if (!username || (usr = getpwnam(username)) == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (home)
|
|
||||||
*home = usr->pw_dir;
|
|
||||||
return usr->pw_uid;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int getgroup(char *group)
|
|
||||||
{
|
|
||||||
#ifdef ENABLE_STATIC
|
|
||||||
return fgetint("/etc/group", "x:\n", group);
|
|
||||||
#else
|
|
||||||
struct group *grp;
|
|
||||||
|
|
||||||
if ((grp = getgrnam(group)) == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return grp->gr_gid;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get current user */
|
|
||||||
int getcuser(char *buf, size_t len)
|
|
||||||
{
|
|
||||||
char *ptr = "root";
|
|
||||||
|
|
||||||
#ifndef ENABLE_STATIC
|
|
||||||
struct passwd *pw = getpwuid(getuid());
|
|
||||||
|
|
||||||
if (pw)
|
|
||||||
ptr = pw->pw_name;
|
|
||||||
#endif
|
|
||||||
if (strlcpy(buf, ptr, len) > len)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get current group */
|
|
||||||
int getcgroup(char *buf, size_t len)
|
|
||||||
{
|
|
||||||
char *ptr = "root";
|
|
||||||
|
|
||||||
#ifndef ENABLE_STATIC
|
|
||||||
struct group *gr = getgrgid(getgid());
|
|
||||||
|
|
||||||
if (gr)
|
|
||||||
ptr = gr->gr_name;
|
|
||||||
#endif
|
|
||||||
if (strlcpy(buf, ptr, len) > len)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mksubsys(const char *dir, mode_t mode, char *user, char *group)
|
|
||||||
{
|
|
||||||
mode_t omask;
|
|
||||||
int uid, gid;
|
|
||||||
int rc = 0;
|
|
||||||
|
|
||||||
omask = umask(0);
|
|
||||||
|
|
||||||
uid = getuser(user, NULL);
|
|
||||||
if (uid >= 0) {
|
|
||||||
gid = getgroup(group);
|
|
||||||
if (gid < 0)
|
|
||||||
gid = 0;
|
|
||||||
|
|
||||||
rc = makedir(dir, mode);
|
|
||||||
if (rc && errno == EEXIST)
|
|
||||||
rc = chmod(dir, mode);
|
|
||||||
if (chown(dir, uid, gid))
|
|
||||||
err(1, "Failed chown(%s, %d, %d)", dir, uid, gid);
|
|
||||||
}
|
|
||||||
|
|
||||||
umask(omask);
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_hostname(char **hostname)
|
void set_hostname(char **hostname)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|||||||
+2
-61
@@ -39,7 +39,6 @@
|
|||||||
#else
|
#else
|
||||||
# include <lite/lite.h>
|
# include <lite/lite.h>
|
||||||
#endif
|
#endif
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
#define PROGRESS_DEFAULT PROGRESS_MODERN
|
#define PROGRESS_DEFAULT PROGRESS_MODERN
|
||||||
|
|
||||||
@@ -70,14 +69,6 @@ void print (int action, const char *fmt, ...) __attribute__ ((forma
|
|||||||
void print_desc (char *action, char *desc);
|
void print_desc (char *action, char *desc);
|
||||||
int print_result (int fail);
|
int print_result (int fail);
|
||||||
|
|
||||||
int getuser (char *username, char **home);
|
|
||||||
int getgroup (char *group);
|
|
||||||
|
|
||||||
int getcuser (char *buf, size_t len);
|
|
||||||
int getcgroup (char *buf, size_t len);
|
|
||||||
|
|
||||||
int mksubsys (const char *dir, mode_t mode, char *user, char *group);
|
|
||||||
|
|
||||||
void set_hostname (char **hostname);
|
void set_hostname (char **hostname);
|
||||||
void networking (int updown);
|
void networking (int updown);
|
||||||
int in_container (void);
|
int in_container (void);
|
||||||
@@ -91,56 +82,6 @@ pid_t run_sh (char *tty, int noclear, int nowait, struct rlimit rlimi
|
|||||||
pid_t run_bg (char *cmd, char *args[]);
|
pid_t run_bg (char *cmd, char *args[]);
|
||||||
int run_parts (char *dir, char *cmd, const char *env[], int progress, int sysv);
|
int run_parts (char *dir, char *cmd, const char *env[], int progress, int sysv);
|
||||||
|
|
||||||
/*
|
|
||||||
* Defaults to user "root" and group "wheel" (root) if:
|
|
||||||
* 1) the user is missing
|
|
||||||
* 2) the group or the file /etc/group is missing
|
|
||||||
*/
|
|
||||||
static inline int create(char *path, mode_t mode, char *user, char *group)
|
|
||||||
{
|
|
||||||
int fd, uid, gid;
|
|
||||||
|
|
||||||
if (!path) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uid = getuser(user, NULL);
|
|
||||||
if (uid < 0)
|
|
||||||
uid = 0;
|
|
||||||
gid = getgroup(group);
|
|
||||||
if (gid < 0)
|
|
||||||
gid = 0;
|
|
||||||
|
|
||||||
fd = creat(path, mode);
|
|
||||||
if (fd == -1) {
|
|
||||||
warn("Failed creating %s properly", path);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
if (chown(path, uid, gid)) {
|
|
||||||
warn("Failed chowning %s properly", path);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int ln(const char *target, const char *linkpath)
|
|
||||||
{
|
|
||||||
if (!target || !linkpath) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (symlink(target, linkpath)) {
|
|
||||||
if (errno != EEXIST)
|
|
||||||
warn("Failed creating %s -> %s symlink", target, linkpath);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
static inline int dprint(int fd, const char *s, size_t len)
|
static inline int dprint(int fd, const char *s, size_t len)
|
||||||
{
|
{
|
||||||
size_t loop = 3;
|
size_t loop = 3;
|
||||||
@@ -159,7 +100,7 @@ static inline int dprint(int fd, const char *s, size_t len)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline char *fgetval(char *line, const char *key, char *sep)
|
static inline char *fgetval(const char *line, const char *key, char *sep)
|
||||||
{
|
{
|
||||||
char *ptr, *str, *copy;
|
char *ptr, *str, *copy;
|
||||||
size_t len;
|
size_t len;
|
||||||
@@ -179,7 +120,7 @@ static inline char *fgetval(char *line, const char *key, char *sep)
|
|||||||
* Check if we should strip optional separator, e.g.,
|
* Check if we should strip optional separator, e.g.,
|
||||||
* 'foo = bar' => '= bar' should be stripped to 'bar'
|
* 'foo = bar' => '= bar' should be stripped to 'bar'
|
||||||
*/
|
*/
|
||||||
while (str && strchr(sep, str[0])) {
|
while (strchr(sep, str[0])) {
|
||||||
ptr = strsep(&str, sep);
|
ptr = strsep(&str, sep);
|
||||||
if (!ptr)
|
if (!ptr)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|||||||
+18
-19
@@ -767,27 +767,25 @@ static int plugins_list(char *arg)
|
|||||||
*/
|
*/
|
||||||
char *runlevel_string(int currlevel, int levels)
|
char *runlevel_string(int currlevel, int levels)
|
||||||
{
|
{
|
||||||
static char lvl[21];
|
static char lvl[32];
|
||||||
int i = INIT_LEVEL;
|
int i = INIT_LEVEL;
|
||||||
int pos = 1;
|
|
||||||
|
|
||||||
memset(lvl, 0, sizeof(lvl));
|
strlcpy(lvl, "[", sizeof(lvl));
|
||||||
lvl[0] = '[';
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (ISSET(levels, i)) {
|
if (ISSET(levels, i)) {
|
||||||
if (!plain && currlevel == i)
|
char l[2] = { '0' + i, 0 };
|
||||||
pos = strlcat(lvl, "\e[1m", sizeof(lvl));
|
|
||||||
|
|
||||||
if (i == INIT_LEVEL)
|
|
||||||
lvl[pos++] = 'S';
|
|
||||||
else
|
|
||||||
lvl[pos++] = '0' + i;
|
|
||||||
|
|
||||||
if (!plain && currlevel == i)
|
if (!plain && currlevel == i)
|
||||||
pos = strlcat(lvl, "\e[0m", sizeof(lvl));
|
strlcat(lvl, "\e[1m", sizeof(lvl));
|
||||||
|
|
||||||
|
strlcat(lvl, i == INIT_LEVEL ? "S" : l, sizeof(lvl));
|
||||||
|
|
||||||
|
|
||||||
|
if (!plain && currlevel == i)
|
||||||
|
strlcat(lvl, "\e[0m", sizeof(lvl));
|
||||||
} else {
|
} else {
|
||||||
lvl[pos++] = '-';
|
strlcat(lvl, "-", sizeof(lvl));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: ugly hack to get order right: S0123456789 */
|
/* XXX: ugly hack to get order right: S0123456789 */
|
||||||
@@ -798,8 +796,7 @@ char *runlevel_string(int currlevel, int levels)
|
|||||||
} while (i < INIT_LEVEL);
|
} while (i < INIT_LEVEL);
|
||||||
|
|
||||||
|
|
||||||
lvl[pos++] = ']';
|
strlcat(lvl, "]", sizeof(lvl));
|
||||||
lvl[pos] = 0;
|
|
||||||
|
|
||||||
return lvl;
|
return lvl;
|
||||||
}
|
}
|
||||||
@@ -872,7 +869,7 @@ static char *svc_environ(svc_t *svc, char *buf, size_t len, int ansi)
|
|||||||
{
|
{
|
||||||
int bold = missing(svc);
|
int bold = missing(svc);
|
||||||
|
|
||||||
if (!ansi || svc_checkenv(svc) || svc->env[0] == '-')
|
if (!ansi || svc_checkenv(svc))
|
||||||
bold = 0;
|
bold = 0;
|
||||||
|
|
||||||
strlcpy(buf, bold ? "\e[1m" : "", len);
|
strlcpy(buf, bold ? "\e[1m" : "", len);
|
||||||
@@ -1138,14 +1135,14 @@ static int show_status(char *arg)
|
|||||||
printf(" Restarts : %d (%d/%d)\n", svc->restart_tot, svc->restart_cnt, svc->restart_max);
|
printf(" Restarts : %d (%d/%d)\n", svc->restart_tot, svc->restart_cnt, svc->restart_max);
|
||||||
printf(" Runlevels : %s\n", runlevel_string(runlevel, svc->runlevels));
|
printf(" Runlevels : %s\n", runlevel_string(runlevel, svc->runlevels));
|
||||||
if (cgrp && svc->pid > 1) {
|
if (cgrp && svc->pid > 1) {
|
||||||
char grbuf[128];
|
const struct cg *cg;
|
||||||
char path[256];
|
char path[256];
|
||||||
struct cg *cg;
|
|
||||||
char *group;
|
char *group;
|
||||||
|
|
||||||
group = pid_cgroup(svc->pid, grbuf, sizeof(grbuf));
|
group = pid_cgroup(svc->pid);
|
||||||
if (!group)
|
if (!group)
|
||||||
goto no_cgroup; /* ... or PID doesn't exist (anymore) */
|
goto no_cgroup; /* ... or PID doesn't exist (anymore) */
|
||||||
|
|
||||||
snprintf(path, sizeof(path), "%s/%s", FINIT_CGPATH, group);
|
snprintf(path, sizeof(path), "%s/%s", FINIT_CGPATH, group);
|
||||||
cg = cg_conf(path);
|
cg = cg_conf(path);
|
||||||
|
|
||||||
@@ -1154,6 +1151,8 @@ static int show_status(char *arg)
|
|||||||
group, cg->cg_cpu.set, cg->cg_cpu.weight, cg->cg_cpu.max,
|
group, cg->cg_cpu.set, cg->cg_cpu.weight, cg->cg_cpu.max,
|
||||||
cg->cg_mem.min, cg->cg_mem.max);
|
cg->cg_mem.min, cg->cg_mem.max);
|
||||||
show_cgroup_tree(group, " ");
|
show_cgroup_tree(group, " ");
|
||||||
|
|
||||||
|
free(group);
|
||||||
}
|
}
|
||||||
no_cgroup:
|
no_cgroup:
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|||||||
@@ -32,6 +32,9 @@
|
|||||||
# include <lite/lite.h>
|
# include <lite/lite.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define SYSLOG_NAMES
|
||||||
|
#include <syslog.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
@@ -106,6 +109,73 @@ static const char *l2s(int prio)
|
|||||||
return "UNK";
|
return "UNK";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int s2f(const char *str)
|
||||||
|
{
|
||||||
|
for (int i = 0; facilitynames[i].c_name; i++) {
|
||||||
|
if (string_match(facilitynames[i].c_name, str))
|
||||||
|
return facilitynames[i].c_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int s2l(const char *str)
|
||||||
|
{
|
||||||
|
for (int i = 0; prioritynames[i].c_name; i++) {
|
||||||
|
if (string_match(prioritynames[i].c_name, str))
|
||||||
|
return prioritynames[i].c_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse syslog facility.priority strings into their numerical values
|
||||||
|
* using arrays defined in <syslog.h>. Note, the 'prio' argument may
|
||||||
|
* be one of:
|
||||||
|
*
|
||||||
|
* - facility.level
|
||||||
|
* - facility
|
||||||
|
* - level
|
||||||
|
*
|
||||||
|
* It is up to the callee to assign defaults to 'facility' and 'level'
|
||||||
|
* before calling this function. If There is any match the respective
|
||||||
|
* facility or level will be assigned and this function returns OK.
|
||||||
|
*/
|
||||||
|
int log_parse(char *prio, int *facility, int *level)
|
||||||
|
{
|
||||||
|
char *fac = prio, *lvl;
|
||||||
|
int f = -1;
|
||||||
|
int l = -1;
|
||||||
|
|
||||||
|
if (!prio || !facility || !level)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
lvl = strchr(prio, '.');
|
||||||
|
if (lvl) {
|
||||||
|
*lvl = 0;
|
||||||
|
lvl++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lvl && *lvl)
|
||||||
|
l = s2l(lvl);
|
||||||
|
|
||||||
|
f = s2f(fac);
|
||||||
|
if (l < 0)
|
||||||
|
l = s2l(fac);
|
||||||
|
|
||||||
|
if (l < 0 && f <= 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (l <= LOG_DEBUG)
|
||||||
|
*level = l;
|
||||||
|
|
||||||
|
if (f <= LOG_LOCAL7)
|
||||||
|
*facility = f;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Log to /dev/kmsg until syslogd has started, then openlog()
|
* Log to /dev/kmsg until syslogd has started, then openlog()
|
||||||
* and continue logging as a regular daemon.
|
* and continue logging as a regular daemon.
|
||||||
@@ -139,7 +209,7 @@ void logit(int prio, const char *fmt, ...)
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(fp, "<%d>finit[1]:", LOG_DAEMON | prio);
|
fprintf(fp, "<%d>finit[1]: ", LOG_DAEMON | prio);
|
||||||
vfprintf(fp, fmt, ap);
|
vfprintf(fp, fmt, ap);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ void log_init (void);
|
|||||||
void log_exit (void);
|
void log_exit (void);
|
||||||
|
|
||||||
void log_debug(void);
|
void log_debug(void);
|
||||||
|
int log_parse(char *prio, int *facility, int *level);
|
||||||
|
|
||||||
void logit (int prio, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
void logit (int prio, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
void flog (char *file, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
void flog (char *file, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
|
|||||||
+66
-13
@@ -36,6 +36,9 @@
|
|||||||
# include <lite/lite.h>
|
# include <lite/lite.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define LOG_MAX (200 * 1024)
|
||||||
|
#define LOG_NUM 5
|
||||||
|
|
||||||
static const char version_info[] = PACKAGE_NAME " v" PACKAGE_VERSION;
|
static const char version_info[] = PACKAGE_NAME " v" PACKAGE_VERSION;
|
||||||
extern int logrotate(char *file, int num, off_t sz);
|
extern int logrotate(char *file, int num, off_t sz);
|
||||||
|
|
||||||
@@ -87,23 +90,61 @@ reopen:
|
|||||||
return fclose(fp);
|
return fclose(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int logit(int level, char *buf, size_t len)
|
/*
|
||||||
|
* Parse possible systemd style log <level> prefix from message
|
||||||
|
* For details, see libsystemd/sd-daemon.h
|
||||||
|
*
|
||||||
|
* Returns the level, and updates buf to point past the prefix
|
||||||
|
*/
|
||||||
|
static int parse_level(char **buf, int default_level)
|
||||||
{
|
{
|
||||||
if (buf[0]) {
|
char *msg = *buf;
|
||||||
syslog(level, "%s", buf);
|
|
||||||
return 0;
|
if (msg[0] == '<' && msg[2] == '>' && msg[1] >= '0' && msg[1] <= '7') {
|
||||||
|
int level;
|
||||||
|
|
||||||
|
switch (msg[1]) {
|
||||||
|
case '0': level = LOG_EMERG; break;
|
||||||
|
case '1': level = LOG_ALERT; break;
|
||||||
|
case '2': level = LOG_CRIT; break;
|
||||||
|
case '3': level = LOG_ERR; break;
|
||||||
|
case '4': level = LOG_WARNING; break;
|
||||||
|
case '5': level = LOG_NOTICE; break;
|
||||||
|
case '6': level = LOG_INFO; break;
|
||||||
|
case '7': level = LOG_DEBUG; break;
|
||||||
|
default: level = default_level; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
*buf = msg + 3;
|
||||||
|
return (default_level & ~LOG_PRIMASK) | level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return default_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_log(int level, char *msg)
|
||||||
|
{
|
||||||
|
syslog(parse_level(&msg, level), "%s", msg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int logit(int level, char *buf, size_t len)
|
||||||
|
{
|
||||||
|
if (buf[0])
|
||||||
|
return do_log(level, buf);
|
||||||
|
|
||||||
while ((fgets(buf, len, stdin)))
|
while ((fgets(buf, len, stdin)))
|
||||||
syslog(level, "%s", buf);
|
do_log(level, buf);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_prio(char *arg, int *f, int *l)
|
static int parse_prio(char *arg, int *fac, int *lvl)
|
||||||
{
|
{
|
||||||
char *duparg = strdup(arg);
|
char *duparg = strdup(arg);
|
||||||
char *ptr, *prio;
|
const char *prio;
|
||||||
|
char *ptr;
|
||||||
|
int found;
|
||||||
|
|
||||||
if (!duparg)
|
if (!duparg)
|
||||||
prio = arg;
|
prio = arg;
|
||||||
@@ -114,23 +155,34 @@ static int parse_prio(char *arg, int *f, int *l)
|
|||||||
if (ptr) {
|
if (ptr) {
|
||||||
*ptr++ = 0;
|
*ptr++ = 0;
|
||||||
|
|
||||||
|
found = -1;
|
||||||
for (int i = 0; facilitynames[i].c_name; i++) {
|
for (int i = 0; facilitynames[i].c_name; i++) {
|
||||||
if (!strcmp(facilitynames[i].c_name, prio)) {
|
if (!strcmp(facilitynames[i].c_name, prio)) {
|
||||||
*f = facilitynames[i].c_val;
|
found = facilitynames[i].c_val;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (found == -1)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
*fac = found;
|
||||||
prio = ptr;
|
prio = ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
found = -1;
|
||||||
for (int i = 0; prioritynames[i].c_name; i++) {
|
for (int i = 0; prioritynames[i].c_name; i++) {
|
||||||
|
|
||||||
if (!strcmp(prioritynames[i].c_name, prio)) {
|
if (!strcmp(prioritynames[i].c_name, prio)) {
|
||||||
*l = prioritynames[i].c_val;
|
found = prioritynames[i].c_val;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (found == -1)
|
||||||
|
return 1;
|
||||||
|
*lvl = found;
|
||||||
|
|
||||||
if (duparg != arg)
|
if (duparg != arg)
|
||||||
free(duparg);
|
free(duparg);
|
||||||
|
|
||||||
@@ -161,13 +213,14 @@ static int usage(int code)
|
|||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int c, rc, num = 5;
|
char *ident = NULL, *logfile = NULL;
|
||||||
|
int log_opts = LOG_NOWAIT;
|
||||||
int facility = LOG_USER;
|
int facility = LOG_USER;
|
||||||
int level = LOG_INFO;
|
int level = LOG_INFO;
|
||||||
int log_opts = LOG_NOWAIT;
|
off_t size = LOG_MAX;
|
||||||
off_t size = 200 * 1024;
|
|
||||||
char *ident = NULL, *logfile = NULL;
|
|
||||||
char buf[512] = "";
|
char buf[512] = "";
|
||||||
|
int num = LOG_NUM;
|
||||||
|
int c, rc;
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, "f:hn:p:r:st:v")) != EOF) {
|
while ((c = getopt(argc, argv, "f:hn:p:r:st:v")) != EOF) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|||||||
+4
-3
@@ -31,6 +31,7 @@
|
|||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SysV init on Debian/Ubuntu skips these protected mount points
|
* SysV init on Debian/Ubuntu skips these protected mount points
|
||||||
@@ -40,7 +41,7 @@
|
|||||||
* and regular filesystems that can be safely unmounted before we do
|
* and regular filesystems that can be safely unmounted before we do
|
||||||
* swapoff, and remount / as read-only, respectively.
|
* swapoff, and remount / as read-only, respectively.
|
||||||
*/
|
*/
|
||||||
static int is_protected(char *dir)
|
static int is_protected(const char *dir)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
char *protected_mnts[] = {
|
char *protected_mnts[] = {
|
||||||
@@ -111,7 +112,7 @@ static int unmount(const char *target)
|
|||||||
|
|
||||||
void unmount_tmpfs(void)
|
void unmount_tmpfs(void)
|
||||||
{
|
{
|
||||||
struct mntent *mnt;
|
const struct mntent *mnt;
|
||||||
FILE *fp = NULL;
|
FILE *fp = NULL;
|
||||||
|
|
||||||
while ((mnt = iterator("/proc/mounts", &fp))) {
|
while ((mnt = iterator("/proc/mounts", &fp))) {
|
||||||
@@ -122,7 +123,7 @@ void unmount_tmpfs(void)
|
|||||||
|
|
||||||
void unmount_regular(void)
|
void unmount_regular(void)
|
||||||
{
|
{
|
||||||
struct mntent *mnt;
|
const struct mntent *mnt;
|
||||||
FILE *fp = NULL;
|
FILE *fp = NULL;
|
||||||
|
|
||||||
while ((mnt = iterator("/proc/mounts", &fp))) {
|
while ((mnt = iterator("/proc/mounts", &fp))) {
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ int pid_file_set(svc_t *svc, char *file, int not)
|
|||||||
* pid:foo.tla --> /run/foo.tla.pid
|
* pid:foo.tla --> /run/foo.tla.pid
|
||||||
* pid:/tmp/foo --> /tmp/foo.pid (Not handled by pidfile plugin!)
|
* pid:/tmp/foo --> /tmp/foo.pid (Not handled by pidfile plugin!)
|
||||||
*
|
*
|
||||||
* An exclamation mark, or logial NOT, in the first character position
|
* An exclamation mark, or logical NOT, in the first character position
|
||||||
* indicates that Finit should *not* manage the PID file, and that the
|
* indicates that Finit should *not* manage the PID file, and that the
|
||||||
* process uses a "non-standard" location. Eg. if service is 'bar'
|
* process uses a "non-standard" location. Eg. if service is 'bar'
|
||||||
* Finit would assume the PID file is /run/bar.pid and the below simply
|
* Finit would assume the PID file is /run/bar.pid and the below simply
|
||||||
|
|||||||
@@ -320,6 +320,8 @@ static int init_plugins(uev_ctx_t *ctx)
|
|||||||
plugin_t *p, *tmp;
|
plugin_t *p, *tmp;
|
||||||
int fail = 0;
|
int fail = 0;
|
||||||
|
|
||||||
|
(void)ctx;
|
||||||
|
|
||||||
PLUGIN_ITERATOR(p, tmp) {
|
PLUGIN_ITERATOR(p, tmp) {
|
||||||
if (plugin_io_init(p))
|
if (plugin_io_init(p))
|
||||||
fail++;
|
fail++;
|
||||||
|
|||||||
+2
-1
@@ -41,12 +41,13 @@ extern int service_interval;
|
|||||||
extern char *fsck_mode;
|
extern char *fsck_mode;
|
||||||
extern char *fsck_repair;
|
extern char *fsck_repair;
|
||||||
|
|
||||||
|
extern uev_ctx_t *ctx;
|
||||||
|
|
||||||
int api_init (uev_ctx_t *ctx);
|
int api_init (uev_ctx_t *ctx);
|
||||||
int api_exit (void);
|
int api_exit (void);
|
||||||
void conf_flush_events(void);
|
void conf_flush_events(void);
|
||||||
|
|
||||||
void service_monitor (pid_t lost, int status);
|
void service_monitor (pid_t lost, int status);
|
||||||
void service_notify_cb(uev_t *w, void *arg, int events);
|
|
||||||
|
|
||||||
const char *plugin_hook_str (hook_point_t no);
|
const char *plugin_hook_str (hook_point_t no);
|
||||||
int plugin_exists (hook_point_t no);
|
int plugin_exists (hook_point_t no);
|
||||||
|
|||||||
+1
-1
@@ -193,7 +193,7 @@ int run_parts(char *dir, char *cmd, const char *env[], int progress, int sysv)
|
|||||||
#ifndef __FINIT__
|
#ifndef __FINIT__
|
||||||
static int usage(int rc)
|
static int usage(int rc)
|
||||||
{
|
{
|
||||||
warnx("usage: runparts [-dhps?] DIRECTORY");
|
warnx("usage: runparts [-bdhps?] DIRECTORY");
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -22,7 +22,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "finit.h"
|
#include "private.h"
|
||||||
|
#include "log.h"
|
||||||
#include "schedule.h"
|
#include "schedule.h"
|
||||||
|
|
||||||
#define SC_INIT 0x494E4954 /* "INIT", see ascii(7) */
|
#define SC_INIT 0x494E4954 /* "INIT", see ascii(7) */
|
||||||
@@ -35,6 +36,7 @@ static void cb(uev_t *w, void *arg, int events)
|
|||||||
struct wq *work = (struct wq *)arg;
|
struct wq *work = (struct wq *)arg;
|
||||||
|
|
||||||
if (UEV_ERROR == events) {
|
if (UEV_ERROR == events) {
|
||||||
|
dbg("%s(): spurious problem with schedule work timer, restarting.", __func__);
|
||||||
uev_timer_start(w);
|
uev_timer_start(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
+444
-229
File diff suppressed because it is too large
Load Diff
@@ -27,12 +27,10 @@
|
|||||||
|
|
||||||
#include "svc.h"
|
#include "svc.h"
|
||||||
|
|
||||||
void service_runlevel (int newlevel);
|
|
||||||
int service_register (int type, char *line, struct rlimit rlimit[], char *file);
|
int service_register (int type, char *line, struct rlimit rlimit[], char *file);
|
||||||
void service_unregister (svc_t *svc);
|
void service_unregister (svc_t *svc);
|
||||||
|
|
||||||
void service_runtask_clean (void);
|
void service_runtask_clean (void);
|
||||||
void service_reload_dynamic (void);
|
|
||||||
void service_update_rdeps (void);
|
void service_update_rdeps (void);
|
||||||
void service_mark_unavail (void);
|
void service_mark_unavail (void);
|
||||||
|
|
||||||
|
|||||||
@@ -94,6 +94,7 @@
|
|||||||
#include "private.h"
|
#include "private.h"
|
||||||
#include "sig.h"
|
#include "sig.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
|
#include "sm.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "utmp-api.h"
|
#include "utmp-api.h"
|
||||||
|
|
||||||
@@ -232,6 +233,8 @@ void do_iterate_proc(int (*cb)(int, void *), void *data)
|
|||||||
dbg("Skipping %s ...", file);
|
dbg("Skipping %s ...", file);
|
||||||
else if (file[0] == '@')
|
else if (file[0] == '@')
|
||||||
dbg("Skipping %s ...", &file[1]);
|
dbg("Skipping %s ...", &file[1]);
|
||||||
|
else if (strstr(file, "initctl"))
|
||||||
|
dbg("Skipping %s ...", file);
|
||||||
else
|
else
|
||||||
if (cb(pid, data)) {
|
if (cb(pid, data)) {
|
||||||
dbg("PID %d is still alive (%s)", pid, file);
|
dbg("PID %d is still alive (%s)", pid, file);
|
||||||
@@ -258,6 +261,7 @@ static int status_cb(int pid, void *data)
|
|||||||
{
|
{
|
||||||
int *has_proc = (int *)data;
|
int *has_proc = (int *)data;
|
||||||
|
|
||||||
|
(void)pid;
|
||||||
*has_proc = 1;
|
*has_proc = 1;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -423,6 +427,8 @@ void do_shutdown(shutop_t op)
|
|||||||
*/
|
*/
|
||||||
static void sighup_cb(uev_t *w, void *arg, int events)
|
static void sighup_cb(uev_t *w, void *arg, int events)
|
||||||
{
|
{
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
dbg("...");
|
dbg("...");
|
||||||
if (UEV_ERROR == events) {
|
if (UEV_ERROR == events) {
|
||||||
errx(1, "Unrecoverable error in signal watcher");
|
errx(1, "Unrecoverable error in signal watcher");
|
||||||
@@ -439,7 +445,7 @@ static void sighup_cb(uev_t *w, void *arg, int events)
|
|||||||
api_init(w->ctx);
|
api_init(w->ctx);
|
||||||
|
|
||||||
/* INIT_CMD_RELOAD: 'init q', 'initctl reload', and SIGHUP */
|
/* INIT_CMD_RELOAD: 'init q', 'initctl reload', and SIGHUP */
|
||||||
service_reload_dynamic();
|
sm_reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -449,6 +455,9 @@ static void sighup_cb(uev_t *w, void *arg, int events)
|
|||||||
*/
|
*/
|
||||||
static void sigint_cb(uev_t *w, void *arg, int events)
|
static void sigint_cb(uev_t *w, void *arg, int events)
|
||||||
{
|
{
|
||||||
|
(void)w;
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
dbg("...");
|
dbg("...");
|
||||||
if (UEV_ERROR == events) {
|
if (UEV_ERROR == events) {
|
||||||
errx(1, "Unrecoverable error in signal watcher");
|
errx(1, "Unrecoverable error in signal watcher");
|
||||||
@@ -465,6 +474,9 @@ static void sigint_cb(uev_t *w, void *arg, int events)
|
|||||||
*/
|
*/
|
||||||
static void sigpwr_cb(uev_t *w, void *arg, int events)
|
static void sigpwr_cb(uev_t *w, void *arg, int events)
|
||||||
{
|
{
|
||||||
|
(void)w;
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
dbg("...");
|
dbg("...");
|
||||||
if (UEV_ERROR == events) {
|
if (UEV_ERROR == events) {
|
||||||
errx(1, "Unrecoverable error in signal watcher");
|
errx(1, "Unrecoverable error in signal watcher");
|
||||||
@@ -479,6 +491,8 @@ static void sigpwr_cb(uev_t *w, void *arg, int events)
|
|||||||
*/
|
*/
|
||||||
static void sigusr1_cb(uev_t *w, void *arg, int events)
|
static void sigusr1_cb(uev_t *w, void *arg, int events)
|
||||||
{
|
{
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
dbg("...");
|
dbg("...");
|
||||||
if (UEV_ERROR == events) {
|
if (UEV_ERROR == events) {
|
||||||
errx(1, "Unrecoverable error in signal watcher");
|
errx(1, "Unrecoverable error in signal watcher");
|
||||||
@@ -500,6 +514,9 @@ static void sigusr1_cb(uev_t *w, void *arg, int events)
|
|||||||
*/
|
*/
|
||||||
static void sigusr2_cb(uev_t *w, void *arg, int events)
|
static void sigusr2_cb(uev_t *w, void *arg, int events)
|
||||||
{
|
{
|
||||||
|
(void)w;
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
dbg("...");
|
dbg("...");
|
||||||
if (UEV_ERROR == events) {
|
if (UEV_ERROR == events) {
|
||||||
errx(1, "Unrecoverable error in signal watcher");
|
errx(1, "Unrecoverable error in signal watcher");
|
||||||
@@ -512,7 +529,7 @@ static void sigusr2_cb(uev_t *w, void *arg, int events)
|
|||||||
}
|
}
|
||||||
|
|
||||||
halt = SHUT_OFF;
|
halt = SHUT_OFF;
|
||||||
service_runlevel(0);
|
sm_runlevel(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -520,6 +537,9 @@ static void sigusr2_cb(uev_t *w, void *arg, int events)
|
|||||||
*/
|
*/
|
||||||
static void sigterm_cb(uev_t *w, void *arg, int events)
|
static void sigterm_cb(uev_t *w, void *arg, int events)
|
||||||
{
|
{
|
||||||
|
(void)w;
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
dbg("...");
|
dbg("...");
|
||||||
if (UEV_ERROR == events) {
|
if (UEV_ERROR == events) {
|
||||||
errx(1, "Unrecoverable error in signal watcher");
|
errx(1, "Unrecoverable error in signal watcher");
|
||||||
@@ -532,7 +552,7 @@ static void sigterm_cb(uev_t *w, void *arg, int events)
|
|||||||
}
|
}
|
||||||
|
|
||||||
halt = SHUT_REBOOT;
|
halt = SHUT_REBOOT;
|
||||||
service_runlevel(6);
|
sm_runlevel(6);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -543,6 +563,9 @@ static void sigchld_cb(uev_t *w, void *arg, int events)
|
|||||||
int status;
|
int status;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
|
(void)w;
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
if (UEV_ERROR == events) {
|
if (UEV_ERROR == events) {
|
||||||
errx(1, "Unrecoverable error in signal watcher");
|
errx(1, "Unrecoverable error in signal watcher");
|
||||||
return;
|
return;
|
||||||
@@ -599,6 +622,9 @@ const char *sig_name(int signo)
|
|||||||
*/
|
*/
|
||||||
static void chld_handler(int sig, siginfo_t *info, void *ctx)
|
static void chld_handler(int sig, siginfo_t *info, void *ctx)
|
||||||
{
|
{
|
||||||
|
(void)sig;
|
||||||
|
(void)info;
|
||||||
|
(void)ctx;
|
||||||
/* NOP */
|
/* NOP */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
#include "log.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "private.h"
|
#include "private.h"
|
||||||
#include "schedule.h"
|
#include "schedule.h"
|
||||||
@@ -38,11 +39,25 @@
|
|||||||
#include "sm.h"
|
#include "sm.h"
|
||||||
#include "utmp-api.h"
|
#include "utmp-api.h"
|
||||||
|
|
||||||
sm_t sm;
|
typedef enum {
|
||||||
|
SM_BOOTSTRAP_STATE = 0, /* Init state, bootstrap services */
|
||||||
|
SM_BOOTSTRAP_WAIT_STATE, /* Waiting for bootstrap to complete */
|
||||||
|
SM_RUNNING_STATE, /* Normal state, services running */
|
||||||
|
SM_RUNLEVEL_CHANGE_STATE, /* A runlevel change has occurred */
|
||||||
|
SM_RUNLEVEL_WAIT_STATE, /* Waiting for all stopped processes to halt */
|
||||||
|
SM_RUNLEVEL_CLEAN_STATE, /* Wait for post:scripts and cleanup:scripts */
|
||||||
|
SM_RELOAD_CHANGE_STATE, /* A reload event has occurred */
|
||||||
|
SM_RELOAD_WAIT_STATE, /* Waiting for all stopped processes to halt */
|
||||||
|
SM_RELOAD_CLEAN_STATE, /* Wait for post:scripts and cleanup:scripts */
|
||||||
|
} sm_state_t;
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
sm_state_t state; /* Running, Changed, Waiting, ... */
|
||||||
|
int newlevel; /* Set to new runlevel on change, -1 otherwise */
|
||||||
|
int reload; /* Set on reload event, else 0 */
|
||||||
|
int in_reload; /* Set when waiting for all processes to be halted */
|
||||||
|
} sm;
|
||||||
|
|
||||||
#ifndef FINIT_NOLOGIN_PATH
|
|
||||||
#define FINIT_NOLOGIN_PATH _PATH_NOLOGIN /* Stop user logging in. */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wait for system bootstrap to complete, all SVC_TYPE_RUNTASK must be
|
* Wait for system bootstrap to complete, all SVC_TYPE_RUNTASK must be
|
||||||
@@ -90,7 +105,7 @@ static void sm_check_bootstrap(void *work)
|
|||||||
} else
|
} else
|
||||||
dbg("Change to default runlevel(%d), starting all services ...", cfglevel);
|
dbg("Change to default runlevel(%d), starting all services ...", cfglevel);
|
||||||
|
|
||||||
service_runlevel(level);
|
sm_runlevel(level);
|
||||||
|
|
||||||
/* Clean up bootstrap-only tasks/services that never started */
|
/* Clean up bootstrap-only tasks/services that never started */
|
||||||
dbg("Clean up all bootstrap-only tasks/services ...");
|
dbg("Clean up all bootstrap-only tasks/services ...");
|
||||||
@@ -107,6 +122,9 @@ static char *sm_status(sm_state_t state)
|
|||||||
case SM_BOOTSTRAP_STATE:
|
case SM_BOOTSTRAP_STATE:
|
||||||
return "bootstrap";
|
return "bootstrap";
|
||||||
|
|
||||||
|
case SM_BOOTSTRAP_WAIT_STATE:
|
||||||
|
return "bootstrap/wait";
|
||||||
|
|
||||||
case SM_RUNNING_STATE:
|
case SM_RUNNING_STATE:
|
||||||
return "running";
|
return "running";
|
||||||
|
|
||||||
@@ -116,18 +134,23 @@ static char *sm_status(sm_state_t state)
|
|||||||
case SM_RUNLEVEL_WAIT_STATE:
|
case SM_RUNLEVEL_WAIT_STATE:
|
||||||
return "runlevel/wait";
|
return "runlevel/wait";
|
||||||
|
|
||||||
|
case SM_RUNLEVEL_CLEAN_STATE:
|
||||||
|
return "runlevel/clean";
|
||||||
|
|
||||||
case SM_RELOAD_CHANGE_STATE:
|
case SM_RELOAD_CHANGE_STATE:
|
||||||
return "reload/change";
|
return "reload/change";
|
||||||
|
|
||||||
case SM_RELOAD_WAIT_STATE:
|
case SM_RELOAD_WAIT_STATE:
|
||||||
return "reload/wait";
|
return "reload/wait";
|
||||||
|
|
||||||
default:
|
case SM_RELOAD_CLEAN_STATE:
|
||||||
return "unknown";
|
return "reload/clean";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
static char sm_runlevel(int lvl)
|
static char sm_rl2ch(int lvl)
|
||||||
{
|
{
|
||||||
if (lvl == INIT_LEVEL)
|
if (lvl == INIT_LEVEL)
|
||||||
return 'S';
|
return 'S';
|
||||||
@@ -150,60 +173,39 @@ static void nologin(void)
|
|||||||
erase(FINIT_NOLOGIN_PATH);
|
erase(FINIT_NOLOGIN_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sm_init(sm_t *sm)
|
void sm_init(void)
|
||||||
{
|
{
|
||||||
static struct wq work = {
|
static struct wq work = {
|
||||||
.cb = sm_check_bootstrap,
|
.cb = sm_check_bootstrap,
|
||||||
.delay = 1000
|
.delay = 1000
|
||||||
};
|
};
|
||||||
|
|
||||||
sm->state = SM_BOOTSTRAP_STATE;
|
sm.state = SM_BOOTSTRAP_STATE;
|
||||||
sm->newlevel = -1;
|
sm.newlevel = -1;
|
||||||
sm->reload = 0;
|
sm.reload = 0;
|
||||||
sm->in_teardown = 0;
|
sm.in_reload = 0;
|
||||||
|
|
||||||
dbg("Starting bootstrap finalize timer ...");
|
dbg("Starting bootstrap finalize timer ...");
|
||||||
schedule_work(&work);
|
schedule_work(&work);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sm_set_runlevel(sm_t *sm, int newlevel)
|
void sm_step(void)
|
||||||
{
|
|
||||||
sm->newlevel = newlevel;
|
|
||||||
|
|
||||||
dbg("Flushing pending .conf file events ...");
|
|
||||||
conf_flush_events();
|
|
||||||
}
|
|
||||||
|
|
||||||
void sm_set_reload(sm_t *sm)
|
|
||||||
{
|
|
||||||
sm->reload = 1;
|
|
||||||
|
|
||||||
dbg("Flushing pending .conf file events ...");
|
|
||||||
conf_flush_events();
|
|
||||||
}
|
|
||||||
|
|
||||||
int sm_is_in_teardown(sm_t *sm)
|
|
||||||
{
|
|
||||||
return sm->in_teardown;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sm_step(sm_t *sm)
|
|
||||||
{
|
{
|
||||||
sm_state_t old_state;
|
sm_state_t old_state;
|
||||||
svc_t *svc;
|
svc_t *svc;
|
||||||
|
|
||||||
restart:
|
restart:
|
||||||
old_state = sm->state;
|
old_state = sm.state;
|
||||||
|
|
||||||
dbg("state: %s, runlevel: %c, newlevel: %d, teardown: %d, reload: %d",
|
dbg("state: %s, runlevel: %c, newlevel: %d, teardown: %d, reload: %d",
|
||||||
sm_status(sm->state), sm_runlevel(runlevel), sm->newlevel, sm->in_teardown, sm->reload);
|
sm_status(sm.state), sm_rl2ch(runlevel), sm.newlevel, sm.in_reload, sm.reload);
|
||||||
|
|
||||||
switch (sm->state) {
|
switch (sm.state) {
|
||||||
case SM_BOOTSTRAP_STATE:
|
case SM_BOOTSTRAP_STATE:
|
||||||
dbg("Bootstrapping all services in runlevel S from %s", finit_conf);
|
dbg("Bootstrapping all services in runlevel S from %s", finit_conf);
|
||||||
service_step_all(SVC_TYPE_RUNTASK | SVC_TYPE_SERVICE);
|
service_step_all(SVC_TYPE_RUNTASK | SVC_TYPE_SERVICE | SVC_TYPE_SYSV);
|
||||||
|
|
||||||
sm->state = SM_BOOTSTRAP_WAIT_STATE;
|
sm.state = SM_BOOTSTRAP_WAIT_STATE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -224,7 +226,7 @@ restart:
|
|||||||
/* Allow runparts to start */
|
/* Allow runparts to start */
|
||||||
cond_set_oneshot("int/bootstrap");
|
cond_set_oneshot("int/bootstrap");
|
||||||
|
|
||||||
if (sm->newlevel == -1)
|
if (sm.newlevel == -1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Hooks that should run at the very end */
|
/* Hooks that should run at the very end */
|
||||||
@@ -235,10 +237,10 @@ restart:
|
|||||||
/* Disable progress output at normal runtime */
|
/* Disable progress output at normal runtime */
|
||||||
enable_progress(0);
|
enable_progress(0);
|
||||||
|
|
||||||
/* System bootrapped, launch TTYs et al */
|
/* System bootstrapped, launch TTYs et al */
|
||||||
bootstrap = 0;
|
bootstrap = 0;
|
||||||
service_step_all(SVC_TYPE_RESPAWN);
|
service_step_all(SVC_TYPE_RESPAWN);
|
||||||
sm->state = SM_RUNNING_STATE;
|
sm.state = SM_RUNNING_STATE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SM_RUNNING_STATE:
|
case SM_RUNNING_STATE:
|
||||||
@@ -246,26 +248,26 @@ restart:
|
|||||||
service_step_all(SVC_TYPE_ANY);
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
|
||||||
/* runlevel changed? */
|
/* runlevel changed? */
|
||||||
if (sm->newlevel >= 0 && sm->newlevel <= 9) {
|
if (sm.newlevel >= 0 && sm.newlevel <= 9) {
|
||||||
if (runlevel == sm->newlevel) {
|
if (runlevel == sm.newlevel) {
|
||||||
sm->newlevel = -1;
|
sm.newlevel = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
sm->state = SM_RUNLEVEL_CHANGE_STATE;
|
sm.state = SM_RUNLEVEL_CHANGE_STATE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* reload ? */
|
/* reload ? */
|
||||||
if (sm->reload) {
|
if (sm.reload) {
|
||||||
sm->reload = 0;
|
sm.reload = 0;
|
||||||
sm->state = SM_RELOAD_CHANGE_STATE;
|
sm.state = SM_RELOAD_CHANGE_STATE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SM_RUNLEVEL_CHANGE_STATE:
|
case SM_RUNLEVEL_CHANGE_STATE:
|
||||||
prevlevel = runlevel;
|
prevlevel = runlevel;
|
||||||
runlevel = sm->newlevel;
|
runlevel = sm.newlevel;
|
||||||
sm->newlevel = -1;
|
sm.newlevel = -1;
|
||||||
|
|
||||||
/* Restore terse mode and run hooks before shutdown */
|
/* Restore terse mode and run hooks before shutdown */
|
||||||
if (runlevel == 0 || runlevel == 6) {
|
if (runlevel == 0 || runlevel == 6) {
|
||||||
@@ -274,11 +276,11 @@ restart:
|
|||||||
plugin_run_hooks(HOOK_SHUTDOWN);
|
plugin_run_hooks(HOOK_SHUTDOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
dbg("Setting new runlevel --> %c <-- previous %c", sm_runlevel(runlevel), sm_runlevel(prevlevel));
|
dbg("Setting new runlevel --> %c <-- previous %c", sm_rl2ch(runlevel), sm_rl2ch(prevlevel));
|
||||||
if (osheading)
|
if (osheading)
|
||||||
logit(LOG_CONSOLE | LOG_NOTICE, "%s, entering runlevel %c", osheading, sm_runlevel(runlevel));
|
logit(LOG_CONSOLE | LOG_NOTICE, "%s, entering runlevel %c", osheading, sm_rl2ch(runlevel));
|
||||||
else
|
else
|
||||||
logit(LOG_CONSOLE | LOG_NOTICE, "Entering runlevel %c", sm_runlevel(runlevel));
|
logit(LOG_CONSOLE | LOG_NOTICE, "Entering runlevel %c", sm_rl2ch(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 */
|
||||||
@@ -294,10 +296,10 @@ restart:
|
|||||||
service_runtask_clean();
|
service_runtask_clean();
|
||||||
|
|
||||||
dbg("Stopping services not allowed in new runlevel ...");
|
dbg("Stopping services not allowed in new runlevel ...");
|
||||||
sm->in_teardown = 1;
|
sm.in_reload = 1;
|
||||||
service_step_all(SVC_TYPE_ANY);
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
|
||||||
sm->state = SM_RUNLEVEL_WAIT_STATE;
|
sm.state = SM_RUNLEVEL_WAIT_STATE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SM_RUNLEVEL_WAIT_STATE:
|
case SM_RUNLEVEL_WAIT_STATE:
|
||||||
@@ -316,9 +318,25 @@ restart:
|
|||||||
plugin_run_hooks(HOOK_RUNLEVEL_CHANGE); /* Reconfigure HW/VLANs/etc here */
|
plugin_run_hooks(HOOK_RUNLEVEL_CHANGE); /* Reconfigure HW/VLANs/etc here */
|
||||||
|
|
||||||
dbg("Starting services new to this runlevel ...");
|
dbg("Starting services new to this runlevel ...");
|
||||||
sm->in_teardown = 0;
|
sm.in_reload = 0;
|
||||||
service_step_all(SVC_TYPE_ANY);
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
|
||||||
|
sm.state = SM_RUNLEVEL_CLEAN_STATE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SM_RUNLEVEL_CLEAN_STATE:
|
||||||
|
/*
|
||||||
|
* Wait for post:script or cleanup:script to be collected,
|
||||||
|
* which moves the svc to HALTED or DEAD state. We will
|
||||||
|
* be called by the service_monitor() on collect.
|
||||||
|
*/
|
||||||
|
svc = svc_clean_completed();
|
||||||
|
if (svc) {
|
||||||
|
dbg("Waiting to collect post/cleanup script for %s, cmd %s(%d) ...",
|
||||||
|
svc_ident(svc, NULL, 0), svc->cmd, svc->pid);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Cleanup stale services */
|
/* Cleanup stale services */
|
||||||
svc_clean_dynamic(service_unregister);
|
svc_clean_dynamic(service_unregister);
|
||||||
|
|
||||||
@@ -337,7 +355,7 @@ restart:
|
|||||||
if (runlevel == 0 || runlevel == 6)
|
if (runlevel == 0 || runlevel == 6)
|
||||||
do_shutdown(halt);
|
do_shutdown(halt);
|
||||||
|
|
||||||
sm->state = SM_RUNNING_STATE;
|
sm.state = SM_RUNNING_STATE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SM_RELOAD_CHANGE_STATE:
|
case SM_RELOAD_CHANGE_STATE:
|
||||||
@@ -349,11 +367,11 @@ restart:
|
|||||||
* let all affected services move to WAITING/HALTED
|
* let all affected services move to WAITING/HALTED
|
||||||
*/
|
*/
|
||||||
dbg("Stopping services not allowed after reconf ...");
|
dbg("Stopping services not allowed after reconf ...");
|
||||||
sm->in_teardown = 1;
|
sm.in_reload = 1;
|
||||||
cond_reload();
|
cond_reload();
|
||||||
service_step_all(SVC_TYPE_ANY);
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
|
||||||
sm->state = SM_RELOAD_WAIT_STATE;
|
sm.state = SM_RELOAD_WAIT_STATE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SM_RELOAD_WAIT_STATE:
|
case SM_RELOAD_WAIT_STATE:
|
||||||
@@ -367,11 +385,27 @@ restart:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
sm->in_teardown = 0;
|
sm.in_reload = 0;
|
||||||
|
|
||||||
dbg("Starting services after reconf ...");
|
dbg("Starting services after reconf ...");
|
||||||
service_step_all(SVC_TYPE_ANY);
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
|
||||||
|
sm.state = SM_RELOAD_CLEAN_STATE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SM_RELOAD_CLEAN_STATE:
|
||||||
|
/*
|
||||||
|
* Wait for post:script or cleanup:script to be collected,
|
||||||
|
* which moves the svc to HALTED or DEAD state. We will
|
||||||
|
* be called by the service_monitor() on collect.
|
||||||
|
*/
|
||||||
|
svc = svc_clean_completed();
|
||||||
|
if (svc) {
|
||||||
|
dbg("Waiting to collect post/cleanup script for %s, cmd %s(%d) ...",
|
||||||
|
svc_ident(svc, NULL, 0), svc->cmd, svc->pid);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Cleanup stale services */
|
/* Cleanup stale services */
|
||||||
svc_clean_dynamic(service_unregister);
|
svc_clean_dynamic(service_unregister);
|
||||||
|
|
||||||
@@ -382,14 +416,66 @@ restart:
|
|||||||
service_notify_reconf();
|
service_notify_reconf();
|
||||||
|
|
||||||
dbg("Reconfiguration done");
|
dbg("Reconfiguration done");
|
||||||
sm->state = SM_RUNNING_STATE;
|
sm.state = SM_RUNNING_STATE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sm->state != old_state)
|
if (sm.state != old_state)
|
||||||
goto restart;
|
goto restart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sm_in_reload - System currently in reload or runlevel change?
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* %TRUE(1) or %FALSE(0)
|
||||||
|
*/
|
||||||
|
int sm_in_reload(void)
|
||||||
|
{
|
||||||
|
return sm.in_reload;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sm_reload - Called on SIGHUP, 'init q' or 'initctl reload'
|
||||||
|
*
|
||||||
|
* This function is called when Finit has received SIGHUP to reload
|
||||||
|
* .conf files in /etc/finit.d. It is responsible for starting,
|
||||||
|
* stopping and reloading (forwarding SIGHUP) to processes affected.
|
||||||
|
*/
|
||||||
|
void sm_reload(void)
|
||||||
|
{
|
||||||
|
sm.reload = 1;
|
||||||
|
|
||||||
|
dbg("Flushing pending .conf file events ...");
|
||||||
|
conf_flush_events();
|
||||||
|
|
||||||
|
sm_step();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sm_runlevel - Change to a new runlevel
|
||||||
|
* @newlevel: New runlevel to activate
|
||||||
|
*
|
||||||
|
* Stops all services not in @newlevel and starts, or lets continue to run,
|
||||||
|
* those in @newlevel. Also updates @prevlevel and active @runlevel.
|
||||||
|
*/
|
||||||
|
void sm_runlevel(int newlevel)
|
||||||
|
{
|
||||||
|
if (!rescue && (runlevel == 1 || runlevel == INIT_LEVEL) && !IS_RESERVED_RUNLEVEL(newlevel))
|
||||||
|
networking(1);
|
||||||
|
|
||||||
|
sm.newlevel = newlevel;
|
||||||
|
|
||||||
|
dbg("Flushing pending .conf file events ...");
|
||||||
|
conf_flush_events();
|
||||||
|
|
||||||
|
sm_step();
|
||||||
|
|
||||||
|
if (!rescue && IS_RESERVED_RUNLEVEL(runlevel))
|
||||||
|
networking(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
|
|||||||
@@ -24,30 +24,12 @@
|
|||||||
#ifndef FINIT_SM_H_
|
#ifndef FINIT_SM_H_
|
||||||
#define FINIT_SM_H_
|
#define FINIT_SM_H_
|
||||||
|
|
||||||
typedef enum {
|
void sm_init (void);
|
||||||
SM_BOOTSTRAP_STATE = 0, /* Init state, bootstrap services */
|
void sm_step (void);
|
||||||
SM_BOOTSTRAP_WAIT_STATE, /* Waiting for bootstrap to complete */
|
|
||||||
SM_RUNNING_STATE, /* Normal state, services running */
|
|
||||||
SM_RUNLEVEL_CHANGE_STATE, /* A runlevel change has occurred */
|
|
||||||
SM_RUNLEVEL_WAIT_STATE, /* Waiting for all stopped runlevel processes to be halted */
|
|
||||||
SM_RELOAD_CHANGE_STATE, /* A reload event has occurred */
|
|
||||||
SM_RELOAD_WAIT_STATE, /* Waiting for all stopped reload processes to be halted */
|
|
||||||
} sm_state_t;
|
|
||||||
|
|
||||||
typedef struct sm {
|
int sm_in_reload (void);
|
||||||
sm_state_t state; /* Running, Changed, Waiting, ... */
|
void sm_reload (void);
|
||||||
int newlevel; /* Set on runlevel change to new runlevel, -1 if not change */
|
void sm_runlevel (int newlevel);
|
||||||
int reload; /* Set on reload event, else 0 */
|
|
||||||
int in_teardown; /* Set when waiting for all processes to be halted */
|
|
||||||
} sm_t;
|
|
||||||
|
|
||||||
extern sm_t sm;
|
|
||||||
|
|
||||||
void sm_init(sm_t *sm);
|
|
||||||
void sm_step(sm_t *sm);
|
|
||||||
void sm_set_runlevel(sm_t *sm, int newlevel);
|
|
||||||
void sm_set_reload(sm_t *sm);
|
|
||||||
int sm_is_in_teardown(sm_t *sm);
|
|
||||||
|
|
||||||
#endif /* FINIT_SM_H_ */
|
#endif /* FINIT_SM_H_ */
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
|
#include "conf.h"
|
||||||
#include "svc.h"
|
#include "svc.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "pid.h"
|
#include "pid.h"
|
||||||
@@ -348,6 +349,43 @@ svc_t *svc_stop_completed(void)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* svc_clean_completed - Have post: and cleanup: scripts finished?
|
||||||
|
*
|
||||||
|
* Called late in runlevel and reload transitions to check if all post: and
|
||||||
|
* cleanup:scripts have completed. A removed service should end up in the
|
||||||
|
* DEAD state, while a service with a post:script ends up in HALTED.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* %NULL if post: and cleanup: scripts have run, otherwise a pointer to
|
||||||
|
* the first found svc_t waiting for post: or cleanup:script.
|
||||||
|
*/
|
||||||
|
svc_t *svc_clean_completed(void)
|
||||||
|
{
|
||||||
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
|
if (svc_enabled(svc))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (svc_is_runtask(svc) && svc->state == SVC_DONE_STATE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (svc_is_removed(svc)) {
|
||||||
|
if (svc->state == SVC_DEAD_STATE)
|
||||||
|
continue; /* any cleanup:script done */
|
||||||
|
} else {
|
||||||
|
if (svc->state == SVC_HALTED_STATE)
|
||||||
|
continue; /* any post:script done */
|
||||||
|
}
|
||||||
|
|
||||||
|
return svc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* svc_find - Find a service object by its full path name
|
* svc_find - Find a service object by its full path name
|
||||||
* @name: Full path name, e.g., /sbin/syslogd
|
* @name: Full path name, e.g., /sbin/syslogd
|
||||||
@@ -580,7 +618,7 @@ void svc_clean_dynamic(void (*cb)(svc_t *))
|
|||||||
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->removed && cb)
|
if (svc_is_removed(svc) && cb)
|
||||||
cb(svc);
|
cb(svc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,14 +52,17 @@ typedef enum {
|
|||||||
} svc_type_t;
|
} svc_type_t;
|
||||||
|
|
||||||
#define SVC_TYPE_ANY (-1)
|
#define SVC_TYPE_ANY (-1)
|
||||||
#define SVC_TYPE_RESPAWN (SVC_TYPE_SERVICE | SVC_TYPE_TTY)
|
#define SVC_TYPE_DAEMON (SVC_TYPE_SERVICE | SVC_TYPE_SYSV)
|
||||||
#define SVC_TYPE_RUNTASK (SVC_TYPE_RUN | SVC_TYPE_TASK | SVC_TYPE_SYSV)
|
#define SVC_TYPE_RESPAWN (SVC_TYPE_SERVICE | SVC_TYPE_SYSV | SVC_TYPE_TTY)
|
||||||
|
#define SVC_TYPE_RUNTASK (SVC_TYPE_RUN | SVC_TYPE_TASK)
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SVC_HALTED_STATE = 0, /* Not allowed in runlevel, or not enabled. */
|
SVC_HALTED_STATE = 0, /* Not allowed in runlevel, or not enabled. */
|
||||||
SVC_DONE_STATE, /* Task/Run job has been run */
|
SVC_DONE_STATE, /* Task/Run job has been run */
|
||||||
|
SVC_DEAD_STATE, /* Process is dead and scheduled for removal */
|
||||||
|
SVC_CLEANUP_STATE, /* Running cleanup: script */
|
||||||
|
SVC_TEARDOWN_STATE, /* Running post: script */
|
||||||
SVC_STOPPING_STATE, /* Waiting to collect the child process */
|
SVC_STOPPING_STATE, /* Waiting to collect the child process */
|
||||||
SVC_CLEANUP_STATE, /* Running post: script */
|
|
||||||
SVC_SETUP_STATE, /* Running pre: script */
|
SVC_SETUP_STATE, /* Running pre: script */
|
||||||
SVC_PAUSED_STATE, /* Condition is in flux, process SIGSTOPed */
|
SVC_PAUSED_STATE, /* Condition is in flux, process SIGSTOPed */
|
||||||
SVC_WAITING_STATE, /* Enabled but condition not satisfied */
|
SVC_WAITING_STATE, /* Enabled but condition not satisfied */
|
||||||
@@ -83,7 +86,7 @@ typedef enum {
|
|||||||
SVC_ONCRASH_SCRIPT,
|
SVC_ONCRASH_SCRIPT,
|
||||||
} svc_oncrash_action_t;
|
} svc_oncrash_action_t;
|
||||||
|
|
||||||
/* 0: none, 1: systemd, 2: s6 */
|
/* 0: none, 1: finit (native), 2: systemd, 3: s6 */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SVC_NOTIFY_NONE = 0,
|
SVC_NOTIFY_NONE = 0,
|
||||||
SVC_NOTIFY_PID,
|
SVC_NOTIFY_PID,
|
||||||
@@ -146,7 +149,7 @@ typedef struct svc {
|
|||||||
char cond[MAX_COND_LEN];
|
char cond[MAX_COND_LEN];
|
||||||
|
|
||||||
/* Instance specifics */
|
/* Instance specifics */
|
||||||
int job; /* For intenal use only, canonical ref is NAME:ID */
|
int job; /* For internal use only, canonical ref is NAME:ID */
|
||||||
char name[MAX_ARG_LEN];
|
char name[MAX_ARG_LEN];
|
||||||
char id[MAX_ID_LEN]; /* :ID */
|
char id[MAX_ID_LEN]; /* :ID */
|
||||||
char ifstmt[MAX_IDENT_LEN];
|
char ifstmt[MAX_IDENT_LEN];
|
||||||
@@ -196,13 +199,25 @@ typedef struct svc {
|
|||||||
char conflict[MAX_ARG_LEN];
|
char conflict[MAX_ARG_LEN];
|
||||||
char desc[MAX_STR_LEN];
|
char desc[MAX_STR_LEN];
|
||||||
char env[MAX_CMD_LEN];
|
char env[MAX_CMD_LEN];
|
||||||
|
|
||||||
char pre_script[MAX_CMD_LEN];
|
char pre_script[MAX_CMD_LEN];
|
||||||
int pre_tmo;
|
int pre_tmo;
|
||||||
|
|
||||||
char post_script[MAX_CMD_LEN];
|
char post_script[MAX_CMD_LEN];
|
||||||
int post_tmo;
|
int post_tmo;
|
||||||
|
|
||||||
char ready_script[MAX_CMD_LEN];
|
char ready_script[MAX_CMD_LEN];
|
||||||
int ready_tmo;
|
int ready_tmo;
|
||||||
|
|
||||||
|
char cleanup_script[MAX_CMD_LEN];
|
||||||
|
int cleanup_tmo;
|
||||||
|
|
||||||
|
/* When set, used instead of SIGHUP or stop-start */
|
||||||
|
char reload_script[MAX_CMD_LEN];
|
||||||
|
|
||||||
|
/* When set, used instead of SIGTERM or sysv 'stop' */
|
||||||
|
char stop_script[MAX_CMD_LEN];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Used to forcefully kill services that won't shutdown on
|
* Used to forcefully kill services that won't shutdown on
|
||||||
* termination and to delay restarts of crashing services.
|
* termination and to delay restarts of crashing services.
|
||||||
@@ -240,6 +255,7 @@ void svc_foreach (int (*cb)(svc_t *));
|
|||||||
void svc_foreach_type (int types, int (*cb)(svc_t *));
|
void svc_foreach_type (int types, int (*cb)(svc_t *));
|
||||||
|
|
||||||
svc_t *svc_stop_completed (void);
|
svc_t *svc_stop_completed (void);
|
||||||
|
svc_t *svc_clean_completed (void);
|
||||||
|
|
||||||
void svc_mark (svc_t *svc);
|
void svc_mark (svc_t *svc);
|
||||||
void svc_mark_dynamic (void);
|
void svc_mark_dynamic (void);
|
||||||
@@ -256,26 +272,27 @@ int svc_ifthen (int is_conf, const char *ident, char *stmt,
|
|||||||
|
|
||||||
int svc_parse_jobstr (char *str, size_t len, void *user_data, int (*found)(svc_t *, void *), int (not_found)(char *, char *, void *));
|
int svc_parse_jobstr (char *str, size_t len, void *user_data, int (*found)(svc_t *, void *), int (not_found)(char *, char *, void *));
|
||||||
|
|
||||||
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_DAEMON & svc->type); }
|
||||||
static inline int svc_is_sysv (svc_t *svc) { return svc && SVC_TYPE_SYSV == svc->type; }
|
static inline int svc_is_sysv (svc_t *svc) { return svc && SVC_TYPE_SYSV == svc->type; }
|
||||||
static inline int svc_is_tty (svc_t *svc) { return svc && SVC_TYPE_TTY == svc->type; }
|
static inline int svc_is_tty (svc_t *svc) { return svc && SVC_TYPE_TTY == 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 && svc->forking; }
|
static inline int svc_is_forking (svc_t *svc) { return svc && svc->forking; }
|
||||||
static inline int svc_is_manual (svc_t *svc) { return svc && svc->manual; }
|
static inline int svc_is_manual (svc_t *svc) { return svc && svc->manual; }
|
||||||
static inline int svc_is_nohup (svc_t *svc) { return svc && (0 == svc->sighup); }
|
static inline int svc_is_noreload (svc_t *svc) { return svc && (0 == svc->sighup && 0 == svc->reload_script[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_nohup (svc_t *svc) { return svc && (0 == svc->sighup || 0 != svc->args_dirty); }
|
|
||||||
static inline int svc_has_pidfile (svc_t *svc) { return svc_is_daemon(svc) && svc->pidfile[0] != 0 && svc->pidfile[0] != '!'; }
|
static inline int svc_has_pidfile (svc_t *svc) { return svc_is_daemon(svc) && svc->pidfile[0] != 0 && svc->pidfile[0] != '!'; }
|
||||||
static inline int svc_has_pre (svc_t *svc) { return svc->pre_script[0]; }
|
static inline int svc_has_pre (svc_t *svc) { return svc->pre_script[0]; }
|
||||||
static inline int svc_has_post (svc_t *svc) { return svc->post_script[0]; }
|
static inline int svc_has_post (svc_t *svc) { return svc->post_script[0]; }
|
||||||
static inline int svc_has_ready (svc_t *svc) { return svc->ready_script[0];}
|
static inline int svc_has_ready (svc_t *svc) { return svc->ready_script[0];}
|
||||||
|
static inline int svc_has_cleanup (svc_t *svc) { return svc->cleanup_script[0]; }
|
||||||
|
|
||||||
static inline void svc_starting (svc_t *svc) { if (svc) svc->starting = 1; }
|
static inline void svc_starting (svc_t *svc) { if (svc) svc->starting = 1; }
|
||||||
static inline void svc_started (svc_t *svc) { if (svc) svc->starting = 0; }
|
static inline void svc_started (svc_t *svc) { if (svc) svc->starting = 0; }
|
||||||
static inline int svc_is_starting (svc_t *svc) { return svc && 0 != svc->starting; }
|
static inline int svc_is_starting (svc_t *svc) { return svc && 0 != svc->starting; }
|
||||||
static inline int svc_is_running (svc_t *svc) { return svc && svc->state == SVC_RUNNING_STATE; }
|
static inline int svc_is_running (svc_t *svc) { return svc && svc->state == SVC_RUNNING_STATE; }
|
||||||
static inline int svc_is_stopping (svc_t *svc) { return svc && svc->state == SVC_STOPPING_STATE; }
|
static inline int svc_is_stopping (svc_t *svc) { return svc && svc->state == SVC_STOPPING_STATE; }
|
||||||
|
static inline int svc_is_stopped (svc_t *svc) { return svc && svc->block == SVC_BLOCK_USER; }
|
||||||
|
|
||||||
static inline int svc_is_removed (svc_t *svc) { return svc && svc->removed; }
|
static inline int svc_is_removed (svc_t *svc) { return svc && svc->removed; }
|
||||||
static inline int svc_is_changed (svc_t *svc) { return svc && 0 != svc->dirty; }
|
static inline int svc_is_changed (svc_t *svc) { return svc && 0 != svc->dirty; }
|
||||||
@@ -390,12 +407,15 @@ static inline char *svc_status(svc_t *svc)
|
|||||||
return "stopping";
|
return "stopping";
|
||||||
}
|
}
|
||||||
|
|
||||||
case SVC_CLEANUP_STATE:
|
case SVC_TEARDOWN_STATE:
|
||||||
return "cleanup";
|
return "teardown";
|
||||||
|
|
||||||
case SVC_SETUP_STATE:
|
case SVC_SETUP_STATE:
|
||||||
return "setup";
|
return "setup";
|
||||||
|
|
||||||
|
case SVC_CLEANUP_STATE:
|
||||||
|
return "cleanup";
|
||||||
|
|
||||||
case SVC_PAUSED_STATE:
|
case SVC_PAUSED_STATE:
|
||||||
return "paused";
|
return "paused";
|
||||||
|
|
||||||
@@ -408,6 +428,9 @@ static inline char *svc_status(svc_t *svc)
|
|||||||
case SVC_RUNNING_STATE:
|
case SVC_RUNNING_STATE:
|
||||||
return "running";
|
return "running";
|
||||||
|
|
||||||
|
case SVC_DEAD_STATE:
|
||||||
|
return "dead";
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return "UNKNOWN";
|
return "UNKNOWN";
|
||||||
}
|
}
|
||||||
|
|||||||
+299
-174
@@ -23,12 +23,47 @@
|
|||||||
|
|
||||||
#include "config.h" /* Generated by configure script */
|
#include "config.h" /* Generated by configure script */
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <ftw.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <glob.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <grp.h>
|
||||||
|
#include <pwd.h>
|
||||||
#include <sys/sysmacros.h>
|
#include <sys/sysmacros.h>
|
||||||
#include "finit.h"
|
|
||||||
#include "helpers.h"
|
#include <stdlib.h>
|
||||||
#include "tmpfiles.h"
|
#include <string.h>
|
||||||
|
#ifdef _LIBITE_LITE
|
||||||
|
# include <libite/lite.h>
|
||||||
|
#else
|
||||||
|
# include <lite/lite.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
int debug;
|
||||||
|
|
||||||
|
int c_flag = 0;
|
||||||
|
int r_flag = 0;
|
||||||
|
|
||||||
|
static int is_dir_empty(const char *path)
|
||||||
|
{
|
||||||
|
struct dirent **namelist;
|
||||||
|
int num;
|
||||||
|
|
||||||
|
num = scandir(path, &namelist, NULL, NULL);
|
||||||
|
if (num < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < num; i++)
|
||||||
|
free(namelist[i]);
|
||||||
|
free(namelist);
|
||||||
|
|
||||||
|
return num >= 3;
|
||||||
|
}
|
||||||
|
|
||||||
static int glob_do(const char *path, int (*cb)(const char *))
|
static int glob_do(const char *path, int (*cb)(const char *))
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
@@ -75,6 +110,9 @@ static int parse_mm(char *arg, int *major, int *minor)
|
|||||||
|
|
||||||
static int do_delete(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftw)
|
static int do_delete(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftw)
|
||||||
{
|
{
|
||||||
|
(void)sb;
|
||||||
|
(void)tflag;
|
||||||
|
|
||||||
if (ftw->level == 0)
|
if (ftw->level == 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@@ -279,182 +317,214 @@ static void tmpfiles(char *line)
|
|||||||
|
|
||||||
strc = stat(path, &st);
|
strc = stat(path, &st);
|
||||||
|
|
||||||
switch (type[0]) {
|
// file and directory removal logic
|
||||||
case 'b':
|
if (r_flag) {
|
||||||
rc = parse_mm(arg, &major, &minor);
|
switch (type[0]) {
|
||||||
if (rc)
|
case 'b':
|
||||||
|
case 'c':
|
||||||
|
case 'C':
|
||||||
|
case 'd':
|
||||||
break;
|
break;
|
||||||
if (!strc) {
|
case 'D':
|
||||||
if (type[1] != '+')
|
if (fisdir(path)) {
|
||||||
break;
|
nftw(path, do_delete, 20, FTW_DEPTH | FTW_PHYS);
|
||||||
erase(path);
|
|
||||||
}
|
|
||||||
mkparent(path, 0755);
|
|
||||||
rc = blkdev(path, mode ?: 0644, major, minor);
|
|
||||||
break;
|
|
||||||
case 'c':
|
|
||||||
rc = parse_mm(arg, &major, &minor);
|
|
||||||
if (rc)
|
|
||||||
break;
|
|
||||||
if (!strc) {
|
|
||||||
if (type[1] != '+')
|
|
||||||
break;
|
|
||||||
erase(path);
|
|
||||||
}
|
|
||||||
mkparent(path, 0755);
|
|
||||||
rc = chardev(path, mode ?: 0644, major, minor);
|
|
||||||
break;
|
|
||||||
case 'C':
|
|
||||||
if (!arg) {
|
|
||||||
paste(buf, sizeof(buf), "/usr/share/factory", path);
|
|
||||||
arg = buf;
|
|
||||||
}
|
|
||||||
if (!strc) {
|
|
||||||
struct dirent **namelist;
|
|
||||||
int num;
|
|
||||||
|
|
||||||
if (!S_ISDIR(st.st_mode))
|
|
||||||
break;
|
|
||||||
num = scandir(path, &namelist, NULL, NULL);
|
|
||||||
free(namelist);
|
|
||||||
if (num >= 3)
|
|
||||||
break; /* not empty */
|
|
||||||
}
|
|
||||||
if (fisdir(arg) && !fisslashdir(arg)) {
|
|
||||||
size_t len = strlen(arg) + 2;
|
|
||||||
|
|
||||||
dst = malloc(len);
|
|
||||||
if (!dst)
|
|
||||||
break;
|
|
||||||
snprintf(dst, len, "%s/", arg);
|
|
||||||
arg = dst;
|
|
||||||
}
|
|
||||||
mkparent(path, 0755);
|
|
||||||
rc = rsync(arg, path, LITE_FOPT_KEEP_MTIME, NULL);
|
|
||||||
if (rc && errno == ENOENT)
|
|
||||||
rc = 0;
|
|
||||||
break;
|
|
||||||
case 'd':
|
|
||||||
case 'D':
|
|
||||||
mkparent(path, 0755);
|
|
||||||
rc = mksubsys(path, mode ?: 0755, user, group);
|
|
||||||
break;
|
|
||||||
case 'e':
|
|
||||||
if (glob(path, GLOB_NOESCAPE, NULL, &gl))
|
|
||||||
break;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < gl.gl_pathc; i++)
|
|
||||||
rc += mksubsys(gl.gl_pathv[i], mode ?: 0755, user, group);
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
case 'F':
|
|
||||||
mkparent(path, 0755);
|
|
||||||
if (type[1] == '+' || type[0] == 'F') {
|
|
||||||
/* f+/F will create or truncate the file */
|
|
||||||
if (!arg) {
|
|
||||||
rc = create(path, mode ?: 0644, user, group);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
fp = fopen(path, "w+");
|
|
||||||
} else {
|
|
||||||
/* f will create the file if it doesn't exist */
|
|
||||||
if (strc)
|
|
||||||
fp = fopen(path, "w");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fp) {
|
|
||||||
write_arg(fp, arg);
|
|
||||||
rc = fclose(fp);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'l': /* Finit extension, like 'L' but only if target exists */
|
|
||||||
if (!arg) {
|
|
||||||
paste(buf, sizeof(buf), "/usr/share/factory", path);
|
|
||||||
if (stat(buf, &ast))
|
|
||||||
break;
|
|
||||||
} else if (arg[0] != '/') {
|
|
||||||
char *tmp;
|
|
||||||
|
|
||||||
tmp = dirname(strdupa(path));
|
|
||||||
paste(buf, sizeof(buf), tmp, arg);
|
|
||||||
dst = realpath(buf, NULL);
|
|
||||||
if (!dst)
|
|
||||||
break;
|
|
||||||
if (stat(dst, &ast))
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
if (stat(arg, &ast))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* fallthrough */
|
|
||||||
case 'L':
|
|
||||||
if (!strc) {
|
|
||||||
if (type[1] != '+')
|
|
||||||
break;
|
|
||||||
rmrf(path);
|
|
||||||
}
|
|
||||||
mkparent(path, 0755);
|
|
||||||
if (!arg) {
|
|
||||||
paste(buf, sizeof(buf), "/usr/share/factory", path);
|
|
||||||
arg = buf;
|
|
||||||
}
|
|
||||||
rc = ln(arg, path);
|
|
||||||
if (rc && errno == EEXIST)
|
|
||||||
rc = 0;
|
|
||||||
break;
|
|
||||||
case 'p':
|
|
||||||
if (!strc) {
|
|
||||||
if (type[1] != '+')
|
|
||||||
break;
|
|
||||||
erase(path);
|
|
||||||
}
|
|
||||||
mkparent(path, 0755);
|
|
||||||
rc = mkfifo(path, mode ?: 0644);
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
rc = glob_do(path, erase);
|
|
||||||
if (rc && errno == ENOENT)
|
|
||||||
rc = 0;
|
|
||||||
break;
|
|
||||||
case 'R':
|
|
||||||
rc = glob_do(path, rmrf);
|
|
||||||
break;
|
|
||||||
case 'w':
|
|
||||||
if (!arg)
|
|
||||||
break;
|
break;
|
||||||
|
case 'e':
|
||||||
if (glob(path, GLOB_NOESCAPE, NULL, &gl))
|
case 'f':
|
||||||
|
case 'F':
|
||||||
|
case 'l': /* Finit extension, like 'L' but only if target exists */
|
||||||
|
case 'L':
|
||||||
|
case 'p':
|
||||||
break;
|
break;
|
||||||
|
case 'r':
|
||||||
|
rc = glob_do(path, erase);
|
||||||
|
if (rc && errno == ENOENT)
|
||||||
|
rc = 0;
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
rc = glob_do(path, rmrf);
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
break;
|
||||||
|
case 'X':
|
||||||
|
case 'x':
|
||||||
|
dbg("Unsupported x/X command, ignoring %s, no support for clean at runtime.", path);
|
||||||
|
break;
|
||||||
|
case 'Z':
|
||||||
|
case 'z':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errx(1, "Unsupported tmpfiles command '%s'", type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// file & directory creation logic
|
||||||
|
if (c_flag) {
|
||||||
|
switch (type[0]) {
|
||||||
|
case 'b':
|
||||||
|
rc = parse_mm(arg, &major, &minor);
|
||||||
|
if (rc)
|
||||||
|
break;
|
||||||
|
if (!strc) {
|
||||||
|
if (type[1] != '+')
|
||||||
|
break;
|
||||||
|
erase(path);
|
||||||
|
}
|
||||||
|
mkparent(path, 0755);
|
||||||
|
rc = blkdev(path, mode ?: 0644, major, minor);
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
rc = parse_mm(arg, &major, &minor);
|
||||||
|
if (rc)
|
||||||
|
break;
|
||||||
|
if (!strc) {
|
||||||
|
if (type[1] != '+')
|
||||||
|
break;
|
||||||
|
erase(path);
|
||||||
|
}
|
||||||
|
mkparent(path, 0755);
|
||||||
|
rc = chardev(path, mode ?: 0644, major, minor);
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
if (!arg) {
|
||||||
|
paste(buf, sizeof(buf), "/usr/share/factory", path);
|
||||||
|
arg = buf;
|
||||||
|
}
|
||||||
|
if (fisdir(path) && !is_dir_empty(path))
|
||||||
|
break;
|
||||||
|
if (fisdir(arg) && !fisslashdir(arg)) {
|
||||||
|
size_t len = strlen(arg) + 2;
|
||||||
|
|
||||||
|
dst = malloc(len);
|
||||||
|
if (!dst)
|
||||||
|
break;
|
||||||
|
snprintf(dst, len, "%s/", arg);
|
||||||
|
arg = dst;
|
||||||
|
}
|
||||||
|
mkparent(path, 0755);
|
||||||
|
rc = rsync(arg, path, LITE_FOPT_KEEP_MTIME, NULL);
|
||||||
|
if (rc && errno == ENOENT)
|
||||||
|
rc = 0;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
case 'D':
|
||||||
|
mkparent(path, 0755);
|
||||||
|
rc = mksubsys(path, mode ?: 0755, user, group);
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
if (glob(path, GLOB_NOESCAPE, NULL, &gl))
|
||||||
|
break;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < gl.gl_pathc; i++)
|
||||||
|
rc += mksubsys(gl.gl_pathv[i], mode ?: 0755, user, group);
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
case 'F':
|
||||||
|
mkparent(path, 0755);
|
||||||
|
if (type[1] == '+' || type[0] == 'F') {
|
||||||
|
/* f+/F will create or truncate the file */
|
||||||
|
if (!arg) {
|
||||||
|
rc = create(path, mode ?: 0644, user, group);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fp = fopen(path, "w+");
|
||||||
|
} else {
|
||||||
|
/* f will create the file if it doesn't exist */
|
||||||
|
if (strc)
|
||||||
|
fp = fopen(path, "w");
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < gl.gl_pathc; i++) {
|
|
||||||
fp = fopen(gl.gl_pathv[i], type[1] == '+' ? "a" : "w");
|
|
||||||
if (fp) {
|
if (fp) {
|
||||||
write_arg(fp, arg);
|
write_arg(fp, arg);
|
||||||
rc = fclose(fp);
|
rc = fclose(fp);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'X':
|
|
||||||
case 'x':
|
|
||||||
dbg("Unsupported x/X command, ignoring %s, no support for clean at runtime.", path);
|
|
||||||
break;
|
|
||||||
case 'Z':
|
|
||||||
opts = "-R";
|
|
||||||
/* fallthrough */
|
|
||||||
case 'z':
|
|
||||||
if (!whichp("restorecon"))
|
|
||||||
break;
|
|
||||||
if (glob(path, GLOB_NOESCAPE, NULL, &gl))
|
|
||||||
break;
|
break;
|
||||||
|
case 'l': /* Finit extension, like 'L' but only if target exists */
|
||||||
|
if (!arg) {
|
||||||
|
paste(buf, sizeof(buf), "/usr/share/factory", path);
|
||||||
|
if (stat(buf, &ast))
|
||||||
|
break;
|
||||||
|
} else if (arg[0] != '/') {
|
||||||
|
char *tmp;
|
||||||
|
|
||||||
for (size_t i = 0; i < gl.gl_pathc; i++) {
|
tmp = dirname(strdupa(path));
|
||||||
snprintf(buf, sizeof(buf), "restorecon %s %s", opts, gl.gl_pathv[i]);
|
paste(buf, sizeof(buf), tmp, arg);
|
||||||
run(buf, "restorecon");
|
dst = realpath(buf, NULL);
|
||||||
|
if (!dst)
|
||||||
|
break;
|
||||||
|
if (stat(dst, &ast))
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (stat(arg, &ast))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* fallthrough */
|
||||||
|
case 'L':
|
||||||
|
if (!strc) {
|
||||||
|
if (type[1] != '+')
|
||||||
|
break;
|
||||||
|
rmrf(path);
|
||||||
|
}
|
||||||
|
mkparent(path, 0755);
|
||||||
|
if (!arg) {
|
||||||
|
paste(buf, sizeof(buf), "/usr/share/factory", path);
|
||||||
|
arg = buf;
|
||||||
|
}
|
||||||
|
rc = ln(arg, path);
|
||||||
|
if (rc && errno == EEXIST)
|
||||||
|
rc = 0;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
if (!strc) {
|
||||||
|
if (type[1] != '+')
|
||||||
|
break;
|
||||||
|
erase(path);
|
||||||
|
}
|
||||||
|
mkparent(path, 0755);
|
||||||
|
rc = mkfifo(path, mode ?: 0644);
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
case 'R':
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
if (!arg)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (glob(path, GLOB_NOESCAPE, NULL, &gl))
|
||||||
|
break;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < gl.gl_pathc; i++) {
|
||||||
|
fp = fopen(gl.gl_pathv[i], type[1] == '+' ? "a" : "w");
|
||||||
|
if (fp) {
|
||||||
|
write_arg(fp, arg);
|
||||||
|
rc = fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'X':
|
||||||
|
case 'x':
|
||||||
|
dbg("Unsupported x/X command, ignoring %s, no support for clean at runtime.", path);
|
||||||
|
break;
|
||||||
|
case 'Z':
|
||||||
|
opts = "-R";
|
||||||
|
/* fallthrough */
|
||||||
|
case 'z':
|
||||||
|
if (!whichp("restorecon"))
|
||||||
|
break;
|
||||||
|
if (glob(path, GLOB_NOESCAPE, NULL, &gl))
|
||||||
|
break;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < gl.gl_pathc; i++) {
|
||||||
|
snprintf(buf, sizeof(buf), "restorecon %s %s", opts, gl.gl_pathv[i]);
|
||||||
|
system(buf);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errx(1, "Unsupported tmpfiles command '%s'", type);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
default:
|
|
||||||
errx(1, "Unsupported tmpfiles command '%s'", type);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dst)
|
if (dst)
|
||||||
@@ -464,14 +534,68 @@ static void tmpfiles(char *line)
|
|||||||
warn("Failed %s operation on path %s", type, path);
|
warn("Failed %s operation on path %s", type, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static int usage(int rc)
|
||||||
* Only the three last tmpfiles.d/ directories are defined in
|
|
||||||
* tmpfiles.d(5) as system search paths. Finit adds two more
|
|
||||||
* before that to have Finit specific ones sorted first, and
|
|
||||||
* a configure prefix specific one after that for user needs.
|
|
||||||
*/
|
|
||||||
void tmpfilesd(void)
|
|
||||||
{
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"Usage: tmpfiles [COMMAND...]\n"
|
||||||
|
"\n"
|
||||||
|
"Commands:\n"
|
||||||
|
" -c, --create Create files and directories\n"
|
||||||
|
" -d, --debug Show developer debug messages\n"
|
||||||
|
" -r, --remove Remove files and directories marked for removal\n"
|
||||||
|
" -h, --help This help text\n"
|
||||||
|
"\n");
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct option long_options[] = {
|
||||||
|
{ "create", 0, NULL, 'c' },
|
||||||
|
{ "debug", 0, NULL, 'd' },
|
||||||
|
{ "remove", 0, NULL, 'r' },
|
||||||
|
{ "help", 0, NULL, 'h' },
|
||||||
|
{ NULL, 0, NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
int c;
|
||||||
|
|
||||||
|
while ((c = getopt_long(argc, argv, "cdrh?", long_options, NULL)) != EOF) {
|
||||||
|
switch(c) {
|
||||||
|
case 'c':
|
||||||
|
c_flag = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'd':
|
||||||
|
debug = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'r':
|
||||||
|
r_flag = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'h':
|
||||||
|
case '?':
|
||||||
|
return usage(0);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return usage(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c_flag + r_flag == 0) {
|
||||||
|
fprintf(stderr, "You need to specify at least one of --create or --remove.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only the three last tmpfiles.d/ directories are defined in
|
||||||
|
* tmpfiles.d(5) as system search paths. Finit adds two more
|
||||||
|
* before that to have Finit specific ones sorted first, and
|
||||||
|
* a configure prefix specific one after that for user needs.
|
||||||
|
*/
|
||||||
|
|
||||||
/* in priority order */
|
/* in priority order */
|
||||||
char *dir[] = {
|
char *dir[] = {
|
||||||
FINIT_TMPFILES "/*.conf",
|
FINIT_TMPFILES "/*.conf",
|
||||||
@@ -518,6 +642,7 @@ void tmpfilesd(void)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
tmpfiles(line);
|
tmpfiles(line);
|
||||||
|
free(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
/* Limited tmpfiles.d implementation
|
|
||||||
*
|
|
||||||
* Copyright (c) 2024 Joachim Wiberg <troglobit@gmail.com>
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef TMPFILES_H_
|
|
||||||
#define TMPFILES_H_
|
|
||||||
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <ftw.h>
|
|
||||||
#include <glob.h>
|
|
||||||
#include <libgen.h>
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#ifdef _LIBITE_LITE
|
|
||||||
# include <libite/lite.h>
|
|
||||||
#else
|
|
||||||
# include <lite/lite.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void tmpfilesd(void);
|
|
||||||
|
|
||||||
#endif /* TMPFILES_H_ */
|
|
||||||
@@ -38,6 +38,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "config.h" /* Generated by configure script */
|
#include "config.h" /* Generated by configure script */
|
||||||
|
#include "log.h"
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
@@ -172,7 +173,7 @@ int tty_parse_args(struct tty *tty, char *cmd, char **args)
|
|||||||
passenv = 1;
|
passenv = 1;
|
||||||
else if (!strcmp(cmd, "rescue"))
|
else if (!strcmp(cmd, "rescue"))
|
||||||
tty->rescue = 1; /* for rescue shells */
|
tty->rescue = 1; /* for rescue shells */
|
||||||
else if (whichp(cmd)) /* in $PATH? */
|
else if (!tty->cmd && whichp(cmd))
|
||||||
tty->cmd = cmd;
|
tty->cmd = cmd;
|
||||||
else
|
else
|
||||||
tty->args[tty->num++] = cmd;
|
tty->args[tty->num++] = cmd;
|
||||||
@@ -229,8 +230,9 @@ int tty_parse_args(struct tty *tty, char *cmd, char **args)
|
|||||||
return errno = EINVAL;
|
return errno = EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
dbg("Registering %s getty on TTY %s at %s baud with term %s", tty->cmd ? "external" : "built-in",
|
dbg("Registering %s getty on TTY %s at %s baud with term %s",
|
||||||
tty->dev, tty->baud ?: "0", tty->term ?: "N/A");
|
tty->cmd ? "external" : "built-in",
|
||||||
|
tty->dev, tty->baud ?: "0", tty->term ?: "N/A");
|
||||||
|
|
||||||
/* Built-in getty now comes as standalone program */
|
/* Built-in getty now comes as standalone program */
|
||||||
if (!tty->cmd) {
|
if (!tty->cmd) {
|
||||||
|
|||||||
+94
@@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
#include <ctype.h> /* isprint() */
|
#include <ctype.h> /* isprint() */
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <grp.h>
|
||||||
|
#include <pwd.h>
|
||||||
#ifdef HAVE_MNTENT_H
|
#ifdef HAVE_MNTENT_H
|
||||||
#include <mntent.h>
|
#include <mntent.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -178,6 +180,98 @@ char *str(char *fmt, ...)
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getuser(char *username, char **home)
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_STATIC
|
||||||
|
if (home)
|
||||||
|
*home = "/"; /* XXX: Fixme */
|
||||||
|
return fgetint("/etc/passwd", "x:\n", username);
|
||||||
|
#else
|
||||||
|
struct passwd *usr;
|
||||||
|
|
||||||
|
if (!username || (usr = getpwnam(username)) == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (home)
|
||||||
|
*home = usr->pw_dir;
|
||||||
|
return usr->pw_uid;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int getgroup(char *group)
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_STATIC
|
||||||
|
return fgetint("/etc/group", "x:\n", group);
|
||||||
|
#else
|
||||||
|
struct group *grp;
|
||||||
|
|
||||||
|
if ((grp = getgrnam(group)) == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return grp->gr_gid;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get current user */
|
||||||
|
int getcuser(char *buf, size_t len)
|
||||||
|
{
|
||||||
|
char *ptr = "root";
|
||||||
|
|
||||||
|
#ifndef ENABLE_STATIC
|
||||||
|
struct passwd *pw = getpwuid(getuid());
|
||||||
|
|
||||||
|
if (pw)
|
||||||
|
ptr = pw->pw_name;
|
||||||
|
#endif
|
||||||
|
if (strlcpy(buf, ptr, len) > len)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get current group */
|
||||||
|
int getcgroup(char *buf, size_t len)
|
||||||
|
{
|
||||||
|
char *ptr = "root";
|
||||||
|
|
||||||
|
#ifndef ENABLE_STATIC
|
||||||
|
struct group *gr = getgrgid(getgid());
|
||||||
|
|
||||||
|
if (gr)
|
||||||
|
ptr = gr->gr_name;
|
||||||
|
#endif
|
||||||
|
if (strlcpy(buf, ptr, len) > len)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mksubsys(const char *dir, mode_t mode, char *user, char *group)
|
||||||
|
{
|
||||||
|
mode_t omask;
|
||||||
|
int uid, gid;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
omask = umask(0);
|
||||||
|
|
||||||
|
uid = getuser(user, NULL);
|
||||||
|
if (uid >= 0) {
|
||||||
|
gid = getgroup(group);
|
||||||
|
if (gid < 0)
|
||||||
|
gid = 0;
|
||||||
|
|
||||||
|
rc = makedir(dir, mode);
|
||||||
|
if (rc && errno == EEXIST)
|
||||||
|
rc = chmod(dir, mode);
|
||||||
|
if (chown(dir, uid, gid))
|
||||||
|
err(1, "Failed chown(%s, %d, %d)", dir, uid, gid);
|
||||||
|
}
|
||||||
|
|
||||||
|
umask(omask);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
int fnread(char *buf, size_t len, char *fmt, ...)
|
int fnread(char *buf, size_t len, char *fmt, ...)
|
||||||
{
|
{
|
||||||
char path[256];
|
char path[256];
|
||||||
|
|||||||
+117
@@ -25,6 +25,8 @@
|
|||||||
#define FINIT_UTIL_H_
|
#define FINIT_UTIL_H_
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
#ifdef HAVE_TERMIOS_H
|
#ifdef HAVE_TERMIOS_H
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -53,11 +55,21 @@ extern char *prognm;
|
|||||||
# include <lite/conio.h>
|
# include <lite/conio.h>
|
||||||
# include <lite/lite.h>
|
# include <lite/lite.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
char *progname (char *arg0);
|
char *progname (char *arg0);
|
||||||
const char *basenm (const char *path);
|
const char *basenm (const char *path);
|
||||||
|
|
||||||
char *str (char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
char *str (char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
||||||
|
|
||||||
|
int getuser (char *username, char **home);
|
||||||
|
int getgroup (char *group);
|
||||||
|
|
||||||
|
int getcuser (char *buf, size_t len);
|
||||||
|
int getcgroup (char *buf, size_t len);
|
||||||
|
|
||||||
|
int mksubsys (const char *dir, mode_t mode, char *user, char *group);
|
||||||
|
|
||||||
int fnread (char *buf, size_t len, char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
|
int fnread (char *buf, size_t len, char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
|
||||||
int fnwrite (char *value, char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
int fnwrite (char *value, char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
int fngetint (char *path, int *val);
|
int fngetint (char *path, int *val);
|
||||||
@@ -92,6 +104,57 @@ int ttcooked (void);
|
|||||||
#define ttcooked() 0
|
#define ttcooked() 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Defaults to user "root" and group "wheel" (root) if:
|
||||||
|
* 1) the user is missing
|
||||||
|
* 2) the group or the file /etc/group is missing
|
||||||
|
*/
|
||||||
|
static inline int create(char *path, mode_t mode, char *user, char *group)
|
||||||
|
{
|
||||||
|
int fd, uid, gid;
|
||||||
|
|
||||||
|
if (!path) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uid = getuser(user, NULL);
|
||||||
|
if (uid < 0)
|
||||||
|
uid = 0;
|
||||||
|
gid = getgroup(group);
|
||||||
|
if (gid < 0)
|
||||||
|
gid = 0;
|
||||||
|
|
||||||
|
fd = creat(path, mode);
|
||||||
|
if (fd == -1) {
|
||||||
|
warn("Failed creating %s properly", path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
if (chown(path, uid, gid)) {
|
||||||
|
warn("Failed chowning %s properly", path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int ln(const char *target, const char *linkpath)
|
||||||
|
{
|
||||||
|
if (!target || !linkpath) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symlink(target, linkpath)) {
|
||||||
|
if (errno != EEXIST)
|
||||||
|
warn("Failed creating %s -> %s symlink", target, linkpath);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline char *strterm(char *str, size_t len)
|
static inline char *strterm(char *str, size_t len)
|
||||||
{
|
{
|
||||||
str[len - 1] = 0;
|
str[len - 1] = 0;
|
||||||
@@ -130,6 +193,60 @@ static inline int suffix(char *path, size_t len, const char *sfx)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void hexdump(const char *buf, size_t len)
|
||||||
|
{
|
||||||
|
size_t i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i += 16) {
|
||||||
|
printf("%08zx ", i);
|
||||||
|
|
||||||
|
for (j = 0; j < 8 && i + j < len; j++)
|
||||||
|
printf("%02x ", buf[i + j]);
|
||||||
|
|
||||||
|
if (j == 8) {
|
||||||
|
printf(" ");
|
||||||
|
} else {
|
||||||
|
for (; j < 8; j++)
|
||||||
|
printf(" ");
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = 8; j < 16 && i + j < len; j++)
|
||||||
|
printf("%02x ", buf[i + j]);
|
||||||
|
|
||||||
|
for (; j < 16; j++)
|
||||||
|
printf(" ");
|
||||||
|
|
||||||
|
printf(" |");
|
||||||
|
for (j = 0; j < 16 && i + j < len; j++) {
|
||||||
|
char c = buf[i + j];
|
||||||
|
printf("%c", isprint(c) ? c : '.');
|
||||||
|
}
|
||||||
|
printf("|\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* drop quotes from a string at point, if any */
|
||||||
|
static inline int unquote(char **str, char *end)
|
||||||
|
{
|
||||||
|
char *ptr = *str;
|
||||||
|
|
||||||
|
/* unquote value, if quoted */
|
||||||
|
if (ptr[0] == '"' || ptr[0] == '\'') {
|
||||||
|
char q = ptr[0];
|
||||||
|
|
||||||
|
if (!end && !(end = strchr(&ptr[1], q)))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (*end == q) {
|
||||||
|
*str = &ptr[1];
|
||||||
|
*end = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* FINIT_UTIL_H_ */
|
#endif /* FINIT_UTIL_H_ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ test_teardown()
|
|||||||
# shellcheck source=/dev/null
|
# shellcheck source=/dev/null
|
||||||
. "$TEST_DIR/lib/setup.sh"
|
. "$TEST_DIR/lib/setup.sh"
|
||||||
|
|
||||||
say "Test start $(date)"
|
|
||||||
|
|
||||||
say "Add a dynamic service in $FINIT_RCSD/service.conf"
|
say "Add a dynamic service in $FINIT_RCSD/service.conf"
|
||||||
run "echo 'service [2345] kill:20 log service.sh -- Dyn serv' > $FINIT_RCSD/service.conf"
|
run "echo 'service [2345] kill:20 log service.sh -- Dyn serv' > $FINIT_RCSD/service.conf"
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ test_teardown()
|
|||||||
# shellcheck source=/dev/null
|
# shellcheck source=/dev/null
|
||||||
. "$TEST_DIR/lib/setup.sh"
|
. "$TEST_DIR/lib/setup.sh"
|
||||||
|
|
||||||
say "Test start $(date)"
|
|
||||||
|
|
||||||
say "Add a dynamic service in $FINIT_CONF"
|
say "Add a dynamic service in $FINIT_CONF"
|
||||||
run "echo 'service [2345] kill:20 log service.sh -- Dyn service' > $FINIT_CONF"
|
run "echo 'service [2345] kill:20 log service.sh -- Dyn service' > $FINIT_CONF"
|
||||||
|
|
||||||
|
|||||||
@@ -11,11 +11,6 @@ BOOTSTRAP="run [S] crasher.sh -- Party crasher"
|
|||||||
# shellcheck source=/dev/null
|
# shellcheck source=/dev/null
|
||||||
. "$TEST_DIR/lib/setup.sh"
|
. "$TEST_DIR/lib/setup.sh"
|
||||||
|
|
||||||
test_setup()
|
|
||||||
{
|
|
||||||
say "Test start $(date)"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_teardown()
|
test_teardown()
|
||||||
{
|
{
|
||||||
say "Test done $(date)"
|
say "Test done $(date)"
|
||||||
|
|||||||
@@ -7,11 +7,6 @@ set -eu
|
|||||||
|
|
||||||
TEST_DIR=$(dirname "$0")
|
TEST_DIR=$(dirname "$0")
|
||||||
|
|
||||||
test_setup()
|
|
||||||
{
|
|
||||||
say "Test start $(date)"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_teardown()
|
test_teardown()
|
||||||
{
|
{
|
||||||
say "Test done $(date)"
|
say "Test done $(date)"
|
||||||
|
|||||||
@@ -5,11 +5,6 @@ set -eu
|
|||||||
|
|
||||||
TEST_DIR=$(dirname "$0")
|
TEST_DIR=$(dirname "$0")
|
||||||
|
|
||||||
test_setup()
|
|
||||||
{
|
|
||||||
say "Test start $(date)"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_teardown()
|
test_teardown()
|
||||||
{
|
{
|
||||||
say "Test done $(date)"
|
say "Test done $(date)"
|
||||||
|
|||||||
+1
-6
@@ -1,5 +1,5 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# Verify handling of dependant services, bug #314
|
# Verify handling of dependent services, bug #314
|
||||||
# Two services: foo and bar, where bar depends on foo:
|
# Two services: foo and bar, where bar depends on foo:
|
||||||
#
|
#
|
||||||
# - bar must not start until foo is ready
|
# - bar must not start until foo is ready
|
||||||
@@ -14,11 +14,6 @@ set -eu
|
|||||||
|
|
||||||
TEST_DIR=$(dirname "$0")
|
TEST_DIR=$(dirname "$0")
|
||||||
|
|
||||||
test_setup()
|
|
||||||
{
|
|
||||||
say "Test start $(date)"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_teardown()
|
test_teardown()
|
||||||
{
|
{
|
||||||
say "Test done $(date)"
|
say "Test done $(date)"
|
||||||
|
|||||||
@@ -7,11 +7,6 @@ set -eu
|
|||||||
|
|
||||||
TEST_DIR=$(dirname "$0")
|
TEST_DIR=$(dirname "$0")
|
||||||
|
|
||||||
test_setup()
|
|
||||||
{
|
|
||||||
say "Test start $(date)"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_teardown()
|
test_teardown()
|
||||||
{
|
{
|
||||||
say "Test done $(date)"
|
say "Test done $(date)"
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ TEST_DIR=$(dirname "$0")
|
|||||||
|
|
||||||
test_setup()
|
test_setup()
|
||||||
{
|
{
|
||||||
say "Test start $(date)"
|
|
||||||
run "mkdir -p /etc/default"
|
run "mkdir -p /etc/default"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,11 +8,6 @@ set COLORTERM=yes\n\
|
|||||||
b aq=oroszoe\n\
|
b aq=oroszoe\n\
|
||||||
baz=qux"
|
baz=qux"
|
||||||
|
|
||||||
test_setup()
|
|
||||||
{
|
|
||||||
say "Test start $(date)"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_teardown()
|
test_teardown()
|
||||||
{
|
{
|
||||||
say "Test done $(date)"
|
say "Test done $(date)"
|
||||||
|
|||||||
@@ -7,11 +7,6 @@ set -eu
|
|||||||
|
|
||||||
TEST_DIR=$(dirname "$0")
|
TEST_DIR=$(dirname "$0")
|
||||||
|
|
||||||
test_setup()
|
|
||||||
{
|
|
||||||
say "Test start $(date)"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_teardown()
|
test_teardown()
|
||||||
{
|
{
|
||||||
say "Test done $(date)"
|
say "Test done $(date)"
|
||||||
|
|||||||
@@ -362,6 +362,8 @@ echo "Finit running as PID $finit_pid"
|
|||||||
#tty=/dev/$(texec cat /sys/class/tty/console/active)
|
#tty=/dev/$(texec cat /sys/class/tty/console/active)
|
||||||
#texec cat "$tty" &
|
#texec cat "$tty" &
|
||||||
|
|
||||||
|
sep "Test start $(date)"
|
||||||
|
|
||||||
# Allow Finit to start up properly before launching the test
|
# Allow Finit to start up properly before launching the test
|
||||||
i=0
|
i=0
|
||||||
set +u
|
set +u
|
||||||
|
|||||||
+1
-1
@@ -41,7 +41,7 @@ export PATH
|
|||||||
# Not supported by Busybox unshare:
|
# Not supported by Busybox unshare:
|
||||||
# --cgroup --time
|
# --cgroup --time
|
||||||
exec "$unshare" \
|
exec "$unshare" \
|
||||||
--user --map-root-user \
|
--user --map-root-user --map-auto \
|
||||||
--fork --pid --mount-proc \
|
--fork --pid --mount-proc \
|
||||||
--mount \
|
--mount \
|
||||||
--mount-proc \
|
--mount-proc \
|
||||||
|
|||||||
+10
-2
@@ -8,7 +8,6 @@ TEST_DIR=$(dirname "$0")
|
|||||||
|
|
||||||
test_setup()
|
test_setup()
|
||||||
{
|
{
|
||||||
say "Test start $(date)"
|
|
||||||
run "mkdir -p /etc/default"
|
run "mkdir -p /etc/default"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,6 +24,15 @@ test_one()
|
|||||||
type=$1
|
type=$1
|
||||||
service=$2
|
service=$2
|
||||||
|
|
||||||
|
# Skip systemd tests if serv doesn't have libsystemd support
|
||||||
|
if [ "$type" = "systemd" ]; then
|
||||||
|
if ! "$TEST_DIR/src/serv" -C | grep -q "libsystemd"; then
|
||||||
|
sep
|
||||||
|
say "Skipping systemd test - serv built without libsystemd support"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
sep
|
sep
|
||||||
|
|
||||||
# num=$(run "find /proc/1/fd |wc -l")
|
# num=$(run "find /proc/1/fd |wc -l")
|
||||||
@@ -71,7 +79,7 @@ test_one()
|
|||||||
assert_status "serv" "running"
|
assert_status "serv" "running"
|
||||||
assert_cond "service/serv/ready"
|
assert_cond "service/serv/ready"
|
||||||
|
|
||||||
# Issue #343; pidfile.so inadvertedly marked systemd services as
|
# Issue #343; pidfile.so inadvertently marked systemd services as
|
||||||
# 'started' when they created their PID file. The serv test daemon
|
# 'started' when they created their PID file. The serv test daemon
|
||||||
# waits 3 sec between pidfile and notify to trigger this bug.
|
# waits 3 sec between pidfile and notify to trigger this bug.
|
||||||
if [ "$type" != "pid" ]; then
|
if [ "$type" != "pid" ]; then
|
||||||
|
|||||||
@@ -5,11 +5,6 @@ set -eu
|
|||||||
|
|
||||||
TEST_DIR=$(dirname "$0")
|
TEST_DIR=$(dirname "$0")
|
||||||
|
|
||||||
test_setup()
|
|
||||||
{
|
|
||||||
say "Test start $(date)"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_teardown()
|
test_teardown()
|
||||||
{
|
{
|
||||||
say "Test done $(date)"
|
say "Test done $(date)"
|
||||||
|
|||||||
@@ -9,11 +9,6 @@ set -eu
|
|||||||
|
|
||||||
TEST_DIR=$(dirname "$0")
|
TEST_DIR=$(dirname "$0")
|
||||||
|
|
||||||
test_setup()
|
|
||||||
{
|
|
||||||
say "Test start $(date)"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_teardown()
|
test_teardown()
|
||||||
{
|
{
|
||||||
say "Test done $(date)"
|
say "Test done $(date)"
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ TEST_DIR=$(dirname "$0")
|
|||||||
|
|
||||||
test_setup()
|
test_setup()
|
||||||
{
|
{
|
||||||
say "Test start $(date)"
|
|
||||||
run "mkdir -p /etc/default"
|
run "mkdir -p /etc/default"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-11
@@ -1,26 +1,20 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# Regression test for basic /etc/rc.local functionality
|
# Regression test for basic /etc/rc.local functionality
|
||||||
# shellcheck disable=SC2317
|
# shellcheck disable=2317,2034
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
|
RCLOCAL="echo 'KILROY WAS HERE' > /tmp/rclocal"
|
||||||
TEST_DIR=$(dirname "$0")
|
TEST_DIR=$(dirname "$0")
|
||||||
#DEBUG=1
|
#DEBUG=1
|
||||||
# shellcheck disable=SC2034
|
|
||||||
RCLOCAL="echo 'KILROY WAS HERE' > /tmp/rclocal"
|
|
||||||
|
|
||||||
# shellcheck source=/dev/null
|
|
||||||
. "$TEST_DIR/lib/setup.sh"
|
|
||||||
|
|
||||||
test_setup()
|
|
||||||
{
|
|
||||||
say "Test start $(date)"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_teardown()
|
test_teardown()
|
||||||
{
|
{
|
||||||
say "Test done $(date)"
|
say "Test done $(date)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# shellcheck source=/dev/null
|
||||||
|
. "$TEST_DIR/lib/setup.sh"
|
||||||
|
|
||||||
sleep 1
|
sleep 1
|
||||||
assert_file_contains /tmp/rclocal "KILROY WAS HERE"
|
assert_file_contains /tmp/rclocal "KILROY WAS HERE"
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,6 @@ set -eu
|
|||||||
|
|
||||||
TEST_DIR=$(dirname "$0")
|
TEST_DIR=$(dirname "$0")
|
||||||
|
|
||||||
test_setup()
|
|
||||||
{
|
|
||||||
say "Test start $(date)"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_teardown()
|
test_teardown()
|
||||||
{
|
{
|
||||||
say "Test done $(date)"
|
say "Test done $(date)"
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ TEST_DIR=$(dirname "$0")
|
|||||||
|
|
||||||
test_setup()
|
test_setup()
|
||||||
{
|
{
|
||||||
say "Test start $(date)"
|
|
||||||
run "mkdir -p /etc/default"
|
run "mkdir -p /etc/default"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user