mirror of
https://github.com/troglobit/finit.git
synced 2026-10-12 10:12:32 +00:00
Compare commits
53
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5d8fcfdf13 | ||
|
|
e4830c5614 | ||
|
|
f33261af6b | ||
|
|
e7516f2b63 | ||
|
|
d18167fe1d | ||
|
|
7d3f95c0a9 | ||
|
|
86c5bbb03d | ||
|
|
7530bb74f6 | ||
|
|
54dd726d16 | ||
|
|
bd9bb92ca0 | ||
|
|
01cb088e51 | ||
|
|
3d91112e0d | ||
|
|
16aef80682 | ||
|
|
fd34914936 | ||
|
|
21a890a04e | ||
|
|
7f5f7e8ef6 | ||
|
|
ff937576ea | ||
|
|
7d831170ae | ||
|
|
6a21ac55ad | ||
|
|
a0820c7f20 | ||
|
|
6d58c9ed0b | ||
|
|
bc2ffbc767 | ||
|
|
4c1fc2410e | ||
|
|
70e1aa889a | ||
|
|
c8c5e4e88a | ||
|
|
86c1398778 | ||
|
|
b37fa2b417 | ||
|
|
a91e197553 | ||
|
|
5adb92ca1b | ||
|
|
cfc99c4e8b | ||
|
|
3e51ed1c55 | ||
|
|
b5df0a6274 | ||
|
|
cbe8d56042 | ||
|
|
a3ec792b44 | ||
|
|
c24855d4d5 | ||
|
|
014e457fda | ||
|
|
21d89c7e24 | ||
|
|
639fb76f5a | ||
|
|
30c189b116 | ||
|
|
e2a8803f7a | ||
|
|
209e140ddd | ||
|
|
2e3fa72924 | ||
|
|
1502838a0d | ||
|
|
377c8bce8c | ||
|
|
a39d958d25 | ||
|
|
7f8a96a73e | ||
|
|
5c2577214d | ||
|
|
f03206a694 | ||
|
|
f0e328edc9 | ||
|
|
13342f2bd9 | ||
|
|
c926160853 | ||
|
|
462d5b22b4 | ||
|
|
b1bfab08f3 |
@@ -3,7 +3,7 @@ name: Release General
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- '[0-9]+.[0-9]+'
|
- '[0-9]+.[0-9]+*'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
|
|||||||
+39
-3
@@ -10,14 +10,40 @@ All relevant changes are documented in this file.
|
|||||||
Critical bug fix release. If you run a 32-bit target with GLIBC 2.34
|
Critical bug fix release. If you run a 32-bit target with GLIBC 2.34
|
||||||
you *need* to upgrade!
|
you *need* to upgrade!
|
||||||
|
|
||||||
|
> **Note:** system verbosity on console at start and shutdown has been
|
||||||
|
> increased. Now the output of all commands is logged to the
|
||||||
|
> system logger, for early services `/dev/kmsg` is used.
|
||||||
|
>
|
||||||
|
> **Also:** please notice the updated support for enabling and disabling
|
||||||
|
> kernel and Finit debug messages on the system console. Very
|
||||||
|
> useful when debugging either of them, e.g., a kernel module.
|
||||||
|
> For details, see [cmdline.md](doc/cmdline.md).
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
* Loading `module`s no longer shows arguments in progress output
|
* Loading `module`s no longer shows arguments in progress output
|
||||||
* Warning messages in progress output now in yellow, not red, issue 214
|
* Warning messages in progress output now in yellow, not red, issue #214
|
||||||
* `initctl`, new command line option `-v,--version` for ease of use
|
* `initctl`, new command line option `-v,--version` for ease of use
|
||||||
* Extended environment variables for pre/post scripts, issue #189
|
* Extended environment variables for pre/post scripts, issue #189
|
||||||
* New condition `done` for run task, issue #207 by Ming Liu, Atlas Copco
|
* New condition `done` for run task, issue #207 by Ming Liu, Atlas Copco
|
||||||
* Refactor parts of shutdown and reboot sequence for PREEMPT-RT kernels,
|
* Refactor parts of shutdown and reboot sequence for PREEMPT-RT kernels,
|
||||||
by Robert Andersson, Mathias Thore, and Ming Liu, Atlas Copco
|
by Robert Andersson, Mathias Thore, and Ming Liu, Atlas Copco
|
||||||
|
* Conditions for run/task/sysv status, e.g. `run/foo/success` and
|
||||||
|
`task/bar/failure`. Issue #232, by Ming Liu, Atlas Copco
|
||||||
|
* initctl support for sending signals to services, by Jörgen
|
||||||
|
Sigvardsson, issue #225
|
||||||
|
* `[WARN]` messages on console now printed in yellow, issue #214
|
||||||
|
* Network services now also stopped when going to runlevel 6 (reboot),
|
||||||
|
not just runlevel 0 (shutdown) or 1 (single-user)
|
||||||
|
* When `ifup` is missing on the system, bring at least `lo` up at boot
|
||||||
|
* Log output from `ifup -a` (and `ifdown -a`), to syslog
|
||||||
|
* Avoid blocking PID 1 when starting SysV init scripts
|
||||||
|
* Allow custom `pid:` for SysV init scripts
|
||||||
|
* Document supported types of forking/non-forking services
|
||||||
|
* Auto-detect running in some common forms of containers
|
||||||
|
* Simplify shutdown/reboot when running in a container
|
||||||
|
* Log to `stderr` when running in a container w/o syslog daemon
|
||||||
|
* Add support for `type:forking` to services, already supported but
|
||||||
|
with a very difficult `pid:` syntax. Documentation updated
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
* Fix nasty 32/64-bit alignment issue between finit and its plugins,
|
* Fix nasty 32/64-bit alignment issue between finit and its plugins,
|
||||||
@@ -27,6 +53,16 @@ you *need* to upgrade!
|
|||||||
or does not have the required controllers (cpu)
|
or does not have the required controllers (cpu)
|
||||||
* Fix #217: iwatcher initialization issue, by Ming Liu, Atlas Copco
|
* Fix #217: iwatcher initialization issue, by Ming Liu, Atlas Copco
|
||||||
* Fix #218: initctl matches too many services, by Ming Liu, Atlas Copco
|
* Fix #218: initctl matches too many services, by Ming Liu, Atlas Copco
|
||||||
|
* Fix #219: not all filesystems unmounted at shutdown, by Ming Liu,
|
||||||
|
Mathias Thore, and Robert Andersson, Atlas Copco
|
||||||
|
* Fix #226: initctl shows wrong PID for crashing services
|
||||||
|
* Fix #227: reboot stalls if process stopped with `[WARN]`
|
||||||
|
* Fix #233: initctl shows wrong status for run/task, by Sergio Morlans
|
||||||
|
and Ming Liu, Atlas Copco
|
||||||
|
* Fix start/stop of SysV init scripts
|
||||||
|
* Fix call to `swapoff` at shutdown, does not support `-e` flag
|
||||||
|
* Fix suspend to RAM issue. Previously `reboot(RB_SW_SUSPEND)` was
|
||||||
|
used, now the modern `/sys/power/state` API is used instead.
|
||||||
|
|
||||||
|
|
||||||
[4.2][] - 2022-01-16
|
[4.2][] - 2022-01-16
|
||||||
@@ -781,7 +817,7 @@ The inetd release.
|
|||||||
### Changes
|
### Changes
|
||||||
* Add support for built-in inetd super server -- launch services on
|
* Add support for built-in inetd super server -- launch services on
|
||||||
demand. Supports filtering per interface and custom Inet ports.
|
demand. Supports filtering per interface and custom Inet ports.
|
||||||
* Upgrade to [libuEv] v1.1.0 to better handle error conditions.
|
* Upgrade to [libuEv][] v1.1.0 to better handle error conditions.
|
||||||
* Allow mixed case config directives in `finit.conf`
|
* Allow mixed case config directives in `finit.conf`
|
||||||
* Add support for RFC 868 (rdate) time plugin, start as inetd service.
|
* Add support for RFC 868 (rdate) time plugin, start as inetd service.
|
||||||
* Load plugins before parsing `finit.conf`, this makes it possible to
|
* Load plugins before parsing `finit.conf`, this makes it possible to
|
||||||
@@ -812,7 +848,7 @@ The inetd release.
|
|||||||
[1.11][] - 2015-01-24 [YANKED]
|
[1.11][] - 2015-01-24 [YANKED]
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
The [libuEv] release.
|
The [libuEv][] release.
|
||||||
|
|
||||||
**Note:** This release has been *yanked* from distribution due to a
|
**Note:** This release has been *yanked* from distribution due to a
|
||||||
regression in launching background processes and TTY's. Fixed in
|
regression in launching background processes and TTY's. Fixed in
|
||||||
|
|||||||
@@ -54,6 +54,11 @@ on server and desktop systems as well. For working examples, see the
|
|||||||
* [Alpine Linux](contrib/alpine/), and
|
* [Alpine Linux](contrib/alpine/), and
|
||||||
* [Debian GNU/Linux](contrib/debian/)
|
* [Debian GNU/Linux](contrib/debian/)
|
||||||
|
|
||||||
|
> **Note:** support for various Linux distributions does not mean Finit
|
||||||
|
> installs easily on all architectures. The bundled install scripts are
|
||||||
|
> examples for standard installations, tested on x86_64 systems. Custom
|
||||||
|
> setups, targeted at embedded systems, can be found in [myLinux][].
|
||||||
|
|
||||||
|
|
||||||
Example
|
Example
|
||||||
-------
|
-------
|
||||||
@@ -598,6 +603,7 @@ and proposed extensions.
|
|||||||
[Joachim Wiberg]: https://troglobit.com
|
[Joachim Wiberg]: https://troglobit.com
|
||||||
[License]: https://en.wikipedia.org/wiki/MIT_License
|
[License]: https://en.wikipedia.org/wiki/MIT_License
|
||||||
[License Badge]: https://img.shields.io/badge/License-MIT-teal.svg
|
[License Badge]: https://img.shields.io/badge/License-MIT-teal.svg
|
||||||
|
[GitHub]: https://github.com/troglobit/myLinux/
|
||||||
[GitHub]: https://github.com/troglobit/finit/actions/workflows/build.yml/
|
[GitHub]: https://github.com/troglobit/finit/actions/workflows/build.yml/
|
||||||
[GitHub Status]: https://github.com/troglobit/finit/actions/workflows/build.yml/badge.svg
|
[GitHub Status]: https://github.com/troglobit/finit/actions/workflows/build.yml/badge.svg
|
||||||
[Coverity Scan]: https://scan.coverity.com/projects/3545
|
[Coverity Scan]: https://scan.coverity.com/projects/3545
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
AC_INIT(Finit, 4.3-dev, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/finit.html)
|
AC_INIT(Finit, 4.3-rc1, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/finit.html)
|
||||||
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])
|
||||||
AM_SILENT_RULES([yes])
|
AM_SILENT_RULES([yes])
|
||||||
|
|||||||
+19
-10
@@ -29,8 +29,8 @@ optional plugins to enable. It depends on two external libraries:
|
|||||||
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:
|
||||||
|
|
||||||
- libite v2.2.0
|
- libite v2.2.0, or later
|
||||||
- libuEv v2.2.0
|
- libuEv v2.2.0, or later
|
||||||
|
|
||||||
|
|
||||||
Configure
|
Configure
|
||||||
@@ -54,7 +54,7 @@ Below are a few of the main switches to configure:
|
|||||||
will be linked statically.
|
will be linked statically.
|
||||||
|
|
||||||
* `--enable-kernel-cmdline`: Enable Finit pre-4.1 parsing of init args from
|
* `--enable-kernel-cmdline`: Enable Finit pre-4.1 parsing of init args from
|
||||||
`/proc/cmdline`, this is not recommended since Finit may be running as the
|
`/proc/cmdline`, this is *not recommended* since Finit may be running as the
|
||||||
init for container apps that can see the host's `/proc` filesystem
|
init for container apps that can see the host's `/proc` filesystem
|
||||||
|
|
||||||
* `--enable-alsa-utils-plugin`: Enable the optional `alsa-utils.so` sound plugin.
|
* `--enable-alsa-utils-plugin`: Enable the optional `alsa-utils.so` sound plugin.
|
||||||
@@ -67,6 +67,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
|
||||||
|
> however included in (officially supported) released tarballs. The
|
||||||
|
> idea is that you should not need GNU autotools to build, only the
|
||||||
|
> above mentioned dependencies, a POSIX shell, a C compiler and make.
|
||||||
|
> Any contributing to Finit can generate it from `configure.ac` using
|
||||||
|
> the `autogen.sh` script.
|
||||||
|
|
||||||
|
|
||||||
Example
|
Example
|
||||||
-------
|
-------
|
||||||
@@ -74,8 +81,8 @@ Example
|
|||||||
First, unpack the archive:
|
First, unpack the archive:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ tar xf finit-4.1.tar.gz
|
$ tar xf finit-4.3.tar.gz
|
||||||
$ cd finit-4.1/
|
$ cd finit-4.3/
|
||||||
```
|
```
|
||||||
|
|
||||||
Then configure, build and install:
|
Then configure, build and install:
|
||||||
@@ -83,7 +90,7 @@ Then configure, build and install:
|
|||||||
```shell
|
```shell
|
||||||
$ ./configure --prefix=/usr --exec-prefix= \
|
$ ./configure --prefix=/usr --exec-prefix= \
|
||||||
--sysconfdir=/etc --localstatedir=/var \
|
--sysconfdir=/etc --localstatedir=/var \
|
||||||
--with-keventd --with-watchdog
|
--with-keventd --with-watchdog
|
||||||
$ make
|
$ make
|
||||||
.
|
.
|
||||||
.
|
.
|
||||||
@@ -91,7 +98,7 @@ $ make
|
|||||||
$ DESTDIR=/tmp/finit make install
|
$ DESTDIR=/tmp/finit make install
|
||||||
```
|
```
|
||||||
|
|
||||||
In this example the [finit-4.1.tar.gz][1] archive is unpacked to the
|
In this example the [finit-4.3.tar.gz][1] archive is unpacked to the
|
||||||
user's home directory, configured, built and installed to a temporary
|
user's home directory, configured, built and installed to a temporary
|
||||||
staging directory. The environment variable `DESTDIR` controls the
|
staging directory. The environment variable `DESTDIR` controls the
|
||||||
destination directory when installing, very useful for building binary
|
destination directory when installing, very useful for building binary
|
||||||
@@ -151,12 +158,14 @@ Debugging
|
|||||||
---------
|
---------
|
||||||
|
|
||||||
Edit, or append to, the kernel command line: remove `quiet` to enable
|
Edit, or append to, the kernel command line: remove `quiet` to enable
|
||||||
kernel messages and add `debug` to enable Finit debug messages.
|
kernel messages and add `finit.debug` to enable Finit debug messages.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
append="init=/sbin/finit debug"
|
append="init=/sbin/finit -- finit.debug"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Notice the `--` separator.
|
||||||
|
|
||||||
To debug startup issues, in particular issues with getty/login, add
|
To debug startup issues, in particular issues with getty/login, add
|
||||||
the following to your Finit .conf file:
|
the following to your Finit .conf file:
|
||||||
|
|
||||||
@@ -175,6 +184,6 @@ it only for debugging start up issues when Finit crashes.
|
|||||||
systems since they can potentially give a user root access.
|
systems since they can potentially give a user root access.
|
||||||
|
|
||||||
|
|
||||||
[1]: ftp://troglobit.com/finit/finit-4.1.tar.gz
|
[1]: ftp://troglobit.com/finit/finit-4.3.tar.gz
|
||||||
[libuEv]: https://github.com/troglobit/libuev
|
[libuEv]: https://github.com/troglobit/libuev
|
||||||
[libite]: https://github.com/troglobit/libite
|
[libite]: https://github.com/troglobit/libite
|
||||||
|
|||||||
+13
-6
@@ -10,13 +10,13 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
|
|||||||
> parameters to init. E.g., `init=/sbin/finit -- finit.debug rescue`
|
> 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.
|
console until Finit starts up, unless `loglevel=7` (below) is used.
|
||||||
|
|
||||||
* `finit.debug[=bool]`: Enable finit debug. This is operated
|
* `finit.debug[=bool]`: Enable finit debug. This is operated
|
||||||
independently of the kernel debug setting. New as of Finit v4.
|
independently of the kernel `debug` setting. New as of Finit v4.
|
||||||
|
|
||||||
* `finit.show_status[=bool]`: Control finit boot progress, including
|
* `finit.status[=bool]`: Control finit boot progress, including banner.
|
||||||
banner.
|
(Used to be `finit.show_status`, which works but is deprecated.)
|
||||||
|
|
||||||
* `finit.status_style=<classic,modern>`: Set Finit boot progress style,
|
* `finit.status_style=<classic,modern>`: Set Finit boot progress style,
|
||||||
when enabled.
|
when enabled.
|
||||||
@@ -26,11 +26,18 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
|
|||||||
signals and has no job control. Recommend using, and modifying,
|
signals and has no job control. Recommend using, and modifying,
|
||||||
`rescue` mode instead.
|
`rescue` mode instead.
|
||||||
|
|
||||||
|
* `loglevel=<0-7>`, sets the kernel's log level, which is more granular
|
||||||
|
than `debug`. Also, when `loglevel=7`, Finit will *not disable*
|
||||||
|
kernel logs to the console. This is very useful when debugging the
|
||||||
|
kernel at system bring-up. Since `loglevel=7` is the same as `debug`
|
||||||
|
this means you have to use `quiet` for a quiet boot, until sysklogd
|
||||||
|
takes over logging of kernel events.
|
||||||
|
|
||||||
* `panic=SEC`: By default the kernel does not reboot after a kernel
|
* `panic=SEC`: By default the kernel does not reboot after a kernel
|
||||||
panic. This setting will cause a kernel reboot after SEC seconds.
|
panic. This setting will cause a kernel reboot after SEC seconds.
|
||||||
|
|
||||||
* `quiet`: Suppress kernel logging to console, except for warnings and
|
* `quiet`: Suppress kernel logging to console, except for warnings and
|
||||||
errors.
|
errors. Also, see `loglevel` and `quiet` above.
|
||||||
|
|
||||||
* `rescue`: Start rescue/maintenance mode. If your system comes with
|
* `rescue`: Start rescue/maintenance mode. If your system comes with
|
||||||
the bundled `sulogin` program (Finit, or from util-linux/Busybox),
|
the bundled `sulogin` program (Finit, or from util-linux/Busybox),
|
||||||
@@ -46,5 +53,5 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
|
|||||||
|
|
||||||
For more on kernel boot parameters, see the man page [bootparam(7)][].
|
For more on kernel boot parameters, see the man page [bootparam(7)][].
|
||||||
|
|
||||||
[config.md][]: config.md#rescue-mode
|
[config.md]: config.md#rescue-mode
|
||||||
[bootparam(7)]: https://www.man7.org/linux/man-pages/man7/bootparam.7.html
|
[bootparam(7)]: https://www.man7.org/linux/man-pages/man7/bootparam.7.html
|
||||||
|
|||||||
+17
-3
@@ -323,6 +323,10 @@ calls `init-script restart` on `initctl reload`. Similar to how
|
|||||||
|
|
||||||
Forking services started with `sysv` scripts can be monitored by Finit
|
Forking services started with `sysv` scripts can be monitored by Finit
|
||||||
by declaring the PID file to look for: `pid:!/path/to/pidfile.pid`.
|
by declaring the PID file to look for: `pid:!/path/to/pidfile.pid`.
|
||||||
|
Notice the leading `!`, it signifies Finit should not try to create the
|
||||||
|
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
|
||||||
|
option to run it in the foreground, more on this below in `service`.
|
||||||
|
|
||||||
> `<COND>` is described in the [Services](#services) section.
|
> `<COND>` is described in the [Services](#services) section.
|
||||||
|
|
||||||
@@ -344,9 +348,19 @@ prevent them from forking off a sub-process in the background. This is
|
|||||||
the most reliable way to monitor a service.
|
the most reliable way to monitor a service.
|
||||||
|
|
||||||
However, not all daemons support running in the foreground, or they may
|
However, not all daemons support running in the foreground, or they may
|
||||||
start logging to the foreground as well, these are called forking
|
start logging to the foreground as well, these are forking daemons and
|
||||||
services and are supported using the same syntax as forking `sysv`
|
are supported using the same syntax as forking `sysv` services, using
|
||||||
services, using the `pid:!/path/to/pidfile.pid` syntax.
|
the `pid:!/path/to/pidfile.pid` syntax. There is an alternative syntax
|
||||||
|
that may be more intuitive, where Finit can also guess the PID file
|
||||||
|
based on the daemon's command name:
|
||||||
|
|
||||||
|
service type:forking ntpd -- NTP daemon
|
||||||
|
|
||||||
|
This example lets BusyBox `ntpd` daemonize itself. Finit uses the
|
||||||
|
basename of the binary to guess the PID file to watch for the PID:
|
||||||
|
`/var/run/ntpd.pid`. If Finit guesses wrong, you have to submit the
|
||||||
|
full `pid:!/path/to/file.pid`.
|
||||||
|
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
|
|||||||
+6
-4
@@ -35,25 +35,27 @@ For your convenience a set of *optional* plugins are available:
|
|||||||
_Optional plugin._
|
_Optional plugin._
|
||||||
|
|
||||||
* *hotplug.so*: Setup and start either udev or mdev hotplug daemon, if
|
* *hotplug.so*: Setup and start either udev or mdev hotplug daemon, if
|
||||||
available.
|
available. Enabled by default.
|
||||||
|
|
||||||
* *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.
|
||||||
|
|
||||||
* *modules-load.so*: Scans /etc/modules-load.d for modules to modprobe.
|
* *modules-load.so*: Scans /etc/modules-load.d for modules to modprobe.
|
||||||
|
|
||||||
* *netlink.so*: Listens to Linux kernel Netlink events for gateway and
|
* *netlink.so*: Listens to Linux kernel Netlink events for gateway and
|
||||||
interfaces. These events are then sent to the Finit service monitor
|
interfaces. These events are then sent to the Finit service monitor
|
||||||
for services that may want to be SIGHUP'ed on new default route or
|
for services that may want to be SIGHUP'ed on new default route or
|
||||||
interfaces going up/down.
|
interfaces going up/down. Enabled by default.
|
||||||
|
|
||||||
* *resolvconf.so*: Setup necessary files for `resolvconf` at startup.
|
* *resolvconf.so*: Setup necessary files for `resolvconf` at startup.
|
||||||
_Optional plugin._
|
_Optional plugin._
|
||||||
|
|
||||||
* *tty.so*: Watches `/dev`, using inotify, for new device nodes (TTY's)
|
* *tty.so*: Watches `/dev`, using inotify, for new device nodes (TTY's)
|
||||||
to start/stop getty consoles on them on demand. Useful when plugging
|
to start/stop getty consoles on them on demand. Useful when plugging
|
||||||
in a usb2serial converter to login to your embedded device.
|
in a usb2serial converter to login to your embedded device. Enabled
|
||||||
|
by default.
|
||||||
|
|
||||||
* *urandom.so*: Setup random seed at startup.
|
* *urandom.so*: Setup random seed at startup. Enabled by default.
|
||||||
|
|
||||||
* *x11-common.so*: Setup necessary files for X-Window. _Optional plugin._
|
* *x11-common.so*: Setup necessary files for X-Window. _Optional plugin._
|
||||||
|
|
||||||
|
|||||||
+11
-1
@@ -27,7 +27,17 @@ Finit can *not* start and monitor a daemon that:
|
|||||||
|
|
||||||
### Forks to Background w/ PID File
|
### Forks to Background w/ PID File
|
||||||
|
|
||||||
service pid:!/run/serv.pid serv -- Forking service
|
There are two syntax variants, type 1 and type 2. The former is the
|
||||||
|
traditional one used also for `sysv` start/stop scripts, and the latter
|
||||||
|
is inspired by systemd, with a twist -- it lets Finit guess the pifdile
|
||||||
|
to look for based on the standard path and the basename of the command.
|
||||||
|
|
||||||
|
service pid:!/run/serv.pid serv -- Forking service, type 1
|
||||||
|
service type:forking serv -- Forking service, type 2
|
||||||
|
|
||||||
|
In this example the resulting files to watch for are `/run/serv.pid` and
|
||||||
|
`/var/run/serv.pid`, respectively. On most modern Linux systems this is
|
||||||
|
the same directory (`/var/run` is a symlink to `../run`).
|
||||||
|
|
||||||
### Runs in Foreground w/ PID File
|
### Runs in Foreground w/ PID File
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -11,8 +11,9 @@
|
|||||||
.Nd Fast init for Linux systems
|
.Nd Fast init for Linux systems
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm /sbin/finit
|
.Nm /sbin/finit
|
||||||
.Op finit.status_style=classic
|
.Op --
|
||||||
.Op finit.show_status=[on,off]
|
.Op finit.status=[on,off]
|
||||||
|
.Op finit.status_style=[classic,modern]
|
||||||
.Op finit.debug
|
.Op finit.debug
|
||||||
.Op rescue | recover
|
.Op rescue | recover
|
||||||
.Op single | S
|
.Op single | S
|
||||||
|
|||||||
+15
-1
@@ -194,7 +194,21 @@ services and are supported using the same syntax as forking
|
|||||||
.Cm sysv
|
.Cm sysv
|
||||||
services, using the
|
services, using the
|
||||||
.Cm pid:!/path/to/pidfile.pid
|
.Cm pid:!/path/to/pidfile.pid
|
||||||
command modifier syntax.
|
command modifier syntax. There is an alternative syntax that may be
|
||||||
|
more intuitive, where Finit can also guess the PID file based on the
|
||||||
|
daemon's command name:
|
||||||
|
.Bd -unfilled -offset indent
|
||||||
|
service type:forking ntpd -- NTP daemon
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Here we let BusyBox
|
||||||
|
.Nm ntpd
|
||||||
|
daemonize itself. Finit uses the basename of the binary to guess the
|
||||||
|
PID file to watch for the PID:
|
||||||
|
.Pa /var/run/ntpd.pid .
|
||||||
|
If Finit guesses wrong, you have to submit the full
|
||||||
|
.Cm pid:!/path/to/file.pid
|
||||||
|
option to your service stanza.
|
||||||
.Pp
|
.Pp
|
||||||
.Sy Example: in the case of
|
.Sy Example: in the case of
|
||||||
.Cm ospfd
|
.Cm ospfd
|
||||||
|
|||||||
+1
-1
@@ -135,7 +135,7 @@ static void setup(void *arg)
|
|||||||
ln("/dev/shm", "/run/shm");
|
ln("/dev/shm", "/run/shm");
|
||||||
|
|
||||||
/* compat only, should really be set up by OS/dist */
|
/* compat only, should really be set up by OS/dist */
|
||||||
ln("../run", "/var/run");
|
ln("/run", "/var/run");
|
||||||
} else {
|
} else {
|
||||||
makedir("/var/lock", 1777);
|
makedir("/var/lock", 1777);
|
||||||
makedir("/var/run", 0755);
|
makedir("/var/run", 0755);
|
||||||
|
|||||||
+3
-1
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
/* Netlink plugin for IFUP/IFDN and GW events
|
/* Netlink plugin for IFUP/IFDN and GW events
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009-2011 Mårten Wikström <marten.wikstrom@keystream.se>
|
* Copyright (C) 2009-2011 Mårten Wikström <marten.wikstrom@keystream.se>
|
||||||
@@ -252,7 +253,7 @@ static int nl_parse(int sd)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("recv %lld bytes", len);
|
_d("recv %zd bytes", len);
|
||||||
l = (size_t)len;
|
l = (size_t)len;
|
||||||
for (nh = (struct nlmsghdr *)nl_buf; NLMSG_OK(nh, l); nh = NLMSG_NEXT(nh, l)) {
|
for (nh = (struct nlmsghdr *)nl_buf; NLMSG_OK(nh, l); nh = NLMSG_NEXT(nh, l)) {
|
||||||
struct nlmsgerr *nle;
|
struct nlmsgerr *nle;
|
||||||
@@ -449,6 +450,7 @@ PLUGIN_INIT(plugin_init)
|
|||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(plugin_exit)
|
||||||
{
|
{
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
|
close(plugin.io.fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+1
-1
@@ -305,8 +305,8 @@ PLUGIN_INIT(plugin_init)
|
|||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(plugin_exit)
|
||||||
{
|
{
|
||||||
iwatch_exit(&iw_pidfile);
|
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
|
iwatch_exit(&iw_pidfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+1
-5
@@ -160,23 +160,19 @@ static void sys_init(void *arg)
|
|||||||
char sysdir[MAX_ARG_LEN];
|
char sysdir[MAX_ARG_LEN];
|
||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
_d("Calling mkpath() on sys conds");
|
|
||||||
if (mkpath(pid_runpath(_PATH_CONDSYS, sysdir, sizeof(sysdir)), 0755) && errno != EEXIST) {
|
if (mkpath(pid_runpath(_PATH_CONDSYS, sysdir, sizeof(sysdir)), 0755) && errno != EEXIST) {
|
||||||
_pe("Failed creating %s condition directory, %s", COND_SYS, _PATH_CONDSYS);
|
_pe("Failed creating %s condition directory, %s", COND_SYS, _PATH_CONDSYS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("Calling realpth() on condsys");
|
|
||||||
path = realpath(_PATH_CONDSYS, NULL);
|
path = realpath(_PATH_CONDSYS, NULL);
|
||||||
if (!path) {
|
if (!path) {
|
||||||
_pe("Cannot figure out real path to %s, aborting", _PATH_CONDSYS);
|
_pe("Cannot figure out real path to %s, aborting", _PATH_CONDSYS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("Calling iwatch_add()");
|
|
||||||
if (iwatch_add(&iw_sys, path, IN_ONLYDIR))
|
if (iwatch_add(&iw_sys, path, IN_ONLYDIR))
|
||||||
iwatch_exit(&iw_sys);
|
iwatch_exit(&iw_sys);
|
||||||
_d("Done.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
@@ -201,8 +197,8 @@ PLUGIN_INIT(plugin_init)
|
|||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(plugin_exit)
|
||||||
{
|
{
|
||||||
iwatch_exit(&iw_sys);
|
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
|
iwatch_exit(&iw_sys);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+1
-2
@@ -116,10 +116,9 @@ PLUGIN_INIT(plugin_init)
|
|||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(plugin_exit)
|
||||||
{
|
{
|
||||||
|
plugin_unregister(&plugin);
|
||||||
if (plugin.io.fd)
|
if (plugin.io.fd)
|
||||||
close(plugin.io.fd);
|
close(plugin.io.fd);
|
||||||
|
|
||||||
plugin_unregister(&plugin);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+1
-1
@@ -123,8 +123,8 @@ PLUGIN_INIT(plugin_init)
|
|||||||
|
|
||||||
PLUGIN_EXIT(plugin_exit)
|
PLUGIN_EXIT(plugin_exit)
|
||||||
{
|
{
|
||||||
iwatch_exit(&iw_usr);
|
|
||||||
plugin_unregister(&plugin);
|
plugin_unregister(&plugin);
|
||||||
|
iwatch_exit(&iw_usr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -250,10 +250,10 @@ static int do_reboot(int cmd, char *buf, size_t len)
|
|||||||
case INIT_CMD_SUSPEND:
|
case INIT_CMD_SUSPEND:
|
||||||
_d("suspend");
|
_d("suspend");
|
||||||
sync();
|
sync();
|
||||||
rc = reboot(RB_SW_SUSPEND);
|
rc = suspend();
|
||||||
if (rc) {
|
if (rc) {
|
||||||
if (errno == EINVAL)
|
if (errno == EINVAL)
|
||||||
snprintf(buf, len, "Kernel does not support suspend.");
|
snprintf(buf, len, "Kernel does not support suspend to RAM.");
|
||||||
else
|
else
|
||||||
snprintf(buf, len, "Failed: %s", strerror(errno));
|
snprintf(buf, len, "Failed: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -526,7 +526,7 @@ void cgroup_init(uev_ctx_t *ctx)
|
|||||||
|
|
||||||
/* Move ourselves to init (best effort, otherwise run in 'root' group */
|
/* Move ourselves to init (best effort, otherwise run in 'root' group */
|
||||||
if (fnwrite("1", FINIT_CGPATH "/init/cgroup.procs")) {
|
if (fnwrite("1", FINIT_CGPATH "/init/cgroup.procs")) {
|
||||||
_pe("Failed moving PID 1 to cgroup ", FINIT_CGPATH "/init");
|
_pe("Failed moving PID 1 to cgroup %s", FINIT_CGPATH "/init");
|
||||||
uev_io_stop(&cgw);
|
uev_io_stop(&cgw);
|
||||||
iwatch_exit(&iw_cgroup);
|
iwatch_exit(&iw_cgroup);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|||||||
+3
-5
@@ -86,8 +86,8 @@ fallback:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* finit.debug = [on,off]
|
* finit.debug = [on,off]
|
||||||
* finit.show_status = [on,off]
|
* finit.status = [on,off] (compat finit.show_status)
|
||||||
* finit.status_style = [old,classic,modern]
|
* finit.status_style = [old,classic,modern]
|
||||||
*/
|
*/
|
||||||
static void parse_finit_opts(char *opt)
|
static void parse_finit_opts(char *opt)
|
||||||
@@ -116,7 +116,7 @@ static void parse_finit_opts(char *opt)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string_compare(opt, "show_status")) {
|
if (string_compare(opt, "status") || string_compare(opt, "show_status")) {
|
||||||
show_progress(get_bool(arg, 1) ? PROGRESS_DEFAULT : PROGRESS_SILENT);
|
show_progress(get_bool(arg, 1) ? PROGRESS_DEFAULT : PROGRESS_SILENT);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -205,8 +205,6 @@ void conf_parse_cmdline(int argc, char *argv[])
|
|||||||
|
|
||||||
parse_kernel_cmdline();
|
parse_kernel_cmdline();
|
||||||
parse_kernel_loglevel();
|
parse_kernel_loglevel();
|
||||||
|
|
||||||
log_init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int kmod_exists(char *mod)
|
static int kmod_exists(char *mod)
|
||||||
|
|||||||
+4
-2
@@ -97,12 +97,14 @@ static int do_redirect(void)
|
|||||||
*/
|
*/
|
||||||
int run(char *cmd, char *log)
|
int run(char *cmd, char *log)
|
||||||
{
|
{
|
||||||
|
char *args[NUM_ARGS + 1] = { 0 };
|
||||||
int status, result, i = 0;
|
int status, result, i = 0;
|
||||||
char *args[NUM_ARGS + 1], *arg;
|
|
||||||
char *backup = NULL;
|
char *backup = NULL;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
if (!log) {
|
if (!log) {
|
||||||
|
char *arg;
|
||||||
|
|
||||||
/* We must create a copy that is possible to modify. */
|
/* We must create a copy that is possible to modify. */
|
||||||
backup = arg = strdup(cmd);
|
backup = arg = strdup(cmd);
|
||||||
if (!arg)
|
if (!arg)
|
||||||
@@ -164,7 +166,7 @@ int run(char *cmd, char *log)
|
|||||||
|
|
||||||
_exit(rc);
|
_exit(rc);
|
||||||
} else if (-1 == pid) {
|
} else if (-1 == pid) {
|
||||||
_pe("%s", args[0]);
|
_pe("%s", !log ? args[0] : cmd);
|
||||||
if (backup)
|
if (backup)
|
||||||
free(backup);
|
free(backup);
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -334,7 +334,7 @@ static void fs_mount_all(void)
|
|||||||
plugin_run_hooks(HOOK_MOUNT_POST);
|
plugin_run_hooks(HOOK_MOUNT_POST);
|
||||||
|
|
||||||
if (whichp("swapon"))
|
if (whichp("swapon"))
|
||||||
run("swapon -ea", "swapon");
|
run_interactive("swapon -ea", "Enabling system swap");
|
||||||
|
|
||||||
_d("Finalize, ensure common file systems are available ...");
|
_d("Finalize, ensure common file systems are available ...");
|
||||||
fs_finalize();
|
fs_finalize();
|
||||||
@@ -570,7 +570,7 @@ int main(int argc, char *argv[])
|
|||||||
};
|
};
|
||||||
uev_ctx_t loop;
|
uev_ctx_t loop;
|
||||||
|
|
||||||
/* telinit or stand-alone process monitor */
|
/* user calling telinit or init */
|
||||||
if (getpid() != 1)
|
if (getpid() != 1)
|
||||||
return telinit(argc, argv);
|
return telinit(argc, argv);
|
||||||
|
|
||||||
@@ -581,12 +581,12 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse /proc/cmdline (debug, rescue, console=, etc.)
|
* Parse /proc/cmdline (debug, rescue, console=, etc.)
|
||||||
* Also calls log_init() to set correct log level
|
|
||||||
*/
|
*/
|
||||||
conf_parse_cmdline(argc, argv);
|
conf_parse_cmdline(argc, argv);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Figure out system console(s)
|
* Figure out system console(s) and call log_init() to set
|
||||||
|
* correct log level, possibly finit.debug enabled.
|
||||||
*/
|
*/
|
||||||
console_init();
|
console_init();
|
||||||
|
|
||||||
|
|||||||
+14
-8
@@ -81,7 +81,7 @@ char *console(void)
|
|||||||
|
|
||||||
void console_init(void)
|
void console_init(void)
|
||||||
{
|
{
|
||||||
ttinit();
|
log_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t cprintf(const char *fmt, ...)
|
ssize_t cprintf(const char *fmt, ...)
|
||||||
@@ -500,20 +500,25 @@ void networking(int updown)
|
|||||||
if (fexist("/etc/network/interfaces")) {
|
if (fexist("/etc/network/interfaces")) {
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
if (!updown) {
|
|
||||||
run_interactive("ifdown -a", "Stopping networking");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
int rc = EX_OSERR;
|
int rc = EX_OSERR;
|
||||||
|
const char *cmd;
|
||||||
FILE *pp;
|
FILE *pp;
|
||||||
|
|
||||||
setsid();
|
setsid();
|
||||||
sig_unblock();
|
sig_unblock();
|
||||||
|
|
||||||
pp = popen("ifup -a 2>&1", "r");
|
if (updown)
|
||||||
|
cmd = "ifup -a 2>&1";
|
||||||
|
else if (whichp("ifquery"))
|
||||||
|
/* Regular ifodwn supports --force but not -f */
|
||||||
|
cmd = "ifdown -a --force 2>&1";
|
||||||
|
else
|
||||||
|
/* Busybox ifdown support -f, but not --force */
|
||||||
|
cmd = "ifdown -a -f 2>&1";
|
||||||
|
|
||||||
|
pp = popen(cmd, "r");
|
||||||
if (pp) {
|
if (pp) {
|
||||||
char buf[256];
|
char buf[256];
|
||||||
|
|
||||||
@@ -526,7 +531,8 @@ void networking(int updown)
|
|||||||
_exit(rc);
|
_exit(rc);
|
||||||
}
|
}
|
||||||
cgroup_service("network", pid, NULL);
|
cgroup_service("network", pid, NULL);
|
||||||
print(pid > 0 ? 0 : 1, "Bringing up network interfaces ...");
|
print(pid > 0 ? 0 : 1, "%s network interfaces ...",
|
||||||
|
updown ? "Bringing up" : "Taking down");
|
||||||
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -65,7 +65,7 @@ struct fstab *getfsent (void);
|
|||||||
|
|
||||||
char *console (void);
|
char *console (void);
|
||||||
void console_init (void);
|
void console_init (void);
|
||||||
ssize_t cprintf (const char *fmt, ...);
|
ssize_t cprintf (const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
||||||
|
|
||||||
char *strip_line (char *line);
|
char *strip_line (char *line);
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ void stty (int fd, speed_t speed);
|
|||||||
|
|
||||||
void print_banner (const char *heading);
|
void print_banner (const char *heading);
|
||||||
void printv (const char *fmt, va_list ap);
|
void printv (const char *fmt, va_list ap);
|
||||||
void print (int action, const char *fmt, ...);
|
void print (int action, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
void print_desc (char *action, char *desc);
|
void print_desc (char *action, char *desc);
|
||||||
int print_result (int fail);
|
int print_result (int fail);
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ int in_container (void);
|
|||||||
|
|
||||||
int complete (char *cmd, int pid);
|
int complete (char *cmd, int pid);
|
||||||
int run (char *cmd, char *log);
|
int run (char *cmd, char *log);
|
||||||
int run_interactive (char *cmd, char *fmt, ...);
|
int run_interactive (char *cmd, char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
int exec_runtask (char *cmd, char *args[]);
|
int exec_runtask (char *cmd, char *args[]);
|
||||||
pid_t run_getty (char *tty, char *cmd, char *args[], int noclear, int nowait, struct rlimit rlimit[]);
|
pid_t run_getty (char *tty, char *cmd, char *args[], int noclear, int nowait, struct rlimit rlimit[]);
|
||||||
pid_t run_sh (char *tty, int noclear, int nowait, struct rlimit rlimit[]);
|
pid_t run_sh (char *tty, int noclear, int nowait, struct rlimit rlimit[]);
|
||||||
|
|||||||
+1
-1
@@ -34,7 +34,7 @@ extern int heading; /* initctl -t */
|
|||||||
extern int verbose; /* initctl -v */
|
extern int verbose; /* initctl -v */
|
||||||
extern int plain; /* initctl -p */
|
extern int plain; /* initctl -p */
|
||||||
|
|
||||||
extern void print_header(const char *fmt, ...);
|
extern void print_header(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
||||||
|
|
||||||
#endif /* FINIT_INITCTL_H_ */
|
#endif /* FINIT_INITCTL_H_ */
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -62,8 +62,10 @@ int iwatch_init(struct iwatch *iw)
|
|||||||
* reconf of systems with lots of services.
|
* reconf of systems with lots of services.
|
||||||
*/
|
*/
|
||||||
len = sizeof(sz);
|
len = sizeof(sz);
|
||||||
if (!getsockopt(iw->fd, SOL_SOCKET, SO_RCVBUF, &sz, &len))
|
if (!getsockopt(iw->fd, SOL_SOCKET, SO_RCVBUF, &sz, &len)) {
|
||||||
setsockopt(iw->fd, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz));
|
if (setsockopt(iw->fd, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)))
|
||||||
|
_pe("Failed increasing size of inotify socket");
|
||||||
|
}
|
||||||
|
|
||||||
initialized = 1;
|
initialized = 1;
|
||||||
|
|
||||||
|
|||||||
+41
-5
@@ -24,6 +24,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
@@ -52,6 +53,10 @@
|
|||||||
static int num_ac_online;
|
static int num_ac_online;
|
||||||
static int num_ac;
|
static int num_ac;
|
||||||
|
|
||||||
|
static int running = 1;
|
||||||
|
static int level;
|
||||||
|
static int logon;
|
||||||
|
|
||||||
int debug; /* debug in other modules as well */
|
int debug; /* debug in other modules as well */
|
||||||
|
|
||||||
void logit(int prio, const char *fmt, ...)
|
void logit(int prio, const char *fmt, ...)
|
||||||
@@ -59,9 +64,9 @@ void logit(int prio, const char *fmt, ...)
|
|||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
if (!debug)
|
if (logon)
|
||||||
vsyslog(prio, fmt, ap);
|
vsyslog(prio, fmt, ap);
|
||||||
else {
|
else if (prio <= level) {
|
||||||
vfprintf(stderr, fmt, ap);
|
vfprintf(stderr, fmt, ap);
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
}
|
}
|
||||||
@@ -179,6 +184,26 @@ static void init(void)
|
|||||||
sys_cond("pwr/ac", 1);
|
sys_cond("pwr/ac", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void set_logging(int prio)
|
||||||
|
{
|
||||||
|
setlogmask(LOG_UPTO(prio));
|
||||||
|
level = prio;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void toggle_debug(int signo)
|
||||||
|
{
|
||||||
|
(void)signo;
|
||||||
|
|
||||||
|
debug ^= 1;
|
||||||
|
set_logging(debug ? LOG_DEBUG : LOG_NOTICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void shut_down(int signo)
|
||||||
|
{
|
||||||
|
(void)signo;
|
||||||
|
running = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Started by Finit as soon as possible when base filesystem is up,
|
* Started by Finit as soon as possible when base filesystem is up,
|
||||||
* modules have been probed, or insmodded from /etc/finit.conf, so by
|
* modules have been probed, or insmodded from /etc/finit.conf, so by
|
||||||
@@ -198,10 +223,13 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!debug) {
|
if (!debug) {
|
||||||
openlog("keventd", LOG_CONS | LOG_PID, LOG_DAEMON);
|
openlog("keventd", LOG_PID, LOG_DAEMON);
|
||||||
setlogmask(LOG_UPTO(LOG_NOTICE));
|
set_logging(LOG_NOTICE);
|
||||||
|
logon = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signal(SIGUSR1, toggle_debug);
|
||||||
|
signal(SIGTERM, shut_down);
|
||||||
init();
|
init();
|
||||||
|
|
||||||
pfd.events = POLLIN;
|
pfd.events = POLLIN;
|
||||||
@@ -216,11 +244,18 @@ int main(int argc, char *argv[])
|
|||||||
panic("bind failed");
|
panic("bind failed");
|
||||||
|
|
||||||
logit(LOG_DEBUG, "Waiting for events ...");
|
logit(LOG_DEBUG, "Waiting for events ...");
|
||||||
while (-1 != poll(&pfd, 1, -1)) {
|
while (running) {
|
||||||
char *path = NULL;
|
char *path = NULL;
|
||||||
int ac = 0;
|
int ac = 0;
|
||||||
int i, len;
|
int i, len;
|
||||||
|
|
||||||
|
if (-1 == poll(&pfd, 1, -1)) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
len = recv(pfd.fd, buf, sizeof(buf), MSG_DONTWAIT);
|
len = recv(pfd.fd, buf, sizeof(buf), MSG_DONTWAIT);
|
||||||
if (len == -1) {
|
if (len == -1) {
|
||||||
switch (errno) {
|
switch (errno) {
|
||||||
@@ -235,6 +270,7 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf[len] = 0;
|
buf[len] = 0;
|
||||||
|
logit(LOG_DEBUG, "%s", buf);
|
||||||
|
|
||||||
/* skip libusb events, focus on kernel events/changes */
|
/* skip libusb events, focus on kernel events/changes */
|
||||||
if (strncmp(buf, "change@", 7))
|
if (strncmp(buf, "change@", 7))
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ static int loglevel = LOG_INFO;
|
|||||||
|
|
||||||
void log_init(void)
|
void log_init(void)
|
||||||
{
|
{
|
||||||
|
ttinit();
|
||||||
|
|
||||||
if (debug)
|
if (debug)
|
||||||
loglevel = LOG_DEBUG;
|
loglevel = LOG_DEBUG;
|
||||||
else
|
else
|
||||||
@@ -72,24 +74,25 @@ static int log_open(void)
|
|||||||
if (debug)
|
if (debug)
|
||||||
opts |= LOG_PERROR;
|
opts |= LOG_PERROR;
|
||||||
|
|
||||||
closelog();
|
|
||||||
openlog("finit", opts, LOG_DAEMON);
|
openlog("finit", opts, LOG_DAEMON);
|
||||||
setlogmask(LOG_UPTO(loglevel));
|
setlogmask(LOG_UPTO(loglevel));
|
||||||
|
|
||||||
return up = 1;
|
return up = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void log_close(void)
|
||||||
|
{
|
||||||
|
closelog();
|
||||||
|
up = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Toggle debug mode */
|
/* Toggle debug mode */
|
||||||
void log_debug(void)
|
void log_debug(void)
|
||||||
{
|
{
|
||||||
debug = !debug;
|
debug = !debug;
|
||||||
|
|
||||||
if (debug) {
|
log_close();
|
||||||
loglevel = LOG_DEBUG;
|
log_init();
|
||||||
} else {
|
|
||||||
loglevel = LOG_NOTICE;
|
|
||||||
ttinit();
|
|
||||||
}
|
|
||||||
log_open();
|
log_open();
|
||||||
|
|
||||||
logit(LOG_NOTICE, "Debug mode %s", debug ? "enabled" : "disabled");
|
logit(LOG_NOTICE, "Debug mode %s", debug ? "enabled" : "disabled");
|
||||||
|
|||||||
@@ -43,14 +43,14 @@
|
|||||||
#define _d(fmt, args...) logit(LOG_DEBUG, "%s():" fmt, __func__, ##args)
|
#define _d(fmt, args...) logit(LOG_DEBUG, "%s():" fmt, __func__, ##args)
|
||||||
#define _w(fmt, args...) logit(LOG_WARNING, "%s():" fmt, __func__, ##args)
|
#define _w(fmt, args...) logit(LOG_WARNING, "%s():" fmt, __func__, ##args)
|
||||||
#define _e(fmt, args...) logit(LOG_ERR, "%s():" fmt, __func__, ##args)
|
#define _e(fmt, args...) logit(LOG_ERR, "%s():" fmt, __func__, ##args)
|
||||||
#define _pe(fmt, args...) logit(LOG_ERR, "%s():" fmt ": %n", __func__, ##args, strerror(errno))
|
#define _pe(fmt, args...) logit(LOG_ERR, "%s():" fmt ": %s", __func__, ##args, strerror(errno))
|
||||||
|
|
||||||
void log_init (void);
|
void log_init (void);
|
||||||
void log_exit (void);
|
void log_exit (void);
|
||||||
|
|
||||||
void log_debug (void);
|
void log_debug (void);
|
||||||
|
|
||||||
void logit (int prio, const char *fmt, ...);
|
void logit (int prio, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
void flog (char *file, const char *fmt, ...);
|
void flog (char *file, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
|
|
||||||
#endif /* FINIT_LOG_H_ */
|
#endif /* FINIT_LOG_H_ */
|
||||||
|
|||||||
+19
-2
@@ -21,10 +21,13 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <mntent.h>
|
#include <mntent.h>
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
|
|
||||||
|
#include "helpers.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SysV init on Debian/Ubuntu skips these protected mount points
|
* SysV init on Debian/Ubuntu skips these protected mount points
|
||||||
*
|
*
|
||||||
@@ -86,13 +89,27 @@ static struct mntent *iterator(char *fstab, FILE **fp)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int unmount(const char *target)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = umount(target);
|
||||||
|
if (rc && errno != EBUSY) {
|
||||||
|
print(2, "Failed unmounting %s, error %d: %s", target, errno, strerror(errno));
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
print(0, "Unmounting %s", target);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void unmount_tmpfs(void)
|
void unmount_tmpfs(void)
|
||||||
{
|
{
|
||||||
struct mntent *mnt;
|
struct mntent *mnt;
|
||||||
FILE *fp = NULL;
|
FILE *fp = NULL;
|
||||||
|
|
||||||
while ((mnt = iterator("/proc/mounts", &fp))) {
|
while ((mnt = iterator("/proc/mounts", &fp))) {
|
||||||
if (!strcmp("tmpfs", mnt->mnt_fsname) && !umount(mnt->mnt_dir))
|
if (!strcmp("tmpfs", mnt->mnt_fsname) && !unmount(mnt->mnt_dir))
|
||||||
iterator_end(&fp); /* Restart iteration */
|
iterator_end(&fp); /* Restart iteration */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,7 +120,7 @@ void unmount_regular(void)
|
|||||||
FILE *fp = NULL;
|
FILE *fp = NULL;
|
||||||
|
|
||||||
while ((mnt = iterator("/proc/mounts", &fp))) {
|
while ((mnt = iterator("/proc/mounts", &fp))) {
|
||||||
if (!umount(mnt->mnt_dir))
|
if (!unmount(mnt->mnt_dir))
|
||||||
iterator_end(&fp); /* Restart iteration */
|
iterator_end(&fp); /* Restart iteration */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,10 +69,11 @@ int pid_alive(pid_t pid)
|
|||||||
*/
|
*/
|
||||||
char *pid_get_name(pid_t pid, char *name, size_t len)
|
char *pid_get_name(pid_t pid, char *name, size_t len)
|
||||||
{
|
{
|
||||||
|
static char line[64];
|
||||||
|
char *pname = NULL;
|
||||||
|
char path[32];
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
char *pname, path[32];
|
|
||||||
static char line[64];
|
|
||||||
|
|
||||||
snprintf(path, sizeof(path), "/proc/%d/status", pid);
|
snprintf(path, sizeof(path), "/proc/%d/status", pid);
|
||||||
fp = fopen(path, "r");
|
fp = fopen(path, "r");
|
||||||
@@ -113,8 +114,8 @@ char *pid_file(svc_t *svc)
|
|||||||
pid_t pid_file_read(const char *fn)
|
pid_t pid_file_read(const char *fn)
|
||||||
{
|
{
|
||||||
pid_t pid = 0;
|
pid_t pid = 0;
|
||||||
FILE *fp;
|
|
||||||
char buf[42];
|
char buf[42];
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
fp = fopen(fn, "r");
|
fp = fopen(fn, "r");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
@@ -157,6 +158,11 @@ int pid_file_set(svc_t *svc, char *file, int not)
|
|||||||
file++;
|
file++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (svc_is_forking(svc) && !not) {
|
||||||
|
logit(LOG_WARNING, "Service %s is forking, adjusting to pid:!%s", svc->name, file);
|
||||||
|
not = 1;
|
||||||
|
}
|
||||||
|
|
||||||
pid_runpath(file, &svc->pidfile[not], sizeof(svc->pidfile) - not);
|
pid_runpath(file, &svc->pidfile[not], sizeof(svc->pidfile) - not);
|
||||||
if (not)
|
if (not)
|
||||||
svc->pidfile[0] = '!';
|
svc->pidfile[0] = '!';
|
||||||
@@ -199,8 +205,8 @@ int pid_file_parse(svc_t *svc, char *arg)
|
|||||||
|
|
||||||
/* 'pid:' implies argument following*/
|
/* 'pid:' implies argument following*/
|
||||||
if (!strncmp(arg, "pid:", 4)) {
|
if (!strncmp(arg, "pid:", 4)) {
|
||||||
int len, not = 0;
|
|
||||||
char path[MAX_ARG_LEN];
|
char path[MAX_ARG_LEN];
|
||||||
|
int len, not = 0;
|
||||||
|
|
||||||
arg += 4;
|
arg += 4;
|
||||||
if ((arg[0] == '!' && arg[1] == '/') || arg[0] == '/')
|
if ((arg[0] == '!' && arg[1] == '/') || arg[0] == '/')
|
||||||
|
|||||||
+4
-2
@@ -160,6 +160,8 @@ int reboot_main(int argc, char *argv[])
|
|||||||
transform(NULL);
|
transform(NULL);
|
||||||
|
|
||||||
if (force) {
|
if (force) {
|
||||||
|
sync();
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case CMD_REBOOT:
|
case CMD_REBOOT:
|
||||||
c = reboot(RB_AUTOBOOT);
|
c = reboot(RB_AUTOBOOT);
|
||||||
@@ -174,9 +176,9 @@ int reboot_main(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CMD_SUSPEND:
|
case CMD_SUSPEND:
|
||||||
c = reboot(RB_SW_SUSPEND);
|
c = suspend();
|
||||||
if (c && errno == EINVAL)
|
if (c && errno == EINVAL)
|
||||||
errx(1, "Kernel does not support suspend.");
|
errx(1, "Kernel does not support suspend to RAM.");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMD_UNKNOWN:
|
case CMD_UNKNOWN:
|
||||||
|
|||||||
+31
-1
@@ -34,9 +34,24 @@
|
|||||||
# include <lite/lite.h>
|
# include <lite/lite.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "client.h"
|
||||||
#include "initctl.h"
|
#include "initctl.h"
|
||||||
|
|
||||||
|
|
||||||
|
static int is_builtin(char *arg)
|
||||||
|
{
|
||||||
|
svc_t *svc;
|
||||||
|
|
||||||
|
svc = client_svc_find(arg);
|
||||||
|
if (!svc)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (svc->file[0])
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int calc_width(char *arr[], size_t len)
|
static int calc_width(char *arr[], size_t len)
|
||||||
{
|
{
|
||||||
int width = 0;
|
int width = 0;
|
||||||
@@ -292,6 +307,8 @@ int serv_touch(char *arg)
|
|||||||
if (!fexist(fn)) {
|
if (!fexist(fn)) {
|
||||||
if (!strstr(arg, "finit.conf"))
|
if (!strstr(arg, "finit.conf"))
|
||||||
errx(1, "%s not available.", arg);
|
errx(1, "%s not available.", arg);
|
||||||
|
if (is_builtin(arg))
|
||||||
|
errx(1, "%s is a built-in service.", arg);
|
||||||
|
|
||||||
strlcpy(path, FINIT_CONF, sizeof(path));
|
strlcpy(path, FINIT_CONF, sizeof(path));
|
||||||
fn = path;
|
fn = path;
|
||||||
@@ -311,6 +328,9 @@ int serv_show(char *arg)
|
|||||||
|
|
||||||
fn = conf(path, sizeof(path), arg, 0);
|
fn = conf(path, sizeof(path), arg, 0);
|
||||||
if (!fexist(fn)) {
|
if (!fexist(fn)) {
|
||||||
|
if (is_builtin(arg))
|
||||||
|
errx(1, "%s is a built-in service.", arg);
|
||||||
|
|
||||||
warnx("Cannot find %s", arg);
|
warnx("Cannot find %s", arg);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -345,6 +365,9 @@ static int do_edit(char *arg, int creat)
|
|||||||
|
|
||||||
fn = conf(path, sizeof(path), arg, creat);
|
fn = conf(path, sizeof(path), arg, creat);
|
||||||
if (!fexist(fn)) {
|
if (!fexist(fn)) {
|
||||||
|
if (is_builtin(arg))
|
||||||
|
errx(1, "%s is a built-in service.", arg);
|
||||||
|
|
||||||
if (!creat) {
|
if (!creat) {
|
||||||
warnx("Cannot find %s, use -c flag, create command, or select one of:", arg);
|
warnx("Cannot find %s, use -c flag, create command, or select one of:", arg);
|
||||||
return serv_list(NULL);
|
return serv_list(NULL);
|
||||||
@@ -371,6 +394,7 @@ int serv_edit(char *arg)
|
|||||||
if (!arg || !arg[0]) {
|
if (!arg || !arg[0]) {
|
||||||
if (!yorn("Do you want to edit %s (y/N)? ", FINIT_CONF))
|
if (!yorn("Do you want to edit %s (y/N)? ", FINIT_CONF))
|
||||||
return 0;
|
return 0;
|
||||||
|
arg = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
return do_edit(arg, icreate);
|
return do_edit(arg, icreate);
|
||||||
@@ -385,6 +409,9 @@ int serv_creat(char *arg)
|
|||||||
if (!arg || !arg[0])
|
if (!arg || !arg[0])
|
||||||
errx(1, "missing argument to create");
|
errx(1, "missing argument to create");
|
||||||
|
|
||||||
|
if (is_builtin(arg))
|
||||||
|
errx(1, "%s is a built-in service.", arg);
|
||||||
|
|
||||||
/* Input from a pipe or a proper TTY? */
|
/* Input from a pipe or a proper TTY? */
|
||||||
if (isatty(STDIN_FILENO))
|
if (isatty(STDIN_FILENO))
|
||||||
return do_edit(arg, 1);
|
return do_edit(arg, 1);
|
||||||
@@ -420,8 +447,11 @@ int serv_delete(char *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn = conf(buf, sizeof(buf), arg, 0);
|
fn = conf(buf, sizeof(buf), arg, 0);
|
||||||
if (!fn)
|
if (!fn) {
|
||||||
|
if (is_builtin(arg))
|
||||||
|
errx(1, "%s is a built-in service.", arg);
|
||||||
errx(1, FINIT_RCSD " missing on system.");
|
errx(1, FINIT_RCSD " missing on system.");
|
||||||
|
}
|
||||||
|
|
||||||
if (!fexist(fn))
|
if (!fexist(fn))
|
||||||
warnx("cannot find %s", fn);
|
warnx("cannot find %s", fn);
|
||||||
|
|||||||
+41
-13
@@ -558,7 +558,7 @@ static int service_start(svc_t *svc)
|
|||||||
|
|
||||||
for (i = 0; i < we.we_wordc; i++) {
|
for (i = 0; i < we.we_wordc; i++) {
|
||||||
if (strlen(we.we_wordv[i]) >= sizeof(svc->args[i])) {
|
if (strlen(we.we_wordv[i]) >= sizeof(svc->args[i])) {
|
||||||
logit(LOG_ERR, "%s: expanded arg. '%s' too long", we.we_wordv[i]);
|
logit(LOG_ERR, "%s: expanded arg. '%s' too long", svc->cmd, we.we_wordv[i]);
|
||||||
rc = WRDE_NOSPACE;
|
rc = WRDE_NOSPACE;
|
||||||
goto nomem;
|
goto nomem;
|
||||||
}
|
}
|
||||||
@@ -747,6 +747,14 @@ static int service_stop(svc_t *svc)
|
|||||||
*/
|
*/
|
||||||
svc_started(svc);
|
svc_started(svc);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify there's still something there before we send the reaper.
|
||||||
|
*/
|
||||||
|
if (svc->pid > 1 && !pid_alive(svc->pid)) {
|
||||||
|
svc->pid = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!svc->desc[0])
|
if (!svc->desc[0])
|
||||||
do_progress = 0;
|
do_progress = 0;
|
||||||
|
|
||||||
@@ -923,7 +931,7 @@ static void parse_env(svc_t *svc, char *env)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (strlen(env) >= sizeof(svc->env)) {
|
if (strlen(env) >= sizeof(svc->env)) {
|
||||||
_e("%s: env file is too long (>%d chars)", svc->cmd, sizeof(svc->env));
|
_e("%s: env file is too long (>%zu chars)", svc->cmd, sizeof(svc->env));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -947,7 +955,7 @@ static void parse_cgroup(svc_t *svc, char *cgroup)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (strlen(ptr) >= sizeof(svc->cgroup)) {
|
if (strlen(ptr) >= sizeof(svc->cgroup)) {
|
||||||
_e("%s: cgroup settings too long (>%d chars)", svc->cmd, sizeof(svc->cgroup));
|
_e("%s: cgroup settings too long (>%zu chars)", svc->cmd, sizeof(svc->cgroup));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -983,7 +991,7 @@ static void parse_killdelay(svc_t *svc, char *delay)
|
|||||||
static void parse_script(char *type, char *script, char *buf, size_t len)
|
static void parse_script(char *type, char *script, char *buf, size_t len)
|
||||||
{
|
{
|
||||||
if (access(script, X_OK))
|
if (access(script, X_OK))
|
||||||
logit(LOG_WARNING, "%s: %s:%s is missing or not executable, skipping.", type, script);
|
logit(LOG_WARNING, "%s:%s is missing or not executable, skipping.", type, script);
|
||||||
else
|
else
|
||||||
strlcpy(buf, script, len);
|
strlcpy(buf, script, len);
|
||||||
}
|
}
|
||||||
@@ -1154,7 +1162,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
|||||||
char *dev = NULL;
|
char *dev = NULL;
|
||||||
int respawn = 0;
|
int respawn = 0;
|
||||||
int levels = 0;
|
int levels = 0;
|
||||||
int manual = 0;
|
int forking = 0, manual = 0;
|
||||||
int restart_max = SVC_RESPAWN_MAX;
|
int restart_max = SVC_RESPAWN_MAX;
|
||||||
int restart_tmo = 0;
|
int restart_tmo = 0;
|
||||||
unsigned oncrash_action = SVC_ONCRASH_IGNORE;
|
unsigned oncrash_action = SVC_ONCRASH_IGNORE;
|
||||||
@@ -1213,6 +1221,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
|||||||
pid = cmd;
|
pid = cmd;
|
||||||
else if (!strncasecmp(cmd, "name:", 5))
|
else if (!strncasecmp(cmd, "name:", 5))
|
||||||
name = cmd;
|
name = cmd;
|
||||||
|
else if (!strncasecmp(cmd, "type:forking", 10))
|
||||||
|
forking = 1;
|
||||||
else if (!strncasecmp(cmd, "manual:yes", 10))
|
else if (!strncasecmp(cmd, "manual:yes", 10))
|
||||||
manual = 1;
|
manual = 1;
|
||||||
else if (!strncasecmp(cmd, "restart:", 8))
|
else if (!strncasecmp(cmd, "restart:", 8))
|
||||||
@@ -1324,10 +1334,6 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
|||||||
svc_unblock(svc);
|
svc_unblock(svc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Decode any optional pid:/optional/path/to/file.pid */
|
|
||||||
if (pid && (svc_is_daemon(svc) || svc_is_sysv(svc)) && pid_file_parse(svc, pid))
|
|
||||||
_e("Invalid 'pid' argument to service: %s", pid);
|
|
||||||
|
|
||||||
if (username) {
|
if (username) {
|
||||||
char *ptr = strchr(username, ':');
|
char *ptr = strchr(username, ':');
|
||||||
|
|
||||||
@@ -1405,8 +1411,26 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
|||||||
parse_env(svc, env);
|
parse_env(svc, env);
|
||||||
if (file)
|
if (file)
|
||||||
strlcpy(svc->file, file, sizeof(svc->file));
|
strlcpy(svc->file, file, sizeof(svc->file));
|
||||||
if (respawn)
|
svc->respawn = respawn;
|
||||||
svc->respawn = 1;
|
svc->forking = forking;
|
||||||
|
|
||||||
|
/* Decode any (optional) pid:/optional/path/to/file.pid */
|
||||||
|
if (svc_is_daemon(svc) || svc_is_sysv(svc)) {
|
||||||
|
char tmp[sizeof(svc->name) + 6]; /* pid:! + svc->name */
|
||||||
|
|
||||||
|
/* no pid: set, figure out a default to track this svc */
|
||||||
|
if (!pid && forking) {
|
||||||
|
snprintf(tmp, sizeof(tmp), "pid:!%s", svc->name);
|
||||||
|
pid = tmp;
|
||||||
|
logit(LOG_INFO, "%s: forking but no pid:!file set, guessing -> %s", svc->name, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid && pid_file_parse(svc, pid))
|
||||||
|
logit(LOG_WARNING, "%s: service has invalid 'pid:' config: %s", svc->name, pid);
|
||||||
|
|
||||||
|
if (svc->pidfile[0] == '!')
|
||||||
|
svc->forking = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set configured limits */
|
/* Set configured limits */
|
||||||
memcpy(svc->rlimit, rlimit, sizeof(svc->rlimit));
|
memcpy(svc->rlimit, rlimit, sizeof(svc->rlimit));
|
||||||
@@ -1485,8 +1509,10 @@ void service_monitor(pid_t lost, int status)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Forking sysv/services declare themselves with pid:!/path/to/pid.file */
|
/* Forking sysv/services declare themselves with pid:!/path/to/pid.file */
|
||||||
if (svc_is_starting(svc) && svc_is_forking(svc))
|
if (svc_is_starting(svc) && svc_is_forking(svc)) {
|
||||||
|
svc->pid = 0; /* Expect no more activity from this one */
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Terminate any children in the same proess group, e.g. logit */
|
/* Terminate any children in the same proess group, e.g. logit */
|
||||||
kill(-svc->pid, SIGKILL);
|
kill(-svc->pid, SIGKILL);
|
||||||
@@ -1573,7 +1599,6 @@ static void set_pre_post_envs(svc_t *svc, const char *type)
|
|||||||
if (!access(fn, R_OK))
|
if (!access(fn, R_OK))
|
||||||
exist = "1";
|
exist = "1";
|
||||||
}
|
}
|
||||||
setenv("SERVICE_ENV_FILE", fn, 1);
|
|
||||||
setenv("SERVICE_ENV_FILE_EXIST", exist, 1);
|
setenv("SERVICE_ENV_FILE_EXIST", exist, 1);
|
||||||
|
|
||||||
#ifdef FINIT_SYSCONFIG
|
#ifdef FINIT_SYSCONFIG
|
||||||
@@ -1846,6 +1871,9 @@ restart:
|
|||||||
|
|
||||||
if (!svc->pid) {
|
if (!svc->pid) {
|
||||||
if (svc_is_daemon(svc) || svc_is_tty(svc)) {
|
if (svc_is_daemon(svc) || svc_is_tty(svc)) {
|
||||||
|
if (svc_is_forking(svc))
|
||||||
|
break;
|
||||||
|
|
||||||
svc_restarting(svc);
|
svc_restarting(svc);
|
||||||
svc_set_state(svc, SVC_HALTED_STATE);
|
svc_set_state(svc, SVC_HALTED_STATE);
|
||||||
|
|
||||||
|
|||||||
@@ -207,7 +207,8 @@ void do_iterate_proc(int (*cb)(int, void *), void *data)
|
|||||||
_d("Skipping %s ...", &file[1]);
|
_d("Skipping %s ...", &file[1]);
|
||||||
else
|
else
|
||||||
if (cb(pid, data)) {
|
if (cb(pid, data)) {
|
||||||
print(0, "PID %d is still alive (%s)", pid, file);
|
_d("PID %d is still alive (%s)", pid, file);
|
||||||
|
fclose(fp);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -323,13 +324,21 @@ void do_shutdown(shutop_t op)
|
|||||||
/* Unmount any tmpfs before unmounting swap ... */
|
/* Unmount any tmpfs before unmounting swap ... */
|
||||||
unmount_tmpfs();
|
unmount_tmpfs();
|
||||||
if (whichp("swapoff"))
|
if (whichp("swapoff"))
|
||||||
run("swapoff -e -a", "swapoff");
|
run_interactive("swapoff -a", "Disabling system swap");
|
||||||
|
|
||||||
/* ... unmount remaining regular file systems. */
|
/* ... unmount remaining regular file systems. */
|
||||||
unmount_regular();
|
unmount_regular();
|
||||||
|
|
||||||
/* We sit on / so we must remount it read-only */
|
/*
|
||||||
run("mount -n -o remount,ro -t none rootfs /", "mount");
|
* We sit on / so we must remount it ro, try all the things!
|
||||||
|
* See the following links for details:
|
||||||
|
* - https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=339023
|
||||||
|
* - https://bugs.launchpad.net/ubuntu/+source/util-linux/+bug/29187
|
||||||
|
*/
|
||||||
|
sync();
|
||||||
|
run("mount -n -o remount,ro -t dummytype dummydev /", NULL);
|
||||||
|
run("mount -n -o remount,ro dummydev /", NULL);
|
||||||
|
run("mount -n -o remount,ro /", "mount");
|
||||||
|
|
||||||
/* Call mdadm to mark any RAID array(s) as clean before halting. */
|
/* Call mdadm to mark any RAID array(s) as clean before halting. */
|
||||||
mdadm_wait();
|
mdadm_wait();
|
||||||
|
|||||||
@@ -127,6 +127,7 @@ typedef struct svc {
|
|||||||
int starting; /* ... waiting for pidfile to be re-asserted */
|
int starting; /* ... waiting for pidfile to be re-asserted */
|
||||||
int runlevels;
|
int runlevels;
|
||||||
int sighup; /* This service supports SIGHUP :) */
|
int sighup; /* This service supports SIGHUP :) */
|
||||||
|
int forking; /* This is a service/sysv daemon that forks, wait for it ... */
|
||||||
svc_block_t block; /* Reason that this service is currently stopped */
|
svc_block_t block; /* Reason that this service is currently stopped */
|
||||||
char cond[MAX_COND_LEN];
|
char cond[MAX_COND_LEN];
|
||||||
|
|
||||||
@@ -228,7 +229,7 @@ static inline int svc_is_daemon (svc_t *svc) { return svc && SVC_TYPE_SERVICE
|
|||||||
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_is_daemon(svc) || svc_is_sysv(svc)) && svc->pidfile[0] == '!'; }
|
static inline int svc_is_forking (svc_t *svc) { return svc && svc->forking; }
|
||||||
|
|
||||||
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_nohup (svc_t *svc) { return svc && (0 == svc->sighup || 0 != svc->args_dirty); }
|
||||||
|
|||||||
+35
-1
@@ -224,7 +224,7 @@ int fngetint(char *path, int *val)
|
|||||||
{
|
{
|
||||||
char buf[64];
|
char buf[64];
|
||||||
|
|
||||||
if (fnread(buf, sizeof(buf), path) <= 0)
|
if (fnread(buf, sizeof(buf), "%s", path) <= 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
@@ -235,6 +235,40 @@ int fngetint(char *path, int *val)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a replacement for the non-working reboot(RB_SW_SUSPEND). It
|
||||||
|
* checks for suspend to RAM support, assuming `mem_sleep` has a sane
|
||||||
|
* default, e.g. 'deep' or 's2idle'. The latter should be possible to
|
||||||
|
* select from finit.conf, but for now we go with the kernel default.
|
||||||
|
* For more information on kernel sleep states, see:
|
||||||
|
* https://www.kernel.org/doc/html/latest/admin-guide/pm/sleep-states.html
|
||||||
|
*/
|
||||||
|
int suspend(void)
|
||||||
|
{
|
||||||
|
char buf[80];
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
if (fnread(buf, sizeof(buf), "/sys/power/state") <= 0) {
|
||||||
|
opnotsup:
|
||||||
|
errno = EINVAL;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
chomp(buf);
|
||||||
|
|
||||||
|
ptr = strtok(buf, " ");
|
||||||
|
while (ptr) {
|
||||||
|
if (!strcmp(ptr, "mem"))
|
||||||
|
break;
|
||||||
|
|
||||||
|
ptr = strtok(NULL, " ");
|
||||||
|
}
|
||||||
|
if (!ptr)
|
||||||
|
goto opnotsup;
|
||||||
|
|
||||||
|
return fnwrite("mem", "/sys/power/state");
|
||||||
|
}
|
||||||
|
|
||||||
int strtobytes(char *arg)
|
int strtobytes(char *arg)
|
||||||
{
|
{
|
||||||
int mod = 0, bytes;
|
int mod = 0, bytes;
|
||||||
|
|||||||
+6
-4
@@ -54,11 +54,13 @@ extern char *prognm;
|
|||||||
|
|
||||||
char *progname (char *arg0);
|
char *progname (char *arg0);
|
||||||
|
|
||||||
char *str (char *fmt, ...);
|
char *str (char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
||||||
int fnread (char *buf, size_t len, char *fmt, ...);
|
int fnread (char *buf, size_t len, char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
|
||||||
int fnwrite (char *value, char *fmt, ...);
|
int fnwrite (char *value, char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
int fngetint (char *path, int *val);
|
int fngetint (char *path, int *val);
|
||||||
|
|
||||||
|
int suspend (void);
|
||||||
|
|
||||||
int strtobytes (char *arg);
|
int strtobytes (char *arg);
|
||||||
char *sig2str (int sig);
|
char *sig2str (int sig);
|
||||||
int str2sig (char *sig);
|
int str2sig (char *sig);
|
||||||
@@ -85,7 +87,7 @@ int ttcooked (void);
|
|||||||
#define ttcooked() 0
|
#define ttcooked() 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline void dbg(char *fmt, ...)
|
static __attribute__ ((format (printf, 1, 2))) inline void dbg(char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
|
|||||||
+16
-1
@@ -1,6 +1,21 @@
|
|||||||
SUBDIRS = common tenv
|
SUBDIRS = common tenv
|
||||||
|
|
||||||
EXTRA_DIST = setup-root.sh
|
EXTRA_DIST = skel/bin/busybox-x86_64.md5 skel/sbin/service.sh skel/bin/slay \
|
||||||
|
skel/cdrom/.empty skel/dev/shm/.empty skel/dev/pts/.empty \
|
||||||
|
skel/etc/inittab skel/etc/hostname skel/etc/fstab \
|
||||||
|
skel/etc/init.d/rcS skel/etc/init.d/rcK skel/tmp/.empty \
|
||||||
|
skel/etc/init.d/S01-service.sh skel/home/.empty \
|
||||||
|
skel/proc/.empty skel/root/.empty skel/run/.empty \
|
||||||
|
skel/sbin/chrootsetup.sh skel/srv/.empty skel/sys/.empty \
|
||||||
|
skel/usr/bin/.empty skel/usr/lib/.empty skel/usr/sbin/.empty \
|
||||||
|
skel/usr/games/.empty skel/usr/src/.empty \
|
||||||
|
skel/usr/share/.empty skel/usr/include/.empty \
|
||||||
|
skel/usr/local/games/.empty skel/usr/local/sbin/.empty \
|
||||||
|
skel/usr/local/share/.empty skel/usr/local/src/.empty \
|
||||||
|
skel/usr/local/lib/.empty skel/usr/local/bin/.empty \
|
||||||
|
skel/usr/local/etc/.empty skel/var/.empty
|
||||||
|
|
||||||
|
EXTRA_DIST += setup-root.sh
|
||||||
EXTRA_DIST += add-remove-dynamic-service.sh
|
EXTRA_DIST += add-remove-dynamic-service.sh
|
||||||
EXTRA_DIST += add-remove-dynamic-service-sub-config.sh
|
EXTRA_DIST += add-remove-dynamic-service-sub-config.sh
|
||||||
EXTRA_DIST += start-stop-service.sh
|
EXTRA_DIST += start-stop-service.sh
|
||||||
|
|||||||
@@ -13,15 +13,12 @@ test_teardown()
|
|||||||
say "Running test teardown."
|
say "Running test teardown."
|
||||||
|
|
||||||
texec rm -f "$FINIT_RCSD/service.conf"
|
texec rm -f "$FINIT_RCSD/service.conf"
|
||||||
texec rm -f /test_assets/service.sh
|
|
||||||
}
|
}
|
||||||
|
|
||||||
say "Test start $(date)"
|
say "Test start $(date)"
|
||||||
|
|
||||||
cp "$TEST_DIR"/common/service.sh "$TENV_ROOT"/test_assets/
|
|
||||||
|
|
||||||
say "Add a dynamic service in $FINIT_RCSD/service.conf"
|
say "Add a dynamic service in $FINIT_RCSD/service.conf"
|
||||||
texec sh -c "echo 'service [2345] kill:20 log /test_assets/service.sh -- Dyn serv' > $FINIT_RCSD/service.conf"
|
texec sh -c "echo 'service [2345] kill:20 log service.sh -- Dyn serv' > $FINIT_RCSD/service.conf"
|
||||||
|
|
||||||
say 'Reload Finit'
|
say 'Reload Finit'
|
||||||
texec sh -c "initctl reload"
|
texec sh -c "initctl reload"
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
TEST_DIR=$(dirname "$0")
|
TEST_DIR=$(dirname "$0")
|
||||||
export DEBUG=1
|
|
||||||
|
|
||||||
# shellcheck source=/dev/null
|
# shellcheck source=/dev/null
|
||||||
. "$TEST_DIR/tenv/lib.sh"
|
. "$TEST_DIR/tenv/lib.sh"
|
||||||
@@ -14,20 +13,12 @@ test_teardown()
|
|||||||
say "Running test teardown."
|
say "Running test teardown."
|
||||||
|
|
||||||
texec rm -f "$FINIT_CONF"
|
texec rm -f "$FINIT_CONF"
|
||||||
texec rm -f /test_assets/service.sh
|
|
||||||
}
|
}
|
||||||
|
|
||||||
say "Hi, this is /run et al"
|
|
||||||
texec sh -c "echo 'ROOT:/bin'; ls -l /bin/; echo 'ROOT:/sbin'; ls -l /sbin/; echo 'ROOT:/run'; ls -l /run/; echo 'ROOT:/run/finit/'; ls -l /run/finit/; echo 'ROOT:/dev'; ls -l /dev/; ps; ls -l /proc/1/fd/"
|
|
||||||
say "HUPing PID 1 ..."
|
|
||||||
texec sh -c "kill -HUP 1"
|
|
||||||
|
|
||||||
say "Test start $(date)"
|
say "Test start $(date)"
|
||||||
|
|
||||||
cp "$TEST_DIR"/common/service.sh "$TENV_ROOT"/test_assets/
|
|
||||||
|
|
||||||
say "Add a dynamic service in $FINIT_CONF"
|
say "Add a dynamic service in $FINIT_CONF"
|
||||||
texec sh -c "echo 'service [2345] kill:20 log /test_assets/service.sh -- Dyn service' > $FINIT_CONF"
|
texec sh -c "echo 'service [2345] kill:20 log service.sh -- Dyn service' > $FINIT_CONF"
|
||||||
|
|
||||||
say 'Reload Finit'
|
say 'Reload Finit'
|
||||||
texec sh -c "initctl reload"
|
texec sh -c "initctl reload"
|
||||||
|
|||||||
@@ -1,4 +1,2 @@
|
|||||||
EXTRA_DIST = service.conf service.sh S01-service.sh slay.sh
|
|
||||||
|
|
||||||
noinst_PROGRAMS = serv
|
noinst_PROGRAMS = serv
|
||||||
serv_SOURCES = serv.c
|
serv_SOURCES = serv.c
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
service [2345] kill:20 log /test_assets/service.sh
|
|
||||||
+3
-10
@@ -5,6 +5,9 @@ set -eu
|
|||||||
# shellcheck disable=SC2154
|
# shellcheck disable=SC2154
|
||||||
make -C "$top_builddir" DESTDIR="$TENV_ROOT" install
|
make -C "$top_builddir" DESTDIR="$TENV_ROOT" install
|
||||||
|
|
||||||
|
mkdir -p "$TENV_ROOT/sbin/"
|
||||||
|
cp "$top_builddir/test/common/serv" "$TENV_ROOT/sbin/"
|
||||||
|
|
||||||
# shellcheck disable=SC2154
|
# shellcheck disable=SC2154
|
||||||
FINITBIN="$(pwd)/$top_builddir/src/finit" DEST="$TENV_ROOT" make -f "$srcdir/tenv/root.mk"
|
FINITBIN="$(pwd)/$top_builddir/src/finit" DEST="$TENV_ROOT" make -f "$srcdir/tenv/root.mk"
|
||||||
|
|
||||||
@@ -12,13 +15,3 @@ FINITBIN="$(pwd)/$top_builddir/src/finit" DEST="$TENV_ROOT" make -f "$srcdir/ten
|
|||||||
for plugin in tty.so urandom.so rtc.so modprobe.so hotplug.so; do
|
for plugin in tty.so urandom.so rtc.so modprobe.so hotplug.so; do
|
||||||
find "$TENV_ROOT" -name $plugin -delete
|
find "$TENV_ROOT" -name $plugin -delete
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "$TENV_ROOT:"
|
|
||||||
ls -l "$TENV_ROOT"
|
|
||||||
echo "$TENV_ROOT:/bin"
|
|
||||||
ls -l "$TENV_ROOT"/bin
|
|
||||||
echo "$TENV_ROOT:/sbin"
|
|
||||||
ls -l "$TENV_ROOT"/sbin
|
|
||||||
echo "$TENV_ROOT:/var"
|
|
||||||
ls -l "$TENV_ROOT"/var/
|
|
||||||
|
|
||||||
|
|||||||
@@ -14,18 +14,15 @@ test_teardown()
|
|||||||
say "Running test teardown."
|
say "Running test teardown."
|
||||||
|
|
||||||
texec rm -f "$FINIT_CONF"
|
texec rm -f "$FINIT_CONF"
|
||||||
texec rm -f /test_assets/service.sh
|
|
||||||
}
|
}
|
||||||
|
|
||||||
say "Test start $(date)"
|
say "Test start $(date)"
|
||||||
|
|
||||||
cp "$TEST_DIR"/common/service.sh "$TENV_ROOT"/test_assets/
|
|
||||||
|
|
||||||
say 'Ensure file system is cleared'
|
say 'Ensure file system is cleared'
|
||||||
texec rm -f /tmp/usr1.log
|
texec rm -f /tmp/usr1.log
|
||||||
|
|
||||||
say "Add service stanza in $FINIT_CONF"
|
say "Add service stanza in $FINIT_CONF"
|
||||||
texec sh -c "echo 'service [2345] kill:20 log /test_assets/service.sh -- Test service' > $FINIT_CONF"
|
texec sh -c "echo 'service [2345] kill:20 log service.sh -- Test service' > $FINIT_CONF"
|
||||||
|
|
||||||
say 'Reload Finit'
|
say 'Reload Finit'
|
||||||
texec sh -c "initctl reload"
|
texec sh -c "initctl reload"
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
test
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# SysV style start script for service.sh
|
# SysV style start script for service.sh
|
||||||
|
|
||||||
DAEMON="/test_assets/service.sh"
|
DAEMON="/sbin/service.sh"
|
||||||
PIDFILE="/var/run/service.pid"
|
PIDFILE="/var/run/service.pid"
|
||||||
|
|
||||||
start()
|
start()
|
||||||
Executable
+4
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo "Shutting down ..."
|
||||||
|
exit 0
|
||||||
Executable
+5
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo "Starting up ..."
|
||||||
|
poweroff -d 2
|
||||||
|
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# /etc/inittab
|
||||||
|
#
|
||||||
|
# Copyright (C) 2001 Erik Andersen <andersen@codepoet.org>
|
||||||
|
#
|
||||||
|
# Note: BusyBox init doesn't support runlevels. The runlevels field is
|
||||||
|
# completely ignored by BusyBox init. If you want runlevels, use
|
||||||
|
# sysvinit.
|
||||||
|
#
|
||||||
|
# Format for each entry: <id>:<runlevels>:<action>:<process>
|
||||||
|
#
|
||||||
|
# id == tty to run on, or empty for /dev/console
|
||||||
|
# runlevels == ignored
|
||||||
|
# action == one of sysinit, respawn, askfirst, wait, and once
|
||||||
|
# process == program to run
|
||||||
|
|
||||||
|
# Startup the system
|
||||||
|
#::sysinit:/bin/mount -t proc proc /proc
|
||||||
|
#::sysinit:/bin/mount -o remount,rw /
|
||||||
|
#::sysinit:/bin/mkdir -p /dev/pts /dev/shm
|
||||||
|
#::sysinit:/bin/mount -a
|
||||||
|
#::sysinit:/bin/mkdir -p /run/lock/subsys
|
||||||
|
#::sysinit:/sbin/swapon -a
|
||||||
|
null::sysinit:/bin/ln -sf /proc/self/fd /dev/fd
|
||||||
|
null::sysinit:/bin/ln -sf /proc/self/fd/0 /dev/stdin
|
||||||
|
null::sysinit:/bin/ln -sf /proc/self/fd/1 /dev/stdout
|
||||||
|
null::sysinit:/bin/ln -sf /proc/self/fd/2 /dev/stderr
|
||||||
|
::sysinit:/bin/hostname -F /etc/hostname
|
||||||
|
# now run any rc scripts
|
||||||
|
::sysinit:/etc/init.d/rcS
|
||||||
|
|
||||||
|
# Put a getty on the serial port
|
||||||
|
#ttyS0::respawn:/sbin/getty -L ttyS0 115200 vt100 # GENERIC_SERIAL
|
||||||
|
|
||||||
|
# Stuff to do for the 3-finger salute
|
||||||
|
#::ctrlaltdel:/sbin/reboot
|
||||||
|
|
||||||
|
# Stuff to do before rebooting
|
||||||
|
::shutdown:/etc/init.d/rcK
|
||||||
|
#::shutdown:/sbin/swapoff -a
|
||||||
|
#::shutdown:/bin/umount -a -r
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
# furnished to do so, subject to the following conditions:
|
# furnished to do so, subject to the following conditions:
|
||||||
#
|
#
|
||||||
# The above copyright notice and this permission notice shall be included in
|
# The above copyright notice and this permission notice shall be included in
|
||||||
# all copies or substantial portions of the Software.
|
# all copies or substantial portions of the Software.
|
||||||
#
|
#
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
@@ -23,11 +23,14 @@
|
|||||||
# THE SOFTWARE.
|
# THE SOFTWARE.
|
||||||
|
|
||||||
set -eu
|
set -eu
|
||||||
|
export PATH=$PATH:/usr/bin:/usr/sbin
|
||||||
|
|
||||||
# It would have been nice to mount /dev as devtmpfs, but unfortunately
|
# It would have been nice to mount /dev as devtmpfs, but unfortunately
|
||||||
# that's not possible if you're not privileged. For now tmpfs will
|
# that's not possible if you're not privileged. For now tmpfs will
|
||||||
# have to do.
|
# have to do.
|
||||||
mount -n -t tmpfs none /dev
|
mount -n -t tmpfs none /dev
|
||||||
|
# Silence BusyBox init
|
||||||
|
touch /dev/null
|
||||||
|
|
||||||
mount -t proc none /proc
|
mount -t proc none /proc
|
||||||
mount -t sysfs none /sys
|
mount -t sysfs none /sys
|
||||||
@@ -15,17 +15,13 @@ test_teardown()
|
|||||||
say "Running test teardown."
|
say "Running test teardown."
|
||||||
|
|
||||||
texec rm -f "$FINIT_CONF"
|
texec rm -f "$FINIT_CONF"
|
||||||
texec rm -f /test_assets/service.sh
|
|
||||||
}
|
}
|
||||||
|
|
||||||
say "Test start $(date)"
|
say "Test start $(date)"
|
||||||
|
|
||||||
cp "$TEST_DIR"/common/slay.sh "$TENV_ROOT"/test_assets/
|
|
||||||
cp "$TEST_DIR"/common/service.sh "$TENV_ROOT"/test_assets/
|
|
||||||
rm -f "$TENV_ROOT"/oldpid
|
rm -f "$TENV_ROOT"/oldpid
|
||||||
|
|
||||||
say "Add service stanza in $FINIT_CONF"
|
say "Add service stanza in $FINIT_CONF"
|
||||||
texec sh -c "echo 'service [2345] respawn log /test_assets/service.sh -- Test service' > $FINIT_CONF"
|
texec sh -c "echo 'service [2345] respawn log service.sh -- Test service' > $FINIT_CONF"
|
||||||
|
|
||||||
say 'Reload Finit'
|
say 'Reload Finit'
|
||||||
texec sh -c "initctl reload"
|
texec sh -c "initctl reload"
|
||||||
@@ -40,7 +36,7 @@ laps=1000
|
|||||||
while [ $i -lt $laps ]; do
|
while [ $i -lt $laps ]; do
|
||||||
i=$((i + 1))
|
i=$((i + 1))
|
||||||
say "Lap $i/$laps, killing service ..." # we have this, no sleep needed
|
say "Lap $i/$laps, killing service ..." # we have this, no sleep needed
|
||||||
texec sh -c "/test_assets/slay.sh service.sh"
|
texec sh -c "slay service.sh"
|
||||||
done
|
done
|
||||||
|
|
||||||
retry 'assert_new_pid service.sh /run/service.pid'
|
retry 'assert_new_pid service.sh /run/service.pid'
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ TEST_DIR=$(dirname "$0")
|
|||||||
test_setup()
|
test_setup()
|
||||||
{
|
{
|
||||||
say "Test start $(date)"
|
say "Test start $(date)"
|
||||||
cp "$TENV_ROOT"/../common/serv "$TENV_ROOT"/test_assets/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test_teardown()
|
test_teardown()
|
||||||
@@ -15,7 +14,6 @@ test_teardown()
|
|||||||
say "Running test teardown."
|
say "Running test teardown."
|
||||||
|
|
||||||
texec rm -f "$FINIT_CONF"
|
texec rm -f "$FINIT_CONF"
|
||||||
texec rm -f /test_assets/serv
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test_one()
|
test_one()
|
||||||
@@ -57,11 +55,12 @@ test_one()
|
|||||||
# shellcheck source=/dev/null
|
# shellcheck source=/dev/null
|
||||||
. "$TEST_DIR/tenv/lib.sh"
|
. "$TEST_DIR/tenv/lib.sh"
|
||||||
|
|
||||||
test_one "/run/serv.pid" "service pid:!/run/serv.pid /test_assets/serv -- Forking service"
|
test_one "/run/serv.pid" "service pid:!/run/serv.pid serv -- Forking service, type 1"
|
||||||
|
test_one "/run/serv.pid" "service type:forking serv -- Forking service, type 2"
|
||||||
# This one could never be started by and monitored by Finit: it forks to
|
# This one could never be started by and monitored by Finit: it forks to
|
||||||
# background and does not create a PID file. Essentially it's lost to
|
# background and does not create a PID file. Essentially it's lost to
|
||||||
# Finit, and any other sane process monitor.
|
# Finit, and any other sane process monitor.
|
||||||
#test_one "/run/serv.pid" "service pid:/run/serv.pid /test_assets/serv -p -- Forking service w/o PID file"
|
#test_one "/run/serv.pid" "service pid:/run/serv.pid serv -p -- Forking service w/o PID file"
|
||||||
test_one "/run/serv.pid" "service pid:/run/serv.pid /test_assets/serv -n -- Foreground service w/o PID file"
|
test_one "/run/serv.pid" "service pid:/run/serv.pid serv -n -- Foreground service w/o PID file"
|
||||||
test_one "/run/serv.pid" "service /test_assets/serv -n -p -- Foreground service w/ PID file"
|
test_one "/run/serv.pid" "service serv -n -p -- Foreground service w/ PID file"
|
||||||
test_one "/run/servy.pid" "service pid:/run/servy.pid /test_assets/serv -n -p -P /run/servy.pid -- Foreground service w/ custom PID file"
|
test_one "/run/servy.pid" "service pid:/run/servy.pid serv -n -p -P /run/servy.pid -- Foreground service w/ custom PID file"
|
||||||
|
|||||||
@@ -13,19 +13,19 @@ test_teardown()
|
|||||||
say "Running test teardown."
|
say "Running test teardown."
|
||||||
|
|
||||||
texec rm -f "$FINIT_RCSD/service.conf"
|
texec rm -f "$FINIT_RCSD/service.conf"
|
||||||
texec rm -f /test_assets/service.sh
|
|
||||||
}
|
}
|
||||||
|
|
||||||
say "Test start $(date)"
|
say "Test start $(date)"
|
||||||
|
|
||||||
cp "$TEST_DIR"/common/service.sh "$TENV_ROOT"/test_assets/
|
|
||||||
|
|
||||||
say "Add service stanza in $FINIT_RCSD/service.conf"
|
say "Add service stanza in $FINIT_RCSD/service.conf"
|
||||||
texec sh -c "echo 'service [2345] kill:20 log /test_assets/service.sh -- Subserv' > $FINIT_RCSD/service.conf"
|
texec sh -c "echo 'service [2345] kill:20 log service.sh -- Subserv' > $FINIT_RCSD/service.conf"
|
||||||
|
|
||||||
say 'Reload Finit'
|
say 'Reload Finit'
|
||||||
texec sh -c "initctl reload"
|
texec sh -c "initctl reload"
|
||||||
|
|
||||||
|
sleep 2
|
||||||
|
texec sh -c "ps"
|
||||||
|
|
||||||
retry 'assert_num_children 1 service.sh'
|
retry 'assert_num_children 1 service.sh'
|
||||||
|
|
||||||
say 'Stop the service'
|
say 'Stop the service'
|
||||||
|
|||||||
@@ -13,15 +13,12 @@ test_teardown()
|
|||||||
say "Running test teardown."
|
say "Running test teardown."
|
||||||
|
|
||||||
texec rm -f "$FINIT_CONF"
|
texec rm -f "$FINIT_CONF"
|
||||||
texec rm -f /test_assets/service.sh
|
|
||||||
}
|
}
|
||||||
|
|
||||||
say "Test start $(date)"
|
say "Test start $(date)"
|
||||||
|
|
||||||
cp "$TEST_DIR"/common/service.sh "$TENV_ROOT"/test_assets/
|
|
||||||
|
|
||||||
say "Add service stanza in $FINIT_CONF"
|
say "Add service stanza in $FINIT_CONF"
|
||||||
texec sh -c "echo 'service [2345] kill:20 log /test_assets/service.sh -- Test service' > $FINIT_CONF"
|
texec sh -c "echo 'service [2345] kill:20 log service.sh -- Test service' > $FINIT_CONF"
|
||||||
|
|
||||||
say 'Reload Finit'
|
say 'Reload Finit'
|
||||||
texec sh -c "initctl reload"
|
texec sh -c "initctl reload"
|
||||||
|
|||||||
@@ -12,17 +12,12 @@ test_teardown() {
|
|||||||
say "Running test teardown."
|
say "Running test teardown."
|
||||||
|
|
||||||
texec rm -f "$FINIT_CONF"
|
texec rm -f "$FINIT_CONF"
|
||||||
texec rm -f /test_assets/service.sh
|
|
||||||
}
|
}
|
||||||
|
|
||||||
say "Test start $(date)"
|
say "Test start $(date)"
|
||||||
|
|
||||||
cp "$TEST_DIR"/common/service.sh "$TENV_ROOT"/test_assets/
|
|
||||||
cp "$TEST_DIR"/common/S01-service.sh "$TENV_ROOT"/test_assets/
|
|
||||||
chmod +x "$TENV_ROOT"/test_assets/*.sh
|
|
||||||
|
|
||||||
say "Add sysv stanza in $FINIT_CONF"
|
say "Add sysv stanza in $FINIT_CONF"
|
||||||
texec sh -c "echo 'sysv [2345] pid:!/run/service.pid name:service.sh /test_assets/S01-service.sh -- SysV test service' > $FINIT_CONF"
|
texec sh -c "echo 'sysv [2345] pid:!/run/service.pid name:service.sh /etc/init.d/S01-service.sh -- SysV test service' > $FINIT_CONF"
|
||||||
|
|
||||||
say 'Reload Finit'
|
say 'Reload Finit'
|
||||||
texec sh -c "initctl reload"
|
texec sh -c "initctl reload"
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
EXTRA_DIST = lib.sh exec.sh start.sh root.mk busybox-x86_64.md5
|
EXTRA_DIST = lib.sh exec.sh start.sh root.mk
|
||||||
EXTRA_DIST += chrootsetup.sh
|
|
||||||
|
|||||||
+3
-5
@@ -154,13 +154,12 @@ if [ -n "${DEBUG:-}" ]; then
|
|||||||
FINIT_ARGS="${FINIT_ARGS:-} finit.debug=on"
|
FINIT_ARGS="${FINIT_ARGS:-} finit.debug=on"
|
||||||
fi
|
fi
|
||||||
# shellcheck disable=2086
|
# shellcheck disable=2086
|
||||||
"$TEST_DIR/tenv/start.sh" finit ${FINIT_ARGS:-} finit.debug=on &
|
"$TEST_DIR/tenv/start.sh" finit ${FINIT_ARGS:-} &
|
||||||
finit_ppid=$!
|
finit_ppid=$!
|
||||||
echo "$finit_ppid" > "$TENV_ROOT"/running_test.pid
|
echo "$finit_ppid" > "$TENV_ROOT"/running_test.pid
|
||||||
|
|
||||||
>&2 echo "Finit runs as PID $finit_ppid outside of container."
|
|
||||||
>&2 echo "Hint: Execute 'TENV_ROOT=$TENV_ROOT $TEST_DIR/tenv/enter.sh' to enter the test namespace"
|
>&2 echo "Hint: Execute 'TENV_ROOT=$TENV_ROOT $TEST_DIR/tenv/enter.sh' to enter the test namespace"
|
||||||
log "$color_reset" 'Setup of test environment done' ''
|
log "$color_reset" 'Setup of test environment done, waiting for Finit to start up ...' ''
|
||||||
|
|
||||||
finit_pid=$(retry "pgrep -P $finit_ppid")
|
finit_pid=$(retry "pgrep -P $finit_ppid")
|
||||||
|
|
||||||
@@ -170,5 +169,4 @@ fi
|
|||||||
|
|
||||||
#tty=/dev/$(texec cat /sys/class/tty/console/active)
|
#tty=/dev/$(texec cat /sys/class/tty/console/active)
|
||||||
#texec cat "$tty" &
|
#texec cat "$tty" &
|
||||||
sleep 5
|
#sleep 1
|
||||||
|
|
||||||
|
|||||||
+17
-57
@@ -20,8 +20,9 @@
|
|||||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
# THE SOFTWARE.
|
# THE SOFTWARE.
|
||||||
|
|
||||||
DEST ?= ../tenv-root
|
|
||||||
srcdir ?= ../
|
srcdir ?= ../
|
||||||
|
SKEL ?= $(srcdir)/skel
|
||||||
|
DEST ?= ../tenv-root
|
||||||
|
|
||||||
CACHE ?= ~/.cache
|
CACHE ?= ~/.cache
|
||||||
ARCH ?= x86_64
|
ARCH ?= x86_64
|
||||||
@@ -30,60 +31,27 @@ FINITBIN ?= ./sbin/finit
|
|||||||
|
|
||||||
BBVER ?= 1.31.0
|
BBVER ?= 1.31.0
|
||||||
BBBIN = busybox-$(ARCH)
|
BBBIN = busybox-$(ARCH)
|
||||||
BBURL ?= https://www.busybox.net/downloads/binaries/$(BBVER)-defconfig-multiarch-musl/$(BBBIN)
|
BBHOME ?= https://www.busybox.net/downloads/binaries
|
||||||
|
BBURL ?= $(BBHOME)/$(BBVER)-defconfig-multiarch-musl/$(BBBIN)
|
||||||
binaries = $(DEST)/bin/awk \
|
|
||||||
$(DEST)/bin/cat \
|
|
||||||
$(DEST)/bin/cp \
|
|
||||||
$(DEST)/bin/date \
|
|
||||||
$(DEST)/bin/echo \
|
|
||||||
$(DEST)/bin/env \
|
|
||||||
$(DEST)/bin/find \
|
|
||||||
$(DEST)/bin/grep \
|
|
||||||
$(DEST)/bin/kill \
|
|
||||||
$(DEST)/bin/ls \
|
|
||||||
$(DEST)/bin/mkdir \
|
|
||||||
$(DEST)/bin/mkfifo \
|
|
||||||
$(DEST)/bin/mknod \
|
|
||||||
$(DEST)/bin/mount \
|
|
||||||
$(DEST)/bin/printf \
|
|
||||||
$(DEST)/bin/pgrep \
|
|
||||||
$(DEST)/bin/ps \
|
|
||||||
$(DEST)/bin/rm \
|
|
||||||
$(DEST)/bin/sh \
|
|
||||||
$(DEST)/bin/sleep \
|
|
||||||
$(DEST)/bin/tail \
|
|
||||||
$(DEST)/bin/top \
|
|
||||||
$(DEST)/bin/touch \
|
|
||||||
$(DEST)/bin/start-stop-daemon
|
|
||||||
|
|
||||||
dirs = $(DEST)/bin \
|
|
||||||
$(DEST)/dev \
|
|
||||||
$(DEST)/etc \
|
|
||||||
$(DEST)/proc \
|
|
||||||
$(DEST)/sbin \
|
|
||||||
$(DEST)/var \
|
|
||||||
$(DEST)/run \
|
|
||||||
$(DEST)/sys \
|
|
||||||
$(DEST)/test_assets \
|
|
||||||
$(DEST)/tmp
|
|
||||||
|
|
||||||
_libs_src = $(shell ldd $(FINITBIN) | grep -Eo '/[^ ]+')
|
_libs_src = $(shell ldd $(FINITBIN) | grep -Eo '/[^ ]+')
|
||||||
libs = $(foreach path,$(_libs_src),$(abspath $(DEST))$(path))
|
libs = $(foreach path,$(_libs_src),$(abspath $(DEST))$(path))
|
||||||
|
|
||||||
all: $(dirs) $(binaries) $(libs) $(DEST)/bin/chrootsetup.sh
|
all: $(libs) $(DEST)/bin/$(BBBIN)
|
||||||
touch $(DEST)/etc/fstab
|
@(cd $(DEST); \
|
||||||
|
for prg in `./bin/$(BBBIN) --list-full`; do \
|
||||||
$(dirs):
|
ln -sf /bin/$(BBBIN) $$prg; \
|
||||||
mkdir -p $@
|
done)
|
||||||
|
|
||||||
$(DEST)/bin/$(BBBIN).md5:
|
$(DEST)/bin/$(BBBIN).md5:
|
||||||
cp $(srcdir)/tenv/$(notdir $@) $@
|
@mkdir -p $(DEST)
|
||||||
|
@cp -a $(SKEL)/* $(DEST)/
|
||||||
|
@chmod -R u+w $(DEST)/
|
||||||
|
@find $(DEST) -name .empty -delete
|
||||||
|
|
||||||
.PHONY: $(DEST)/bin/$(BBBIN)
|
|
||||||
$(DEST)/bin/$(BBBIN): $(DEST)/bin/$(BBBIN).md5
|
$(DEST)/bin/$(BBBIN): $(DEST)/bin/$(BBBIN).md5
|
||||||
@cd $(dir $@)
|
@(cd $(dir $@); \
|
||||||
@if ! md5sum --status -c $(BBBIN).md5 2>/dev/null; then \
|
if ! md5sum --status -c $(BBBIN).md5 2>/dev/null; then \
|
||||||
if [ -d $(CACHE) ]; then \
|
if [ -d $(CACHE) ]; then \
|
||||||
echo "Cannot find $(BBBIN), checking $(CACHE) ..."; \
|
echo "Cannot find $(BBBIN), checking $(CACHE) ..."; \
|
||||||
cd $(CACHE); \
|
cd $(CACHE); \
|
||||||
@@ -101,17 +69,9 @@ $(DEST)/bin/$(BBBIN): $(DEST)/bin/$(BBBIN).md5
|
|||||||
fi; \
|
fi; \
|
||||||
cd $(dir $@); \
|
cd $(dir $@); \
|
||||||
md5sum -c $(BBBIN).md5; \
|
md5sum -c $(BBBIN).md5; \
|
||||||
fi
|
fi)
|
||||||
@chmod +x $@
|
@chmod +x $@
|
||||||
|
|
||||||
$(DEST)/bin/chrootsetup.sh:
|
$(libs): $(DEST)/bin/$(BBBIN).md5
|
||||||
cp $(srcdir)/tenv/$(notdir $@) $@
|
|
||||||
|
|
||||||
$(binaries): $(DEST)/bin/$(BBBIN)
|
|
||||||
cd $(DEST)/bin; \
|
|
||||||
rm -f $(notdir $@); \
|
|
||||||
ln -s $(BBBIN) $(notdir $@)
|
|
||||||
|
|
||||||
$(libs):
|
|
||||||
mkdir -p $(dir $@)
|
mkdir -p $(dir $@)
|
||||||
cp $(patsubst $(abspath $(DEST))%,%,$@) $@
|
cp $(patsubst $(abspath $(DEST))%,%,$@) $@
|
||||||
|
|||||||
+1
-1
@@ -46,4 +46,4 @@ exec "$unshare" \
|
|||||||
--mount \
|
--mount \
|
||||||
--mount-proc \
|
--mount-proc \
|
||||||
--uts --ipc --net \
|
--uts --ipc --net \
|
||||||
"$chroot" "$TENV_ROOT" /bin/chrootsetup.sh "$@"
|
"$chroot" "$TENV_ROOT" /sbin/chrootsetup.sh "$@"
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
prefix=@prefix@
|
prefix=@prefix@
|
||||||
exec_prefix=@exec_prefix@
|
exec_prefix=@exec_prefix@
|
||||||
|
|
||||||
export TESTENV_PATH=/bin:/sbin:"@bindir@":"@sbindir@"
|
export TESTENV_PATH=/bin:/sbin:/usr/bin:/usr/sbin:"@bindir@":"@sbindir@"
|
||||||
export FINIT_CONF="@FINIT_CONF@"
|
export FINIT_CONF="@FINIT_CONF@"
|
||||||
export FINIT_RCSD="@FINIT_RCSD@"
|
export FINIT_RCSD="@FINIT_RCSD@"
|
||||||
|
|||||||
Reference in New Issue
Block a user