mirror of
https://github.com/troglobit/finit.git
synced 2026-10-12 10:12:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
338521a748 | ||
|
|
6ae1083c99 | ||
|
|
846806747b | ||
|
|
8904ca993e | ||
|
|
efed0db16b | ||
|
|
11946f12d3 | ||
|
|
2ba359ed80 | ||
|
|
fafd524701 | ||
|
|
1ee6c9f46b | ||
|
|
a88eb82a68 | ||
|
|
a436a1c8cb | ||
|
|
7cb91854b0 | ||
|
|
939ae02a6a | ||
|
|
480d29175c | ||
|
|
ea68413512 | ||
|
|
4edfa9859e | ||
|
|
eb6291c943 | ||
|
|
756b7c3fb6 | ||
|
|
263aec292a | ||
|
|
5a946a4ea7 | ||
|
|
c90b4d797b | ||
|
|
6e7a2fb6d5 | ||
|
|
ddedcf77e8 | ||
|
|
924ec2ef80 | ||
|
|
a49f27c191 | ||
|
|
b41b4ce989 | ||
|
|
3d74e93fa2 | ||
|
|
443700a88e | ||
|
|
4701edef4c | ||
|
|
e6da0a22e7 | ||
|
|
7be2bbbc30 | ||
|
|
3e269c632f | ||
|
|
f2507d9fd7 | ||
|
|
e9f403bceb | ||
|
|
c03176c42a | ||
|
|
9707bfb103 | ||
|
|
11430f83c8 | ||
|
|
a22a794f55 | ||
|
|
5556501287 | ||
|
|
ab554568b2 | ||
|
|
b39a4498a3 | ||
|
|
dead2444e2 | ||
|
|
a58002588e | ||
|
|
28e101aaae | ||
|
|
6da8af8136 | ||
|
|
3069e753e1 | ||
|
|
aafd5c1010 | ||
|
|
2f51c8ea0d | ||
|
|
d1130473fc | ||
|
|
b682a5e4fe | ||
|
|
1fc0f36c6c | ||
|
|
5df5b22327 | ||
|
|
4153c7966d | ||
|
|
458d68533f | ||
|
|
63b5db38df | ||
|
|
2135639508 | ||
|
|
9c8cd6c024 | ||
|
|
450f498061 | ||
|
|
5769500afe | ||
|
|
dc61969164 | ||
|
|
6f0d448765 | ||
|
|
0c9b7a67e0 | ||
|
|
5db2fb2c32 | ||
|
|
f4d3ec1a9f | ||
|
|
51befb492c | ||
|
|
7850378e15 | ||
|
|
438d6b4e63 | ||
|
|
712f68f9da | ||
|
|
8a32ec5c92 | ||
|
|
081622a085 | ||
|
|
2526431d8e | ||
|
|
47d8a83668 | ||
|
|
f72f3febf9 |
@@ -10,12 +10,24 @@ jobs:
|
||||
name: Build and upload release tarball
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
MAKEFLAGS: -j3
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Installing dependencies ...
|
||||
run: |
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y install pkg-config jq libuev-dev libite-dev
|
||||
- name: Setting release variables ...
|
||||
id: build
|
||||
run: |
|
||||
ver=${GITHUB_REF#refs/tags/}
|
||||
echo "ver=${ver}" >> $GITHUB_OUTPUT
|
||||
if echo $ver | grep -qE '[0-9.]+(-alpha|-beta|-rc)[0-9]*'; then
|
||||
echo "pre=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "pre=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
- name: Creating Makefiles ...
|
||||
run: |
|
||||
./autogen.sh
|
||||
@@ -36,5 +48,6 @@ jobs:
|
||||
- uses: ncipollo/release-action@v1
|
||||
with:
|
||||
name: Finit v${{ github.ref_name }}
|
||||
prerelease: ${{ needs.build.outputs.pre }}
|
||||
bodyFile: "release.md"
|
||||
artifacts: "artifacts/*"
|
||||
|
||||
@@ -15,6 +15,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Check for any commits since last week
|
||||
id: schedule
|
||||
run: |
|
||||
commits="$(git log --format=%H --since='1 week ago')"
|
||||
if [ -n "$commits" ]; then
|
||||
@@ -22,10 +23,9 @@ jobs:
|
||||
else
|
||||
echo "run=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
distcheck:
|
||||
needs: schedule
|
||||
if: ${{ needs.schedule.outputs.run == 'true' }}
|
||||
if: ${{ needs.schedule.outputs.run }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
|
||||
+70
-3
@@ -4,8 +4,54 @@ Change Log
|
||||
All relevant changes are documented in this file.
|
||||
|
||||
|
||||
[4.4][UNRELEASED]
|
||||
-----------------
|
||||
[4.5][] - 2023-09-24
|
||||
--------------------
|
||||
|
||||
### Changes
|
||||
- Refactor `runparts` and `/etc/rc.local` to no longer block the main
|
||||
loop, allowing `initctl` calls to interact with Finit. Issue #356
|
||||
- Refactor the `run` stanza to no longer block the main loop, issue #362
|
||||
- Allow `sulogin` with a user different from `root`, issue #357
|
||||
- Allow disabling invocation of rescue mode from kernel command line
|
||||
- Add `initctl -f` to force-skip asking Finit for existing services
|
||||
when creating new services during bootstrap, e.g. `/etc/rc.local`
|
||||
- `initctl runlevel` now returns `N S` instead of `N 10` in bootstrap
|
||||
- Improved logging on failure to `execvp()` a run/task/service, now
|
||||
with `errno`, e.g., "No such file or directory" when the command
|
||||
is missing from `$PATH`
|
||||
- Add support for Bash completion to `initctl`, issue #360
|
||||
- Handle absolute path to `initctl [enable|disable]`, not supported
|
||||
- Update `finit.conf(5)` man page with the recommended directory
|
||||
hierarchy in `/etc/finit.d/`
|
||||
- The `runparts` code has been split into `/libexec/finit/runparts`
|
||||
- The `runparts` command now takes two options: `sysv` and `progress`.
|
||||
The former ensures only `SNNfoo` and `KNNfoo` scripts are run.
|
||||
- Add SysV Init Compatibility section to documentation
|
||||
- Increased MAX path for commands, and arguments: 64 -> 256
|
||||
- The bundled watchdog daemon no longer tries to log at startup, because
|
||||
syslog is not available yet, any startup message leak to console
|
||||
|
||||
### Fixes
|
||||
- Fix #227: believed to have been fixed in v4.3, the root cause was
|
||||
actually that Finit was waiting for a process that was no longer in
|
||||
the system. The fix is to ask the kernel on process-stop-timeout and
|
||||
replay the lost PID so that Finit can continue with reboot/shutdown
|
||||
- Fix #358: fix inotify events for `/etc/finit.conf`, improved log
|
||||
messages and error handling
|
||||
- Fix #361: cgroup move fail if run/task/services start as non-root.
|
||||
Regression in the v4.4 release cycle while adding support for the
|
||||
pre:/post:/ready: scripts. Now the latter scripts also properly run
|
||||
in their correct cgroup
|
||||
- Fix #366: document `fsck.*` kernel command line options and simplify
|
||||
the configure flags `--enable-fsckfix` and `--enable-fastboot` to
|
||||
only adjust the default values for the `fsck.*` options.
|
||||
- The `runparts` executor now skips backup files (`foo~`)
|
||||
- The `runparts` stanza now properly appends ` start` to scripts that
|
||||
start with `S[0-9]+`. This has been broken for a very long time.
|
||||
|
||||
|
||||
[4.4][] - 2023-05-15
|
||||
--------------------
|
||||
|
||||
> **Note 1:** this release contains changes to the `.conf` parser. If you
|
||||
> have .conf file statements with comment character (`#`) in the command
|
||||
@@ -307,6 +353,23 @@ All relevant changes are documented in this file.
|
||||
reload, halt, poweroff, suspend. Also, prevent `SIGHUP` and `SIGUSR1`
|
||||
signals when in shutdown or reboot
|
||||
* Fix #352: separate runlevel S from runlevel 0
|
||||
* Fix #355: regression in v3.2 stopping a process and its group
|
||||
|
||||
In Finit v3.2 a regression was introduced that affects the way Finit
|
||||
stops a supervised process and its process group.
|
||||
|
||||
Instead of sending SIGTERM to the process, and thus delegating the
|
||||
responsibility to that process to inform any children it may have, as
|
||||
of commit 91a9c83 Finit sends SIGTERM to the entire process group.
|
||||
For SIGKILL this is fine, SIGKILL only runs as cleanup and as a last
|
||||
ditch effort if the process doesn't respond to SIGTERM.
|
||||
|
||||
This regression, introduced in v3.2, directly affects services like
|
||||
`avahi-autoipd` that have forked off children that it needs to tell to
|
||||
exit cleanly before it returns. With the patch in question these
|
||||
children are never allowed to complete, which in turn causes lingering
|
||||
169.254 link-local addresses on interfaces.
|
||||
|
||||
* Fix bootmisc plugin: octal permission on `/run/lock` and `/var/lock`
|
||||
|
||||
* Ensure `initctl cond get` support the flux state (exit code 255)
|
||||
@@ -340,6 +403,9 @@ All relevant changes are documented in this file.
|
||||
However, on `initctl reload` (and no change to .conf files) the arg
|
||||
list was lost while parsing the .conf files. Leading to a false
|
||||
positive 'diff' in args causing nginx to be unnecessarily restarted.
|
||||
* Fix issue with disabled "linewrap" on the console TTY after login.
|
||||
The root cause is `qemu-system-x86_64 -nographics` disabling it when
|
||||
starting up. The correct `\e[?7h` escape code is now used.
|
||||
|
||||
|
||||
[4.3][] - 2022-05-15
|
||||
@@ -1490,7 +1556,8 @@ Major bug fix release.
|
||||
|
||||
* Initial release
|
||||
|
||||
[UNRELEASED]: https://github.com/troglobit/finit/compare/4.3...HEAD
|
||||
[UNRELEASED]: https://github.com/troglobit/finit/compare/4.5...HEAD
|
||||
[4.5]: https://github.com/troglobit/finit/compare/4.4...4.5
|
||||
[4.4]: https://github.com/troglobit/finit/compare/4.3...4.4
|
||||
[4.3]: https://github.com/troglobit/finit/compare/4.2...4.3
|
||||
[4.2]: https://github.com/troglobit/finit/compare/4.1...4.2
|
||||
|
||||
+3
-1
@@ -30,4 +30,6 @@ release: distcheck
|
||||
printf "$$file.sha256\t"; cat ../$$file.sha256 | cut -f1 -d' '; \
|
||||
done
|
||||
|
||||
DISTCHECK_CONFIGURE_FLAGS = --with-fstab=/etc/fstab
|
||||
DISTCHECK_CONFIGURE_FLAGS = --prefix=/usr --sysconfdir=/etc --localstatedir=/var \
|
||||
--enable-testserv-plugin --enable-x11-common-plugin \
|
||||
--with-watchdog --with-keventd --with-fstab=/etc/fstab
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
# Run test suite with the correct configure params
|
||||
|
||||
make distclean
|
||||
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
|
||||
--enable-x11-common-plugin --with-watchdog --with-keventd
|
||||
make -j17 clean check
|
||||
+19
-6
@@ -1,4 +1,4 @@
|
||||
AC_INIT([Finit],[4.4-rc1],[https://github.com/troglobit/finit/issues],[finit],[https://troglobit.com/projects/finit/])
|
||||
AC_INIT([Finit],[4.5-rc3],[https://github.com/troglobit/finit/issues],[finit],[https://troglobit.com/projects/finit/])
|
||||
AC_CONFIG_AUX_DIR(aux)
|
||||
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
|
||||
AM_SILENT_RULES([yes])
|
||||
@@ -71,7 +71,7 @@ AC_ARG_ENABLE(redirect,
|
||||
enable_redirect=yes])
|
||||
|
||||
AC_ARG_ENABLE(logrotate,
|
||||
AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp, default enabled]),,[
|
||||
AS_HELP_STRING([--disable-logrotate], [Disable built-in rotation of /var/log/wtmp]),,[
|
||||
enable_logrotate=yes])
|
||||
|
||||
AC_ARG_ENABLE(doc,
|
||||
@@ -82,6 +82,10 @@ AC_ARG_ENABLE(contrib,
|
||||
AS_HELP_STRING([--disable-contrib], [Disable build and install of contrib section]),,[
|
||||
enable_contrib=yes])
|
||||
|
||||
AC_ARG_ENABLE([rescue],
|
||||
AS_HELP_STRING([--disable-rescue], [Disable potentially unsafe rescue mode]),,
|
||||
[enable_rescue=yes])
|
||||
|
||||
# Check for extra plugins to enable
|
||||
AC_ARG_ENABLE(all_plugins,
|
||||
AS_HELP_STRING([--enable-all-plugins], [Enable all plugins, default: auto]),
|
||||
@@ -145,10 +149,10 @@ AC_ARG_WITH(keventd,
|
||||
AS_HELP_STRING([--with-keventd], [Enable built-in keventd, default: no]),, [with_keventd=no])
|
||||
|
||||
AC_ARG_WITH(sulogin,
|
||||
AS_HELP_STRING([--with-sulogin], [Enable built-in sulogin, default: no.]),, [with_sulogin=no])
|
||||
AS_HELP_STRING([--with-sulogin@<:@=USER@:>@], [Enable built-in sulogin, optional USER to request password for (default root), default: no.]),[sulogin=$withval],[with_sulogin=no])
|
||||
|
||||
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=])
|
||||
|
||||
AC_ARG_WITH(hook-scripts-path,
|
||||
@@ -185,6 +189,9 @@ AS_IF([test "x$enable_redirect" = "xyes"], [
|
||||
AS_IF([test "x$enable_logrotate" != "xno"], [
|
||||
AC_DEFINE(LOGROTATE_ENABLED, 1, [Enable built-in rotation of /var/log/wtmp et al.])])
|
||||
|
||||
AS_IF([test "x$enable_rescue" != "xno"], [
|
||||
AC_DEFINE([RESCUE_MODE], 1, [Define to enable support for rescue mode.])])
|
||||
|
||||
AM_CONDITIONAL(LOGROTATE, [test "x$enable_logrotate" = "xyes"])
|
||||
|
||||
### With features ##############################################################################
|
||||
@@ -252,7 +259,12 @@ AS_IF([test "x$rtc_date" != "xno"], [
|
||||
|
||||
AS_IF([test "x$with_keventd" != "xno"], [with_keventd=yes])
|
||||
|
||||
AS_IF([test "x$with_sulogin" != "xno"], [with_sulogin=yes])
|
||||
AS_IF([test "x$with_sulogin" != "xno"], [
|
||||
AS_IF([test "x$sulogin" = "xyes"], [
|
||||
sulogin=root])
|
||||
with_sulogin=yes
|
||||
AC_DEFINE_UNQUOTED(SULOGIN_USER, "$sulogin", [Built-in sulogin user, default: root])], [
|
||||
sulogin=])
|
||||
|
||||
AS_IF([test "x$with_watchdog" != "xno"], [
|
||||
AS_IF([test "x$watchdog" = "xyes"], [
|
||||
@@ -344,12 +356,13 @@ Optional features:
|
||||
Install doc/..........: $enable_doc
|
||||
Install contrib/......: $enable_contrib
|
||||
Built-in keventd......: $with_keventd
|
||||
Built-in sulogin......: $with_sulogin
|
||||
Built-in sulogin......: $with_sulogin $sulogin
|
||||
Built-in watchdogd....: $with_watchdog $watchdog
|
||||
Built-in logrotate....: $enable_logrotate
|
||||
Skip fsck check.......: $enable_fastboot
|
||||
Run fsck fix mode.....: $enable_fsckfix
|
||||
Redirect output.......: $enable_redirect
|
||||
Rescue mode...........: $enable_rescue
|
||||
Default hostname......: $hostname
|
||||
Default group.........: $group
|
||||
Default runlevel......: $runlevel
|
||||
|
||||
@@ -17,7 +17,7 @@ PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig ./configure \
|
||||
--prefix=/usr --exec-prefix= \
|
||||
--sysconfdir=/etc --localstatedir=/var \
|
||||
--enable-dbus-plugin --enable-x11-common-plugin \
|
||||
--enable-alsa-utils-plugin --with-watchdog \
|
||||
--enable-alsa-utils-plugin --without-watchdog \
|
||||
--with-keventd --with-sulogin
|
||||
|
||||
echo
|
||||
|
||||
+16
-4
@@ -12,6 +12,15 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
|
||||
* `debug`: Enable kernel debug. Debug messages are printed to the
|
||||
console until Finit starts up, unless `loglevel=7` (below) is used.
|
||||
|
||||
* `fsck.mode=<auto,force,skip>`, default: `auto`, unless built with
|
||||
`configure --enable-fastboot`, in which case the default is `skip`
|
||||
|
||||
* `fsck.repair=<preen,yes,no>`, default: `preen`, unless built with
|
||||
`configure --enable-fsckfix`, in which case the default is `yes`.
|
||||
This configure option also sets `fsck.mode=force`, unless fastboot
|
||||
is selected at the same time. I.e., the `--enable-fastboot` build
|
||||
option overrides the `fsck.mode` default value.
|
||||
|
||||
* `finit.cond=foo[,bar[,baz]]`: set `<boot/foo>` condition, optionally
|
||||
multiple conditions can be set using the same option, separated with a
|
||||
comma. Alternatively, multiple `foo.cond=arg` can be given. Each will
|
||||
@@ -86,13 +95,16 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
|
||||
the system booted in a limited fallback mode. See [config.md][]
|
||||
for more information.
|
||||
|
||||
This option can be disabled with `configure --without-rescue`
|
||||
|
||||
**Note:** in this mode `initctl` will not work. Correct the problem
|
||||
and use `reboot -f` to force reboot.
|
||||
|
||||
* `single`, or `S`: Single user mode, runlevel 1, in Finit. Useful to
|
||||
debug problems with the regular runlevel. All services and TTYs in
|
||||
`[1]` will be started, so a `tty [1] @console nologin` configuration
|
||||
presents you with a root console without login.
|
||||
* `single`, or `S`: Overrides the configured runlevel (default: 2) to go
|
||||
to after bootstrap by forcing it to runlevel 1, this is also known
|
||||
as single user mode. Useful to debug startup problems. All services
|
||||
and TTYs in `[1]` will be started, so a `tty [1] @console nologin`
|
||||
configuration presents you with a root console without login.
|
||||
|
||||
* `1-9`, except `6`: override the configured `runlevel`. Like the `S`
|
||||
and `rescue`, giving a single number on the kernel command line tells
|
||||
|
||||
+139
-43
@@ -28,6 +28,7 @@ Finit Configuration
|
||||
* [TTYs and Consoles](#ttys-and-consoles)
|
||||
* [Non-privileged Services](#non-privileged-services)
|
||||
* [Redirecting Output](#redirecting-output)
|
||||
* [SysV Init Compatibility](#sysv-init-compatibility)
|
||||
* [Rescue Mode](#rescue-mode)
|
||||
* [Limitations](#limitations)
|
||||
* [/etc/finit.conf](#etcfinitconf)
|
||||
@@ -45,14 +46,15 @@ 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.,
|
||||
PID file monitoring, or [conditions](conditions.md).
|
||||
|
||||
> **Tip:** see [SysV Init Compatibility](#sysv-init-compatibility) for
|
||||
> help to quickly get going with an existing SysV or BusyBox init setup.
|
||||
|
||||
|
||||
### Configuration Files
|
||||
|
||||
Originally Finit was configured using a single file, `/etc/finit.conf`.
|
||||
Although still possible, today we recommended using the Apache-style
|
||||
`available/*.conf` and `enabled/*.conf` layaout. These are called
|
||||
dynamic services, in contrast to static -- the only difference being
|
||||
where they are installed and if the `initctl` tool can manage them.
|
||||
Although still possible to use this single configuration file, today the
|
||||
following familiar layout is recommended:
|
||||
|
||||
/etc/
|
||||
|- finit.d/
|
||||
@@ -62,9 +64,15 @@ where they are installed and if the `initctl` tool can manage them.
|
||||
: | `- my-service.conf -> ../available/my-service.conf
|
||||
: :
|
||||
: |- static-service.conf
|
||||
: `- another-static.conf # eg. bootstrap run/task commands
|
||||
: `- another-static.conf
|
||||
:
|
||||
`- finit.conf # global settings
|
||||
`- finit.conf
|
||||
|
||||
Services in the `available/` and `enabled/` sub-directories are called
|
||||
dynamic services, in contrast to static services -- the only difference
|
||||
being where they are installed and if the `initctl` tool can manage them
|
||||
with the `enable` and `disable` commands. An administrator can always
|
||||
create files and symlinks manually.
|
||||
|
||||
At bootstrap, and `initctl reload`, all .conf files are read, starting
|
||||
with `finit.conf`, then, in alphabetical order, all `finit.d/*.conf`
|
||||
@@ -131,8 +139,8 @@ as listed above, provided their respective mount point exists.
|
||||
With all filesystems mounted, Finit calls `swapon`.
|
||||
|
||||
At shutdown, and after having stopped all services and other lingering
|
||||
processes killed, filesystems are unmounted in the reverse order, and
|
||||
`swapoff` is called.
|
||||
processes have been killed, filesystems are unmounted in the reverse
|
||||
order, and `swapoff` is called.
|
||||
|
||||
[FHS]: https://refspecs.linuxfoundation.org/FHS_3.0/fhs/index.html
|
||||
|
||||
@@ -574,19 +582,37 @@ Finit disables networking in this mode.
|
||||
|
||||
**Syntax:** `run [LVLS] <COND> /path/to/cmd ARGS -- Optional description`
|
||||
|
||||
One-shot command to run in sequence when entering a runlevel, with
|
||||
optional arguments and description.
|
||||
|
||||
`run` commands are guaranteed to be completed before running the next
|
||||
command. Highly useful if true serialization is needed.
|
||||
|
||||
> `<COND>` is described in the [Services](#services) section.
|
||||
|
||||
One-shot command to run in sequence when entering a runlevel, with
|
||||
optional arguments and description. `run` commands are guaranteed to be
|
||||
completed before running the next command. Useful when serialization is
|
||||
required.
|
||||
|
||||
> **Warning:** try to avoid the `run` command. It blocks much of the
|
||||
> functionality in Finit, like (re)starting other (perhaps crashing)
|
||||
> services while a `run` task is executing. Use other synchronization
|
||||
> mechanisms instead, like conditions.
|
||||
|
||||
Incomplete list of unsupported `initctl` commands in `run` tasks:
|
||||
|
||||
- `initctl runlevel N`, setting runlevel
|
||||
- `initctl reboot`
|
||||
- `initctl halt`
|
||||
- `initctl poweroff`
|
||||
- `initctl suspend`
|
||||
|
||||
To prevent `initctl` from calling Finit when enabling and disabling
|
||||
services from inside a `run` task, use the `--force` option. See
|
||||
also the `--quiet` and `--batch` options.
|
||||
|
||||
|
||||
### One-shot Commands (parallel)
|
||||
|
||||
**Syntax:** `task [LVLS] <COND> /path/to/cmd ARGS -- Optional description`
|
||||
|
||||
> `<COND>` is described in the [Services](#services) section.
|
||||
|
||||
One-shot like 'run', but starts in parallel with the next command.
|
||||
|
||||
Both `run` and `task` commands are run in a shell, so pipes and
|
||||
@@ -594,13 +620,13 @@ redirects can be freely used:
|
||||
|
||||
task [s] echo "foo" | cat >/tmp/bar
|
||||
|
||||
> `<COND>` is described in the [Services](#services) section.
|
||||
|
||||
|
||||
### SysV Init Scripts
|
||||
|
||||
**Syntax:** `sysv [LVLS] <COND> /path/to/init-script -- Optional description`
|
||||
|
||||
> `<COND>` is described in the [Services](#services) section.
|
||||
|
||||
Similar to `task` is the `sysv` stanza, which can be used to call SysV
|
||||
style scripts. The primary intention for this command is to be able to
|
||||
re-use much of existing setup and init scripts in Linux distributions.
|
||||
@@ -618,7 +644,7 @@ 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.
|
||||
> **Tip:** see also [SysV Init Compatibility](#sysv-init-compatibility).
|
||||
|
||||
|
||||
### Services
|
||||
@@ -816,7 +842,7 @@ the above `kill:SEC` syntax.
|
||||
|
||||
### Run-parts Scripts
|
||||
|
||||
**Syntax:** `runparts <DIR>`
|
||||
**Syntax:** `runparts [progress] [sysv] <DIR>`
|
||||
|
||||
Call [run-parts(8)][] on `DIR` to run start scripts. All executable
|
||||
files, or scripts, in the directory are called, in alphabetic order.
|
||||
@@ -826,27 +852,25 @@ The scripts in this directory are executed at the very end of runlevel
|
||||
A common use-case for runparts scripts is to create and enable/disable
|
||||
services, which Finit will then apply when changing runlevel from S to
|
||||
whatever the next runlevel is set to be (default 2). E.g., generate a
|
||||
`/etc/chrony.conf` and `initctl enable chronyd`.
|
||||
`/etc/chrony.conf` and call `initctl enable chronyd`.
|
||||
|
||||
**Options:**
|
||||
|
||||
- `progress`: display the progress of each script being executed
|
||||
- `sysv`: run only SysV style scripts, i.e., `SNNfoo`, or `KNNbar`,
|
||||
where `NN` is a number (0-99).
|
||||
|
||||
If global debug mode is enabled, the `runparts` program is also called
|
||||
with the debug flag.
|
||||
|
||||
**Limitations:**
|
||||
|
||||
Scripts called from `runparts`, or hook scripts (see below), are limited
|
||||
in what they can do and expect from Finit:
|
||||
|
||||
1. Finit is single threaded and all scripts executed from these two
|
||||
mechanisms are limited to file system operations (early or late
|
||||
hooks may not have write access!) and standard UNIX programs.
|
||||
2. Thus, it is *not possible* to call `initctl` to query status of
|
||||
services since that calls Finit over the `/run/finit/socket`.
|
||||
3. Confusingly enough, there are some commands to `initctl` that are
|
||||
available; `ls`, `enable`, `disable`, `touch`, `create`, `delete`,
|
||||
and all the `cond` commands. Because all these are basically just
|
||||
wrappers for manipulating files (again, write access for early/late
|
||||
hooks may not be available).
|
||||
|
||||
Also, similar to the `/etc/rc.local` shell script, make sure that all
|
||||
your services and programs either terminate or start in the background
|
||||
or you will block Finit.
|
||||
in their interaction with Finit. Like the standalone `run` stanza and
|
||||
the `/etc/rc.local` shell script, Finit waits for their completion
|
||||
before continuing. None of them can issue commands to start, stop, or
|
||||
restart other services. Also, ensure all your services and programs
|
||||
either terminate or start in the background or you will block Finit.
|
||||
|
||||
> **Note:** `runparts` scrips are only read and executed in runlevel S
|
||||
> ([bootstrap][]). See [hook scripts](plugins.md#hooks) for other ways
|
||||
@@ -1044,6 +1068,72 @@ sync(2) has been called, twice.
|
||||
> finally written.
|
||||
|
||||
|
||||
SysV Init Compatibility
|
||||
-----------------------
|
||||
|
||||
It is not possible to run unmodified SysV init systems with Finit. This
|
||||
was never the intention and is not the strength of Finit. However, it
|
||||
comes with a few SysV Init compatibility features to ease the transition
|
||||
from a serialized boot process.
|
||||
|
||||
### `runparts DIRECTORY`
|
||||
|
||||
For a directory with traditional start/stop scripts that should run, in
|
||||
order, at bootstrap, Finit provides the `runparts` directive. It runs
|
||||
in runlevel S, at the very end of it (before calling `/etc/rc.local`)
|
||||
making it perfect for most scenarios.
|
||||
|
||||
For syntax details, see [Run-parts Scripts](#run-parts-scripts) above.
|
||||
Here is an example take from a Debian installation:
|
||||
|
||||
runparts /etc/rc2.d
|
||||
|
||||
Files in these directories are usually named `SNNfoo` and `KNNfoo`,
|
||||
which Finit knows about and automatically appends the correct argument:
|
||||
|
||||
/bin/sh -c /etc/rc2.d/S01openbsd-inetd start
|
||||
|
||||
or
|
||||
|
||||
/bin/sh -c /etc/rc0.d/K01openbsd-inetd stop
|
||||
|
||||
Files that do not match this pattern are started similarly but without
|
||||
the extra command line argument.
|
||||
|
||||
|
||||
### Start/Stop Scripts
|
||||
|
||||
For syntax details, see [SysV Init Scripts](#sysv-init-scripts), above.
|
||||
Here follows an example taken from a Debian installation:
|
||||
|
||||
sysv [2345] <pid/syslogd> /etc/init.d/openbsd-inetd -- OpenBSD inet daemon
|
||||
|
||||
The init script header could be parsed to extract `Default-Start:` and
|
||||
other parameters for the `sysv` command to Finit. There is currently no
|
||||
way to detail a generic syslogd dependency in Finit, so `Should-Start:`
|
||||
in the header must be mapped to the condition system in Finit using an
|
||||
absolute reference, here we depend on the sysklogd project's syslogd.
|
||||
|
||||
### `/etc/rc.local`
|
||||
|
||||
One often requested feature, early on, was a way to run a site specific
|
||||
script to set up, e.g., static routes or firewall rules. A user can add
|
||||
a `task` or `run` command in the Finit configuration for this, but for
|
||||
compatibility reasons the more widely know `/etc/rc.local` is used if
|
||||
it exists, and is executable. It is called very late in the boot process
|
||||
when the system has left runlevel S, stopped all old and started all new
|
||||
services in the target runlevel (default 2).
|
||||
|
||||
> In Finit releases before v4.5 this script blocked Finit execution and
|
||||
> made it as good as impossible to call `initctl` during that time.
|
||||
|
||||
### `init q`
|
||||
|
||||
When `/sbin/finit` is installed as `/sbin/init`, it is possible to use
|
||||
`init q` to reload the configuration. This is the same as calling
|
||||
`initctl reload`.
|
||||
|
||||
|
||||
Rescue Mode
|
||||
-----------
|
||||
|
||||
@@ -1051,6 +1141,10 @@ Finit supports a rescue mode which is activated by the `rescue` option
|
||||
on the kernel command line. See [cmdline docs](cmdline.md) for how to
|
||||
activate it.
|
||||
|
||||
This rescue mode can be disabled at configure time using:
|
||||
|
||||
configure --without-rescue
|
||||
|
||||
The rescue mode comes in two flavors; *traditional* and *fallback*.
|
||||
|
||||
> **Note:** in this mode `initctl` will not work. Use the `-f` flag to
|
||||
@@ -1060,15 +1154,17 @@ The rescue mode comes in two flavors; *traditional* and *fallback*.
|
||||
### Traditional
|
||||
|
||||
This is what most users expect. A very early maintenance login prompt,
|
||||
served by the bundled `/libexec/finit/sulogin` program, or the standard
|
||||
`sulogin` from util-linux or BusyBox is searched for in the UNIX default
|
||||
`$PATH`. If a successful login is made, or the user exits (Ctrl-D), the
|
||||
rescue mode is ended and the system boots up normally.
|
||||
served by the system `sulogin` program from util-linux, or BusyBox. If
|
||||
that is not found in `$PATH`, the bundled `/libexec/finit/sulogin`
|
||||
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
|
||||
normally.
|
||||
|
||||
> **Note:** if the user (UID 0 and GID 0) does not have a password, or
|
||||
> __the account is locked__, the user is presented with a password-less
|
||||
> `"Press enter to enter maintenance mode."`, prompt which opens up a
|
||||
> root shell.
|
||||
> **Note:** the bundled sulogin in Finit can at configure time be given
|
||||
> another user than the default (root). If the sulogin user does not
|
||||
> have a password, or __the account is locked__, the user is presented
|
||||
> with a password-less `"Press enter to enter maintenance mode."`,
|
||||
> prompt which opens up a root shell.
|
||||
|
||||
|
||||
### Fallback
|
||||
|
||||
+2
-2
@@ -136,7 +136,7 @@ hook points:
|
||||
**Example:**
|
||||
|
||||
$ mkdir -p /libexec/finit/hook/sys/down
|
||||
$ cat <<EOF >/libexec/finit/hook/sys/foo.sh
|
||||
$ cat <<EOF >/libexec/finit/hook/sys/down/foo.sh
|
||||
#!/bin/sh
|
||||
echo 'I run just before the reboot() syscall at shutdown/reboot'
|
||||
echo 'I have access to /dev since devtmpfs is exempt from umount'
|
||||
@@ -146,7 +146,7 @@ hook points:
|
||||
fi
|
||||
exit 0
|
||||
EOF
|
||||
$ chmod +x /libexec/finit/hook/sys/foo.sh
|
||||
$ chmod +x /libexec/finit/hook/sys/down/foo.sh
|
||||
|
||||
> **Note:** to use hook scripts, even for pre-bootstrap and pre-shutdown
|
||||
> tasks, you must build with `configure --enable-hook-scripts-plugin`.
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
_cond()
|
||||
{
|
||||
initctl -pt cond dump | awk '{print $4}' | sed 's/<\(.*\)>/\1/'
|
||||
}
|
||||
|
||||
_ident()
|
||||
{
|
||||
if [ -n "$1" ]; then
|
||||
initctl ident | grep -q $1
|
||||
else
|
||||
initctl ident
|
||||
fi
|
||||
}
|
||||
|
||||
_svc()
|
||||
{
|
||||
initctl ls -pt | grep $1 | sed "s/.*\/\(.*\)/\1/g" | sort -u
|
||||
}
|
||||
|
||||
_enabled()
|
||||
{
|
||||
echo "$(_svc enabled)"
|
||||
}
|
||||
|
||||
_available()
|
||||
{
|
||||
all=$(mktemp)
|
||||
ena=$(mktemp)
|
||||
echo "$(_svc available)" >$all
|
||||
echo "$(_svc enabled)" >$ena
|
||||
grep -v -f $ena $all
|
||||
rm $all $ena
|
||||
}
|
||||
|
||||
# Determine first non-option word. Usually the command
|
||||
_firstword() {
|
||||
local firstword i
|
||||
|
||||
firstword=
|
||||
for ((i = 1; i < ${#COMP_WORDS[@]}; ++i)); do
|
||||
if [[ ${COMP_WORDS[i]} != -* ]]; then
|
||||
firstword=${COMP_WORDS[i]}
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
echo $firstword
|
||||
}
|
||||
|
||||
# Determine last non-option word. Uusally a sub-command
|
||||
_lastword() {
|
||||
local lastword i
|
||||
|
||||
lastword=
|
||||
for ((i = 1; i < ${#COMP_WORDS[@]}; ++i)); do
|
||||
if [[ ${COMP_WORDS[i]} != -* ]] && [[ -n ${COMP_WORDS[i]} ]] && [[ ${COMP_WORDS[i]} != $cur ]]; then
|
||||
lastword=${COMP_WORDS[i]}
|
||||
fi
|
||||
done
|
||||
|
||||
echo $lastword
|
||||
}
|
||||
|
||||
_initctl()
|
||||
{
|
||||
local cur command
|
||||
|
||||
cur=${COMP_WORDS[COMP_CWORD]}
|
||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
firstword=$(_firstword)
|
||||
lastword=$(_lastword)
|
||||
|
||||
commands="status cond debug help kill ls log version list enable \
|
||||
disable touch show cat edit create delete reload start \
|
||||
stop restart signal cgroup ps top plugins runlevel reboot \
|
||||
halt poweroff suspend utmp"
|
||||
cond_cmds="set get clear status dump"
|
||||
cond_types="hook net pid service task usr"
|
||||
signals="int term hup stop tstp cont usr1 usr2 pwr"
|
||||
options="-b --batch \
|
||||
-c --create \
|
||||
-d --debug \
|
||||
-f --force \
|
||||
-h --help \
|
||||
-j --json \
|
||||
-n --noerr \
|
||||
-1 --once \
|
||||
-p --plain \
|
||||
-q --quiet \
|
||||
-t --no-heading \
|
||||
-v --verbose \
|
||||
-V --version"
|
||||
|
||||
case "${firstword}" in
|
||||
enable)
|
||||
COMPREPLY=($(compgen -W "$(_available)" -- $cur))
|
||||
;;
|
||||
disable|touch)
|
||||
COMPREPLY=($(compgen -W "$(_enabled)" -- $cur))
|
||||
;;
|
||||
show|cat|edit|delete)
|
||||
COMPREPLY=($(compgen -W "$(_svc .)" -- $cur))
|
||||
;;
|
||||
start|stop|restart|log|status)
|
||||
COMPREPLY=($(compgen -W "$(_ident)" -- $cur))
|
||||
;;
|
||||
signal|kill)
|
||||
if $(_ident "${prev}"); then
|
||||
COMPREPLY=($(compgen -W "$signals" -- $cur))
|
||||
else
|
||||
COMPREPLY=($(compgen -W "$(_ident)" -- $cur))
|
||||
fi
|
||||
;;
|
||||
cond)
|
||||
case "${lastword}" in
|
||||
set|clear)
|
||||
compopt -o nospace
|
||||
COMPREPLY=($(compgen -W "usr/" -- $cur))
|
||||
;;
|
||||
get)
|
||||
COMPREPLY=($(compgen -W "$(_cond)" -- $cur))
|
||||
;;
|
||||
dump)
|
||||
COMPREPLY=($(compgen -W "$cond_types" -- $cur))
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=($(compgen -W "$cond_cmds" -- $cur))
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=($(compgen -W "$commands" -- $cur))
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ $cur == -* ]]; then
|
||||
COMPREPLY=($(compgen -W "$options" -- $cur))
|
||||
fi
|
||||
}
|
||||
|
||||
complete -F _initctl initctl
|
||||
+1
-1
@@ -275,7 +275,7 @@ The following condition families are available today:
|
||||
Linux netlink events, e.g. net/route/default, net/eth0/up, and
|
||||
net/et0/running
|
||||
.It Cm pid
|
||||
PID files basd on the service declaration
|
||||
PID files based on the service declaration
|
||||
.Cm name:id ,
|
||||
gives the condition pid/name:id
|
||||
.It Cm service
|
||||
|
||||
+50
-26
@@ -2,7 +2,7 @@
|
||||
.\" First parameter, NAME, should be all caps
|
||||
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||
.\" other parameters are allowed: see man(7), man(1)
|
||||
.Dd Apr 24, 2023
|
||||
.Dd July 11, 2023
|
||||
.Dt FINIT.CONF 5 SMM
|
||||
.Os Linux
|
||||
.Sh NAME
|
||||
@@ -12,40 +12,64 @@
|
||||
.Nm /etc/finit.conf
|
||||
.Nm /etc/finit.d/*.conf
|
||||
.Nm /etc/finit.d/available/*.conf
|
||||
.Nm /etc/finit.d/enabled/*.conf
|
||||
.Sh DESCRIPTION
|
||||
.Nm finit
|
||||
can be configured using only the original
|
||||
.Pa /etc/finit.conf
|
||||
file or in combination with
|
||||
.Pa /etc/finit.d/*.conf .
|
||||
Useful for package-based Linux distributions \(em each package can
|
||||
provide its own "script" file.
|
||||
.Nm Finit
|
||||
based systems can be set up with a single file:
|
||||
.Pa /etc/finit.conf .
|
||||
This is the traditional way of doing it which can be ideal for some
|
||||
setups since it gives a great overview of the system configuration.
|
||||
.Pp
|
||||
.Bl -tag -width /etc/finit.d/*.conf -offset indent -compact
|
||||
.It Pa /etc/finit.conf
|
||||
Main configuration file
|
||||
.It Pa /etc/finit.d/*.conf
|
||||
Snippets, usually one service per file
|
||||
.El
|
||||
More comprehensive setups, however, require more careful planning.
|
||||
The recommendation is per-package
|
||||
.Cm *.conf
|
||||
files in
|
||||
.Pa /etc/finit.d/available/ .
|
||||
This allows end users to enable and disable parts of the system
|
||||
configuration at runtime. Finit tracks which tasks and services belong
|
||||
to a given file, so that when the user calls
|
||||
.Cm initctl reload
|
||||
to activate the changes they have made, only the affected tasks and
|
||||
services are stopped, started, or restarted. Hence, this approach is
|
||||
useful for modern package-based Linux distributions.
|
||||
.Pp
|
||||
Not all configuration directives are available in
|
||||
.Pa /etc/finit.d/*.conf
|
||||
and some directives are only available at bootstrap, runlevel
|
||||
.Cm S ,
|
||||
see the section
|
||||
.Sx Limitations
|
||||
below for details.
|
||||
The following sections describe the more of this in detail, starting
|
||||
with files, the file format, and available directives. Remember to
|
||||
also visit the other manual pages (references at the bottom).
|
||||
.Sh FILES
|
||||
.Bl -tag -width /etc/finit.d/available/*.conf -compact
|
||||
.It Pa /etc/finit.conf
|
||||
Main configuration file
|
||||
Main configuration file, optional
|
||||
.It Pa /etc/finit.d/*.conf
|
||||
Static service definitions
|
||||
Static (system) service definitions
|
||||
.It Pa /etc/finit.d/available/*.conf
|
||||
Available services
|
||||
Available (installed) services
|
||||
.It Pa /etc/finit.d/enabled/*.conf
|
||||
Enabled services, symlinks from available
|
||||
Enabled services (symlink back)
|
||||
.El
|
||||
.Pp
|
||||
Static services,
|
||||
.Cm .conf
|
||||
files in
|
||||
.Pa /etc/finit.d/ ,
|
||||
cannot be enabled or disabled using
|
||||
.Cm initctl [enable | disable] service[.conf] .
|
||||
An enabled service is a symlink back to the corresponding
|
||||
.Cm ../available/
|
||||
service
|
||||
.Cm .conf
|
||||
file. Please use the
|
||||
.Cm initctl
|
||||
tool to manage these symlinks to ensure proper operation.
|
||||
.Pp
|
||||
.Sy NOTE:
|
||||
Previous versions of
|
||||
.Nm Finit
|
||||
created symlinks in
|
||||
.Pa /etc/finit.d/
|
||||
if
|
||||
.Pa /etc/finit.d/enabled/
|
||||
was missing, this is as of v4.4 not supported.
|
||||
.Sh FILE FORMAT
|
||||
The file format is line based, empty lines and comments, lines starting
|
||||
with `#', are ignored. A configuration directive starts with a keyword
|
||||
@@ -960,6 +984,6 @@ settings in
|
||||
.Xr finit 8 ,
|
||||
.Xr initctl 8
|
||||
.Sh AUTHORS
|
||||
.Nm finit
|
||||
.Nm Finit
|
||||
was conceived and reverse engineered by Claudio Matsuoka. Since v1.0,
|
||||
maintained by Joachim Wiberg, with contributions by many others.
|
||||
|
||||
@@ -101,7 +101,7 @@ static int modules_load(const char *file, int index)
|
||||
}
|
||||
|
||||
while ((line = fparseln(fp, NULL, NULL, NULL, 0))) {
|
||||
char cmd[CMD_SIZE * 2], *mod, *args, *set;
|
||||
char cmd[CMD_SIZE], *mod, *args, *set;
|
||||
|
||||
/*
|
||||
* fparseln() skips regular UNIX comments only.
|
||||
|
||||
@@ -45,7 +45,7 @@ static void setup(void *arg)
|
||||
|
||||
touch("/etc/resolvconf/run/enable-updates");
|
||||
chdir("/etc/resolvconf/run/interface");
|
||||
run_parts("/etc/resolvconf/update.d", "-i", NULL, 0);
|
||||
run_parts("/etc/resolvconf/update.d", "-i", NULL, 0, 0);
|
||||
chdir("/");
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ initctl
|
||||
keventd
|
||||
logit
|
||||
reboot
|
||||
runparts
|
||||
sulogin
|
||||
watchdogd
|
||||
Makefile
|
||||
|
||||
+7
-2
@@ -8,7 +8,7 @@ AM_LDFLAGS = -export-dynamic
|
||||
endif
|
||||
|
||||
sbin_PROGRAMS = finit initctl
|
||||
pkglibexec_PROGRAMS = getty logit
|
||||
pkglibexec_PROGRAMS = getty logit runparts
|
||||
if SULOGIN
|
||||
pkglibexec_PROGRAMS += sulogin
|
||||
endif
|
||||
@@ -32,6 +32,11 @@ keventd_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||
keventd_CFLAGS += $(lite_CFLAGS)
|
||||
keventd_LDADD = $(lite_LIBS)
|
||||
|
||||
runparts_SOURCES = runparts.c
|
||||
runparts_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||
runparts_CFLAGS += $(lite_CFLAGS)
|
||||
runparts_LDADD = $(lite_LIBS)
|
||||
|
||||
sulogin_SOURCES = sulogin.c
|
||||
sulogin_CFLAGS = -W -Wall -Wextra -std=gnu99
|
||||
sulogin_LDADD = -lcrypt
|
||||
@@ -54,7 +59,7 @@ finit_SOURCES = api.c cgroup.c cgroup.h \
|
||||
mdadm.c mount.c \
|
||||
pid.c pid.h \
|
||||
plugin.c plugin.h private.h \
|
||||
schedule.c schedule.h \
|
||||
runparts.c schedule.c schedule.h \
|
||||
service.c service.h \
|
||||
sig.c sig.h \
|
||||
sm.c sm.h \
|
||||
|
||||
@@ -65,6 +65,7 @@ static int stop(svc_t *svc, void *user_data)
|
||||
service_timeout_cancel(svc);
|
||||
svc_stop(svc);
|
||||
service_step(svc);
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -77,6 +78,7 @@ static int start(svc_t *svc, void *user_data)
|
||||
service_timeout_cancel(svc);
|
||||
svc_start(svc);
|
||||
service_step(svc);
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+111
-19
@@ -62,8 +62,29 @@ static TAILQ_HEAD(, env_entry) env_list = TAILQ_HEAD_INITIALIZER(env_list);
|
||||
struct rlimit initial_rlimit[RLIMIT_NLIMITS];
|
||||
struct rlimit global_rlimit[RLIMIT_NLIMITS];
|
||||
|
||||
/*
|
||||
* --enable-fastboot => fsck_mode: NULL => no fsck by default
|
||||
* --enable-fsckfix => fsck_mode: "-f" + fsck_repair: "y"
|
||||
*/
|
||||
#ifdef FSCK_FIX
|
||||
# ifdef FAST_BOOT
|
||||
char *fsck_mode = NULL;
|
||||
# else
|
||||
char *fsck_mode = "-f";
|
||||
# endif
|
||||
char *fsck_repair = "-y";
|
||||
#else
|
||||
# ifdef FAST_BOOT
|
||||
char *fsck_mode = NULL;
|
||||
# else
|
||||
char *fsck_mode = "";
|
||||
# endif
|
||||
char *fsck_repair = "-p";
|
||||
#endif
|
||||
|
||||
char *runparts = NULL;
|
||||
int runparts_progress;
|
||||
int runparts_sysv;
|
||||
|
||||
char cgroup_current[16]; /* cgroup.NAME sets current cgroup for a set of services */
|
||||
|
||||
@@ -78,6 +99,9 @@ static uev_t etcw;
|
||||
|
||||
static TAILQ_HEAD(, conf_change) conf_change_list = TAILQ_HEAD_INITIALIZER(conf_change_list);
|
||||
|
||||
static char *path;
|
||||
static char *shell;
|
||||
|
||||
static int parse_conf(char *file, int is_rcsd);
|
||||
static void drop_changes(void);
|
||||
|
||||
@@ -243,10 +267,12 @@ static void parse_arg(char *arg)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef RESCUE_MODE
|
||||
if (string_compare(arg, "rescue") || string_compare(arg, "recover")) {
|
||||
rescue = 1;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (string_compare(arg, "single") || string_compare(arg, "S")) {
|
||||
single = 1;
|
||||
@@ -326,6 +352,8 @@ void conf_parse_cmdline(int argc, char *argv[])
|
||||
fstab = strdup(FINIT_FSTAB);
|
||||
finit_conf = strdup(FINIT_CONF);
|
||||
finit_rcsd = strdup(FINIT_RCSD);
|
||||
path = getenv("PATH");
|
||||
shell = getenv("SHELL");
|
||||
|
||||
for (int i = 1; i < argc; i++)
|
||||
parse_arg(argv[i]);
|
||||
@@ -351,8 +379,14 @@ void conf_reset_env(void)
|
||||
free(node);
|
||||
}
|
||||
|
||||
setenv("PATH", _PATH_STDPATH, 1);
|
||||
setenv("SHELL", _PATH_BSHELL, 1);
|
||||
if (path)
|
||||
setenv("PATH", path, 1);
|
||||
else
|
||||
setenv("PATH", _PATH_STDPATH, 1);
|
||||
if (shell)
|
||||
setenv("SHELL", shell, 1);
|
||||
else
|
||||
setenv("SHELL", _PATH_BSHELL, 1);
|
||||
setenv("LOGNAME", "root", 1);
|
||||
setenv("USER", "root", 1);
|
||||
}
|
||||
@@ -765,6 +799,15 @@ static int parse_static(char *line, int is_rcsd)
|
||||
|
||||
if (BOOTSTRAP && MATCH_CMD(line, "runparts ", x)) {
|
||||
if (runparts) free(runparts);
|
||||
runparts_progress = runparts_sysv = 0;
|
||||
while (x) {
|
||||
if (MATCH_CMD(x, "progress", x))
|
||||
runparts_progress = 1;
|
||||
else if (MATCH_CMD(x, "sysv", x))
|
||||
runparts_sysv = 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
runparts = strdup(strip_line(x));
|
||||
return 0;
|
||||
}
|
||||
@@ -851,7 +894,7 @@ static int parse_static(char *line, int is_rcsd)
|
||||
|
||||
service_interval = val * 1000; /* to milliseconds */
|
||||
if (disabled)
|
||||
service_init();
|
||||
service_init(NULL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1025,14 +1068,37 @@ static int parse_conf(char *file, int is_rcsd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void glob_append(glob_t *gl, int append, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
size_t len;
|
||||
char *path;
|
||||
|
||||
va_start(ap, fmt);
|
||||
len = vsnprintf(NULL, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
path = alloca(++len);
|
||||
if (!path) {
|
||||
warn("failed alloca() in glob_append()");
|
||||
return;
|
||||
}
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(path, len, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
dbg("conf_reload(): glob %s ...", path);
|
||||
glob(path, append ? GLOB_APPEND : 0, NULL, gl);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reload /etc/finit.conf and all *.conf in /etc/finit.d/
|
||||
*/
|
||||
int conf_reload(void)
|
||||
{
|
||||
char path[strlen(finit_rcsd) + 16];
|
||||
size_t i;
|
||||
glob_t gl;
|
||||
size_t i;
|
||||
|
||||
/* Set time according to current time zone */
|
||||
tzset();
|
||||
@@ -1049,9 +1115,17 @@ int conf_reload(void)
|
||||
*/
|
||||
memcpy(global_rlimit, initial_rlimit, sizeof(global_rlimit));
|
||||
|
||||
/*
|
||||
* When built with --disable-rescue mode many other 'if (rescue)'
|
||||
* code paths are #ifdeffed out. This one, and the ones in the
|
||||
* plugins, are not because a hook or plugin can still trigger
|
||||
* the alternative rescue.conf instead of finit.conf. This for
|
||||
* very advanced use-cases where files on /etc are generated at
|
||||
* bootstrap, including users and passwords, from other sources.
|
||||
*/
|
||||
if (rescue) {
|
||||
int rc;
|
||||
char line[80] = "tty [12345] rescue";
|
||||
char line[80] = "tty [12345789] rescue";
|
||||
|
||||
/* If rescue.conf is missing, fall back to a root shell */
|
||||
rc = parse_conf(RESCUE_CONF, 0);
|
||||
@@ -1079,12 +1153,9 @@ int conf_reload(void)
|
||||
* /etc/finit.d -- similar to how tmfiles.d(5) work. E.g., add
|
||||
* an override .conf, or an ignore by symlinking to /dev/null
|
||||
*/
|
||||
snprintf(path, sizeof(path), "%s/*.conf", finit_rcsd);
|
||||
glob(path, 0, NULL, &gl);
|
||||
snprintf(path, sizeof(path), "%s/*.conf", FINIT_SYSPATH);
|
||||
glob(path, GLOB_APPEND, NULL, &gl);
|
||||
snprintf(path, sizeof(path), "%s/enabled/*.conf", finit_rcsd);
|
||||
glob(path, GLOB_APPEND, NULL, &gl);
|
||||
glob_append(&gl, 0, "%s/*.conf", finit_rcsd);
|
||||
glob_append(&gl, 1, "%s/*.conf", FINIT_SYSPATH);
|
||||
glob_append(&gl, 1, "%s/enabled/*.conf", finit_rcsd);
|
||||
|
||||
for (i = 0; i < gl.gl_pathc; i++) {
|
||||
char *path = gl.gl_pathv[i];
|
||||
@@ -1204,7 +1275,10 @@ static int conf_change_act(char *dir, char *name, uint32_t mask)
|
||||
struct conf_change *node;
|
||||
char *rp = NULL;
|
||||
|
||||
paste(fn, sizeof(fn), dir, name);
|
||||
if (name[0])
|
||||
paste(fn, sizeof(fn), dir, name);
|
||||
else
|
||||
strlcpy(fn, dir, sizeof(fn));
|
||||
dbg("path: %s mask: %08x", fn, mask);
|
||||
|
||||
/* Handle disabling/removal of service */
|
||||
@@ -1235,7 +1309,7 @@ static int conf_change_act(char *dir, char *name, uint32_t mask)
|
||||
dbg("event registered for %s, mask 0x%x", rp, mask);
|
||||
return 0;
|
||||
fail:
|
||||
warn("failed registering %s event", fn);
|
||||
warn("failed registering %s event mask %08x", fn, mask);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1298,10 +1372,8 @@ static int conf_iwatch_read(int fd)
|
||||
if (!iwp)
|
||||
continue;
|
||||
|
||||
if (conf_change_act(iwp->path, ev->name, ev->mask)) {
|
||||
err(1, " Out of memory");
|
||||
if (conf_change_act(iwp->path, ev->name, ev->mask))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1389,7 +1461,7 @@ int conf_init(uev_ctx_t *ctx)
|
||||
*/
|
||||
#ifdef WDT_DEVNODE
|
||||
if (whichp(FINIT_EXECPATH_ "/watchdogd") && fexist(WDT_DEVNODE)) {
|
||||
service_register(SVC_TYPE_SERVICE, "[S123456789] cgroup.init name:watchdog :finit " FINIT_EXECPATH_ "/watchdogd -- Finit watchdog daemon", global_rlimit, NULL);
|
||||
service_register(SVC_TYPE_SERVICE, "[S0123456789] cgroup.init name:watchdog :finit " FINIT_EXECPATH_ "/watchdogd -- Finit watchdog daemon", global_rlimit, NULL);
|
||||
wdog = svc_find("watchdog", "finit");
|
||||
}
|
||||
#endif
|
||||
@@ -1397,7 +1469,7 @@ int conf_init(uev_ctx_t *ctx)
|
||||
* Start kernel event daemon as soon as possible, if enabled
|
||||
*/
|
||||
if (whichp(FINIT_EXECPATH_ "/keventd"))
|
||||
service_register(SVC_TYPE_SERVICE, "[S123456789] cgroup.init " FINIT_EXECPATH_ "/keventd -- Finit kernel event daemon", global_rlimit, NULL);
|
||||
service_register(SVC_TYPE_SERVICE, "[S0123456789] cgroup.init " FINIT_EXECPATH_ "/keventd -- Finit kernel event daemon", global_rlimit, NULL);
|
||||
|
||||
dbg("Allow plugins to register early runlevel 1 run/task/services ...");
|
||||
plugin_run_hooks(HOOK_SVC_PLUGIN);
|
||||
@@ -1416,6 +1488,26 @@ int conf_init(uev_ctx_t *ctx)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Background startup scripts in the runparts directory, if any.
|
||||
*/
|
||||
if (runparts && fisdir(runparts) && !rescue) {
|
||||
char conf[sizeof(_PATH_RUNPARTS) + strlen(runparts) + 100];
|
||||
char args[10] = { 0 };
|
||||
|
||||
if (debug)
|
||||
strlcat(args, "-d ", sizeof(args));
|
||||
if (runparts_progress)
|
||||
strlcat(args, "-p ", sizeof(args));
|
||||
if (runparts_sysv)
|
||||
strlcat(args, "-s ", sizeof(args));
|
||||
|
||||
snprintf(conf, sizeof(conf), "[S] <int/bootstrap> log:console %s %s %s"
|
||||
" -- Calling runparts %s in the background",
|
||||
_PATH_RUNPARTS, args, runparts, runparts);
|
||||
service_register(SVC_TYPE_TASK, conf, global_rlimit, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -243,7 +243,7 @@ static void devmon_cb(uev_t *w, void *arg, int events)
|
||||
}
|
||||
}
|
||||
|
||||
void devmon_init(void)
|
||||
void devmon_init(uev_ctx_t *ctx)
|
||||
{
|
||||
char dir[MAX_ARG_LEN];
|
||||
|
||||
|
||||
+1
-1
@@ -27,6 +27,6 @@
|
||||
void devmon_add_cond(const char *cond);
|
||||
void devmon_del_cond(const char *cond);
|
||||
|
||||
void devmon_init(void);
|
||||
void devmon_init(uev_ctx_t *ctx);
|
||||
|
||||
#endif /* FINIT_DEVMON_H_ */
|
||||
|
||||
+15
-93
@@ -24,8 +24,6 @@
|
||||
|
||||
#include "config.h" /* Generated by configure script */
|
||||
|
||||
#include <ctype.h> /* isdigit() */
|
||||
#include <dirent.h>
|
||||
#include <err.h>
|
||||
#include <stdarg.h>
|
||||
#include <sysexits.h>
|
||||
@@ -59,11 +57,11 @@ int complete(char *cmd, int pid)
|
||||
|
||||
if (waitpid(pid, &status, 0) == -1) {
|
||||
if (errno == EINTR)
|
||||
errx(1, "Caught unblocked signal waiting for %s, aborting", cmd);
|
||||
warnx("Caught unblocked signal waiting for %s, aborting", cmd);
|
||||
else if (errno == ECHILD)
|
||||
errx(1, "Caught SIGCHLD waiting for %s, aborting", cmd);
|
||||
warnx("Caught SIGCHLD waiting for %s, aborting", cmd);
|
||||
else
|
||||
errx(1, "Failed starting %s, error %d: %s", cmd, errno, strerror (errno));
|
||||
warnx("Failed starting %s, error %d: %s", cmd, errno, strerror(errno));
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -186,7 +184,7 @@ int run(char *cmd, char *log)
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
dbg("Process '%s' terminated by signal %d", cmd, WTERMSIG(status));
|
||||
if (!result)
|
||||
result = 1; /* Must alert callee that the command did complete successfully.
|
||||
result = 1; /* Must alert callee the command did not complete successfully.
|
||||
* This is necessary since not all programs trap signals and
|
||||
* change their return code accordingly. --Jocke */
|
||||
}
|
||||
@@ -272,7 +270,7 @@ int exec_runtask(char *cmd, char *args[])
|
||||
size_t i;
|
||||
|
||||
strlcat(buf, cmd, sizeof(buf));
|
||||
for (i = 1; args[i]; i++) {
|
||||
for (i = 1; args && args[i]; i++) {
|
||||
strlcat(buf, " ", sizeof(buf));
|
||||
strlcat(buf, args[i], sizeof(buf));
|
||||
}
|
||||
@@ -443,96 +441,20 @@ pid_t run_sh(char *tty, int noclear, int nowait, struct rlimit rlimit[])
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void run_env(const char *env[])
|
||||
pid_t run_bg(char *cmd, char *args[])
|
||||
{
|
||||
size_t i = 0;
|
||||
pid_t pid;
|
||||
|
||||
if (!env)
|
||||
return;
|
||||
if (access(cmd, X_OK))
|
||||
return 0;
|
||||
|
||||
while (env[i]) {
|
||||
size_t j = i + 1;
|
||||
print(-1, "Calling %s in the background", cmd);
|
||||
pid = fork();
|
||||
if (!pid)
|
||||
_exit(exec_runtask(cmd, args));
|
||||
print_result(pid == -1);
|
||||
|
||||
if (!env[j])
|
||||
break;
|
||||
|
||||
setenv(env[i], env[j], 1);
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
int run_parts(char *dir, char *cmd, const char *env[], int progress)
|
||||
{
|
||||
struct dirent **e;
|
||||
int i, num;
|
||||
|
||||
num = scandir(dir, &e, NULL, alphasort);
|
||||
if (num < 0) {
|
||||
dbg("No files found in %s, skipping ...", dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
const char *name = e[i]->d_name;
|
||||
char path[strlen(dir) + strlen(name) + 2];
|
||||
struct stat st;
|
||||
char *argv[4] = {
|
||||
"sh",
|
||||
"-c",
|
||||
path,
|
||||
NULL
|
||||
};
|
||||
pid_t pid = 0;
|
||||
int status;
|
||||
|
||||
paste(path, sizeof(path), dir, name);
|
||||
if (stat(path, &st)) {
|
||||
dbg("Failed stat(%s): %s", path, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!S_ISEXEC(st.st_mode) || S_ISDIR(st.st_mode)) {
|
||||
if (strcmp(name, ".") && strcmp(name, ".."))
|
||||
dbg("Skipping %s ...", path);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If the callee didn't supply a run_parts() argument */
|
||||
if (!cmd) {
|
||||
/* Check if S<NUM>service or K<NUM>service notation is used */
|
||||
// dbg("Checking if %s is a sysvinit startstop script ...", name);
|
||||
if (name[0] == 'S' && isdigit(name[1]))
|
||||
strlcat(path, " start", sizeof(path));
|
||||
else if (name[0] == 'K' && isdigit(name[1]))
|
||||
strlcat(path, " stop", sizeof(path));
|
||||
} else {
|
||||
strlcat(path, cmd, sizeof(path));
|
||||
}
|
||||
|
||||
if (progress)
|
||||
print_desc("Calling ", path);
|
||||
pid = fork();
|
||||
if (!pid) {
|
||||
sig_unblock();
|
||||
run_env(env);
|
||||
|
||||
return execvp(_PATH_BSHELL, argv);
|
||||
}
|
||||
|
||||
status = complete(path, pid);
|
||||
if (WIFEXITED(status))
|
||||
warnx("%s exited with status %d", path, WEXITSTATUS(status));
|
||||
else if (WIFSIGNALED(status))
|
||||
warnx("%s terminated by signad %d", path, WTERMSIG(status));
|
||||
if (progress)
|
||||
print_result(WEXITSTATUS(status));
|
||||
}
|
||||
|
||||
while (num--)
|
||||
free(e[num]);
|
||||
free(e);
|
||||
|
||||
return 0;
|
||||
return pid;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+11
-132
@@ -58,7 +58,6 @@
|
||||
#include "tty.h"
|
||||
#include "util.h"
|
||||
#include "utmp-api.h"
|
||||
#include "schedule.h"
|
||||
|
||||
int runlevel = INIT_LEVEL; /* Bootstrap 'S' */
|
||||
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
|
||||
@@ -76,7 +75,6 @@ char *fstab = NULL;
|
||||
char *sdown = NULL;
|
||||
char *network = NULL;
|
||||
char *hostname = NULL;
|
||||
char *runparts = NULL;
|
||||
char *osheading = NULL;
|
||||
|
||||
uev_ctx_t *ctx = NULL; /* Main loop context */
|
||||
@@ -256,11 +254,7 @@ static int fsck(int pass)
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef FSCK_FIX
|
||||
snprintf(cmd, sizeof(cmd), "fsck -yf %s", dev);
|
||||
#else
|
||||
snprintf(cmd, sizeof(cmd), "fsck %s %s %s", fsck_mode, fsck_repair, dev);
|
||||
#endif
|
||||
dbg("Running pass %d fsck command %s", pass, cmd);
|
||||
fsck_rc = run_interactive(cmd, "Checking filesystem %s", dev);
|
||||
/*
|
||||
@@ -283,7 +277,6 @@ static int fsck(int pass)
|
||||
static int fsck_all(void)
|
||||
{
|
||||
int rc = 0;
|
||||
#ifndef FAST_BOOT
|
||||
int pass;
|
||||
|
||||
if (!fsck_mode)
|
||||
@@ -294,7 +287,7 @@ static int fsck_all(void)
|
||||
if (rc)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -521,113 +514,6 @@ static void fs_init(void)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Handle bootstrap transition to configured runlevel, start TTYs
|
||||
*
|
||||
* This is the final stage of bootstrap. It changes to the default
|
||||
* (configured) runlevel, calls all external start scripts and final
|
||||
* bootstrap hooks before bringing up TTYs.
|
||||
*
|
||||
* We must ensure that all declared `task [S]` and `run [S]` jobs in
|
||||
* finit.conf, or *.conf in finit.d/, run to completion before we
|
||||
* finalize the bootstrap process by calling this function.
|
||||
*/
|
||||
static void finalize(void *unused)
|
||||
{
|
||||
/* Clean up bootstrap-only tasks/services that never started */
|
||||
dbg("Clean up all bootstrap-only tasks/services ...");
|
||||
svc_prune_bootstrap();
|
||||
|
||||
/* All services/tasks/etc. in configure runlevel have started */
|
||||
dbg("Running svc up hooks ...");
|
||||
plugin_run_hooks(HOOK_SVC_UP);
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
|
||||
/* Convenient SysV compat for when you just don't care ... */
|
||||
if (!access(FINIT_RC_LOCAL, X_OK) && !rescue)
|
||||
run_interactive(FINIT_RC_LOCAL, "Calling %s", FINIT_RC_LOCAL);
|
||||
|
||||
/* Hooks that should run at the very end */
|
||||
dbg("Calling all system up hooks ...");
|
||||
plugin_run_hooks(HOOK_SYSTEM_UP);
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
|
||||
/* Disable progress output at normal runtime */
|
||||
enable_progress(0);
|
||||
|
||||
/* System bootrapped, launch TTYs et al */
|
||||
bootstrap = 0;
|
||||
service_step_all(SVC_TYPE_RESPAWN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Start cranking the big state machine
|
||||
*/
|
||||
static void crank_worker(void *unused)
|
||||
{
|
||||
/*
|
||||
* Initialize state machine and start all bootstrap tasks
|
||||
* NOTE: no network available!
|
||||
*/
|
||||
sm_init(&sm);
|
||||
sm_step(&sm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for system bootstrap to complete, all SVC_TYPE_RUNTASK must be
|
||||
* allowed to complete their work in [S], or timeout, before we switch
|
||||
* to the configured runlevel and call finalize(), should not take more
|
||||
* than 120 sec.
|
||||
*/
|
||||
static void bootstrap_worker(void *work)
|
||||
{
|
||||
static struct wq final = {
|
||||
.cb = finalize,
|
||||
.delay = 10
|
||||
};
|
||||
static int cnt = 120 * 10; /* We run with 100ms period */
|
||||
int level = cfglevel;
|
||||
|
||||
dbg("Step all services ...");
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
|
||||
if (cnt-- > 0 && !service_completed()) {
|
||||
dbg("Not all bootstrap run/tasks have completed yet ... %d", cnt);
|
||||
schedule_work(work);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cnt > 0)
|
||||
dbg("All run/task have completed, resuming bootstrap.");
|
||||
else
|
||||
dbg("Timeout, resuming bootstrap.");
|
||||
|
||||
dbg("Starting runlevel change finalize ...");
|
||||
schedule_work(&final);
|
||||
|
||||
/*
|
||||
* Run startup scripts in the runparts directory, if any.
|
||||
*/
|
||||
if (runparts && fisdir(runparts) && !rescue)
|
||||
run_parts(runparts, NULL, NULL, 1);
|
||||
|
||||
|
||||
dbg("Flushing pending .conf file events ...");
|
||||
conf_flush_events();
|
||||
|
||||
/*
|
||||
* Start all tasks/services in the configured runlevel, or jump
|
||||
* into the runlevel selected from the command line.
|
||||
*/
|
||||
if (cmdlevel) {
|
||||
dbg("Runlevel %d requested from command line, starting all services ...", cmdlevel);
|
||||
level = cmdlevel;
|
||||
} else
|
||||
dbg("Change to default runlevel(%d), starting all services ...", cfglevel);
|
||||
|
||||
service_runlevel(level);
|
||||
}
|
||||
|
||||
static int version(int rc)
|
||||
{
|
||||
puts(PACKAGE_STRING);
|
||||
@@ -658,7 +544,7 @@ static int usage(int rc)
|
||||
" 2-9 Change runlevel\n"
|
||||
" q, Q Reload /etc/finit.conf and/or any *.conf in /etc/finit.d/\n"
|
||||
" if modified, same as initctl reload or SIGHUP to PID 1\n"
|
||||
" 1, s, S Enter system rescue mode, runlevel 1\n"
|
||||
" 1, s, S Enter single user mode, no networking, runlevel 1\n"
|
||||
"\n", prognm);
|
||||
|
||||
return rc;
|
||||
@@ -708,14 +594,6 @@ static int telinit(int argc, char *argv[])
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct wq crank_work = {
|
||||
.cb = crank_worker,
|
||||
.delay = 10
|
||||
};
|
||||
struct wq bootstrap_work = {
|
||||
.cb = bootstrap_worker,
|
||||
.delay = 100
|
||||
};
|
||||
uev_ctx_t loop;
|
||||
|
||||
/* user calling telinit or init */
|
||||
@@ -765,8 +643,10 @@ int main(int argc, char *argv[])
|
||||
/*
|
||||
* In case of emergency.
|
||||
*/
|
||||
#ifdef RESCUE_MODE
|
||||
if (rescue)
|
||||
rescue = sulogin(0);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Load plugins early, the first hook is in banner(), so we
|
||||
@@ -819,7 +699,7 @@ int main(int argc, char *argv[])
|
||||
* Initialize .conf system and load static /etc/finit.conf then
|
||||
* tell the world what we used.
|
||||
*/
|
||||
devmon_init();
|
||||
devmon_init(&loop);
|
||||
conf_init(&loop);
|
||||
conf_saverc();
|
||||
|
||||
@@ -832,16 +712,15 @@ int main(int argc, char *argv[])
|
||||
dbg("Starting initctl API responder ...");
|
||||
api_init(&loop);
|
||||
|
||||
dbg("Starting the big state machine ...");
|
||||
schedule_work(&crank_work);
|
||||
|
||||
dbg("Starting bootstrap finalize timer ...");
|
||||
schedule_work(&bootstrap_work);
|
||||
dbg("Starting service interval monitor ...");
|
||||
service_init(&loop);
|
||||
|
||||
/*
|
||||
* Background service tasks
|
||||
* Initialize state machine and start all bootstrap tasks
|
||||
* NOTE: no network available!
|
||||
*/
|
||||
service_init();
|
||||
sm_init(&sm);
|
||||
sm_step(&sm);
|
||||
|
||||
/*
|
||||
* Enter main loop to monitor /dev/initctl and services
|
||||
|
||||
+2
-1
@@ -56,10 +56,11 @@
|
||||
|
||||
/* To use these, include config.h, or define FINIT_EXECPATH_ */
|
||||
#define _PATH_LOGIT FINIT_EXECPATH_ "/logit"
|
||||
#define _PATH_RUNPARTS FINIT_EXECPATH_ "/runparts"
|
||||
#define _PATH_SULOGIN FINIT_EXECPATH_ "/sulogin"
|
||||
#define _PATH_GETTY FINIT_EXECPATH_ "/getty"
|
||||
|
||||
#define CMD_SIZE 256
|
||||
#define CMD_SIZE 1024
|
||||
#define LINE_SIZE 1024
|
||||
#define BUF_SIZE 4096
|
||||
|
||||
|
||||
+1
-1
@@ -369,7 +369,7 @@ restart:
|
||||
|
||||
static int usage(int rc)
|
||||
{
|
||||
warnx("usage: getty [-h?] tty [speed [term]]");
|
||||
warnx("usage: getty [-h?p] tty [speed [term]]");
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -84,6 +84,9 @@ char *console(void)
|
||||
|
||||
void console_init(void)
|
||||
{
|
||||
/* Enable line wrap, if disabled previously, e.g., qemu */
|
||||
dprint(STDOUT_FILENO, "\033[?7h", 5);
|
||||
|
||||
log_init();
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -88,7 +88,8 @@ int run_interactive (char *cmd, char *fmt, ...) __attribute__ ((format (prin
|
||||
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_sh (char *tty, int noclear, int nowait, struct rlimit rlimit[]);
|
||||
int run_parts (char *dir, char *cmd, const char *env[], int progress);
|
||||
pid_t run_bg (char *cmd, char *args[]);
|
||||
int run_parts (char *dir, char *cmd, const char *env[], int progress, int sysv);
|
||||
|
||||
/*
|
||||
* Defaults to user "root" and group "wheel" (root) if:
|
||||
|
||||
+10
-3
@@ -209,19 +209,26 @@ static int do_runlevel(char *arg)
|
||||
if (!arg) {
|
||||
int prevlevel = 0;
|
||||
int currlevel;
|
||||
char prev;
|
||||
char prev, curr;
|
||||
|
||||
currlevel = runlevel_get(&prevlevel);
|
||||
if (255 == currlevel) {
|
||||
switch (currlevel) {
|
||||
case 255:
|
||||
printf("unknown\n");
|
||||
return 0;
|
||||
case INIT_LEVEL:
|
||||
curr = 'S';
|
||||
break;
|
||||
default:
|
||||
curr = currlevel + '0';
|
||||
break;
|
||||
}
|
||||
|
||||
prev = prevlevel + '0';
|
||||
if (prev <= '0' || prev > '9')
|
||||
prev = 'N';
|
||||
|
||||
printf("%c %d\n", prev , currlevel);
|
||||
printf("%c %c\n", prev , curr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ static __attribute__ ((format (printf, 1, 2))) inline void dbg(char *fmt, ...)
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fputs("\n", stderr);
|
||||
va_end(ap);
|
||||
}
|
||||
#define info(fmt, args...) warnx(fmt, ##args)
|
||||
|
||||
+1
-1
@@ -230,7 +230,7 @@ void plugin_script_run(hook_point_t no)
|
||||
} else
|
||||
env[2] = NULL;
|
||||
|
||||
run_parts(path, NULL, env, 0);
|
||||
run_parts(path, NULL, env, 0, 0);
|
||||
}
|
||||
#else
|
||||
void plugin_script_run(hook_point_t no)
|
||||
|
||||
+230
@@ -0,0 +1,230 @@
|
||||
#include <ctype.h> /* isdigit() */
|
||||
#include <dirent.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <paths.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/conio.h>
|
||||
# include <libite/lite.h>
|
||||
#else
|
||||
# include <lite/conio.h>
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
#include "sig.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef __FINIT__
|
||||
#include "helpers.h"
|
||||
#else
|
||||
#include <sys/prctl.h>
|
||||
|
||||
int debug;
|
||||
|
||||
static void print_desc(const char *prefix, const char *msg)
|
||||
{
|
||||
fprintf(stderr, "\e[1m[\e[0m\e[1;33m ⋯ \e[0m\e[1m]\e[0m %s %s", prefix, msg);
|
||||
}
|
||||
static void print_result(int rc)
|
||||
{
|
||||
if (rc)
|
||||
fputs("\r\e[1m[\e[0m\e[1;31mFAIL\e[0m\e[1m]\e[0m\n", stderr);
|
||||
else
|
||||
fputs("\r\e[1m[\e[0m\e[1;32m OK \e[0m\e[1m]\e[0m\n", stderr);
|
||||
}
|
||||
|
||||
void sig_unblock(void)
|
||||
{
|
||||
struct sigaction sa;
|
||||
sigset_t nmask;
|
||||
int i;
|
||||
|
||||
sigemptyset(&nmask);
|
||||
sigaddset(&nmask, SIGHUP);
|
||||
sigaddset(&nmask, SIGCHLD);
|
||||
sigaddset(&nmask, SIGINT);
|
||||
sigaddset(&nmask, SIGPWR);
|
||||
sigaddset(&nmask, SIGSTOP);
|
||||
sigaddset(&nmask, SIGTSTP);
|
||||
sigaddset(&nmask, SIGCONT);
|
||||
sigaddset(&nmask, SIGTERM);
|
||||
sigaddset(&nmask, SIGUSR1);
|
||||
sigaddset(&nmask, SIGUSR2);
|
||||
sigprocmask(SIG_UNBLOCK, &nmask, NULL);
|
||||
|
||||
/* Reset signal handlers that were set by the parent process */
|
||||
for (i = 1; i < NSIG; i++)
|
||||
DFLSIG(sa, i, 0);
|
||||
}
|
||||
#endif /* __FINIT__ */
|
||||
|
||||
static void run_env(const char *env[])
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
if (!env)
|
||||
return;
|
||||
|
||||
while (env[i]) {
|
||||
size_t j = i + 1;
|
||||
|
||||
if (!env[j])
|
||||
break;
|
||||
|
||||
setenv(env[i], env[j], 1);
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
int run_parts(char *dir, char *cmd, const char *env[], int progress, int sysv)
|
||||
{
|
||||
size_t cmdlen = cmd ? strlen(cmd) : strlen("start");
|
||||
struct dirent **d;
|
||||
int i, num;
|
||||
int rc = 0;
|
||||
|
||||
num = scandir(dir, &d, NULL, alphasort);
|
||||
if (num < 0) {
|
||||
dbg("No files found in %s, skipping ...", dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
char path[strlen(dir) + strlen(d[i]->d_name) + 3 + cmdlen];
|
||||
const char *name = d[i]->d_name;
|
||||
char *argv[4] = {
|
||||
"sh",
|
||||
"-c",
|
||||
path,
|
||||
NULL
|
||||
};
|
||||
struct stat st;
|
||||
int result = 0;
|
||||
pid_t pid = 0;
|
||||
int status;
|
||||
|
||||
/* skip backup files */
|
||||
if (name[strlen(name) - 1] == '~')
|
||||
continue;
|
||||
|
||||
/* cannot rely on d_type, not supported on all filesystems */
|
||||
paste(path, sizeof(path), dir, name);
|
||||
if (stat(path, &st)) {
|
||||
warn("failed stat(%s)", path);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* skip non-executable files and directories */
|
||||
if (!S_ISEXEC(st.st_mode) || S_ISDIR(st.st_mode)) {
|
||||
dbg("skipping %s not an executable or is a directory", path);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sysv && name[0] != 'S' && name[0] != 'K') {
|
||||
dbg("S-only flag set, skipping non-SysV script: %s", name);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If the callee didn't supply a run_parts() argument */
|
||||
if (!cmd) {
|
||||
/* Check if S<NUM>service or K<NUM>service notation is used */
|
||||
if (name[0] == 'S' && isdigit(name[1]))
|
||||
strlcat(path, " start", sizeof(path));
|
||||
else if (name[0] == 'K' && isdigit(name[1]))
|
||||
strlcat(path, " stop", sizeof(path));
|
||||
} else {
|
||||
strlcat(path, " ", sizeof(path));
|
||||
strlcat(path, cmd, sizeof(path));
|
||||
}
|
||||
|
||||
if (progress)
|
||||
print_desc("Calling", path);
|
||||
|
||||
pid = fork();
|
||||
if (!pid) {
|
||||
sig_unblock();
|
||||
run_env(env);
|
||||
|
||||
_exit(execvp(_PATH_BSHELL, argv));
|
||||
}
|
||||
|
||||
if (waitpid(pid, &status, 0) == -1) {
|
||||
warnx("failed starting %s, error %d: %s", path, errno, strerror(errno));
|
||||
result = 1;
|
||||
} else {
|
||||
if (WIFEXITED(status)) {
|
||||
result = WEXITSTATUS(status);
|
||||
dbg("%s exited with status %d", path, result);
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
warnx("%s terminated by signal %d", path, WTERMSIG(status));
|
||||
result = 1;
|
||||
} else
|
||||
result = 1;
|
||||
}
|
||||
|
||||
if (progress)
|
||||
print_result(result);
|
||||
rc += result;
|
||||
}
|
||||
|
||||
while (num--)
|
||||
free(d[num]);
|
||||
free(d);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifndef __FINIT__
|
||||
static int usage(int rc)
|
||||
{
|
||||
warnx("usage: runparts [-dhps?] DIRECTORY");
|
||||
return rc;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int rc, c, progress = 0, sysv = 0;
|
||||
char *dir;
|
||||
|
||||
while ((c = getopt(argc, argv, "dh?ps")) != EOF) {
|
||||
switch(c) {
|
||||
case 'd':
|
||||
debug = 1;
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
return usage(0);
|
||||
case 'p':
|
||||
progress = 1;
|
||||
break;
|
||||
case 's':
|
||||
sysv = 1;
|
||||
break;
|
||||
default:
|
||||
return usage(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind >= argc)
|
||||
return usage(1);
|
||||
|
||||
dir = argv[optind];
|
||||
if (!fisdir(dir))
|
||||
return usage(1);
|
||||
|
||||
prctl(PR_SET_CHILD_SUBREAPER, 1);
|
||||
|
||||
rc = run_parts(dir, NULL, NULL, progress, sysv);
|
||||
if (rc == -1)
|
||||
err(1, "failed run-parts %s", dir);
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif /* __FINIT__ */
|
||||
+14
@@ -41,6 +41,10 @@ static int is_builtin(char *arg)
|
||||
{
|
||||
svc_t *svc;
|
||||
|
||||
/* skip check, we may be in non-responsive bootstrap */
|
||||
if (iforce)
|
||||
return 0;
|
||||
|
||||
svc = client_svc_find(arg);
|
||||
if (!svc)
|
||||
return 0;
|
||||
@@ -262,6 +266,11 @@ int serv_enable(char *arg)
|
||||
return serv_list("available");
|
||||
}
|
||||
|
||||
if (arg[0] == '/') {
|
||||
WARNX("absolute paths not supported, this command manages %s/available/", finit_rcsd);
|
||||
return serv_list("available");
|
||||
}
|
||||
|
||||
len = strlen(arg);
|
||||
serv = alloca(len + 6);
|
||||
if (!serv)
|
||||
@@ -322,6 +331,11 @@ int do_disable(char *arg, int check)
|
||||
return serv_list("enabled");
|
||||
}
|
||||
|
||||
if (arg[0] == '/') {
|
||||
WARNX("absolute paths not supported, this command manages %s/enabled/", finit_rcsd);
|
||||
return serv_list("available");
|
||||
}
|
||||
|
||||
len = strlen(arg);
|
||||
serv = alloca(len + 6);
|
||||
if (!serv)
|
||||
|
||||
+106
-55
@@ -56,6 +56,12 @@
|
||||
#include "utmp-api.h"
|
||||
#include "schedule.h"
|
||||
|
||||
/*
|
||||
* run tasks block other tasks/services from starting, we track the
|
||||
* current run task here. For service_step() and service_start().
|
||||
*/
|
||||
static pid_t run_block_pid;
|
||||
|
||||
static struct wq work = {
|
||||
.cb = service_worker,
|
||||
};
|
||||
@@ -173,7 +179,7 @@ static int service_script_del(pid_t pid)
|
||||
if (ptr->pid != pid)
|
||||
continue;
|
||||
|
||||
dbg("Collected service %s script PID %d.", svc_ident(ptr->svc, NULL, 0), pid);
|
||||
dbg("Collected service %s script PID %d, killing process group.", svc_ident(ptr->svc, NULL, 0), pid);
|
||||
service_timeout_cancel(ptr->svc);
|
||||
kill(-ptr->pid, SIGKILL);
|
||||
TAILQ_REMOVE(&svc_assoc_list, ptr, link);
|
||||
@@ -560,6 +566,15 @@ static pid_t service_fork(svc_t *svc)
|
||||
source_env(svc);
|
||||
}
|
||||
|
||||
if (pid > 1) {
|
||||
char grnam[80];
|
||||
|
||||
if (svc_is_tty(svc))
|
||||
cgroup_user("getty", pid);
|
||||
else
|
||||
cgroup_service(group_name(svc, grnam, sizeof(grnam)), pid, &svc->cgroup);
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
@@ -575,7 +590,6 @@ static int service_start(svc_t *svc)
|
||||
int result = 0, do_progress = 1;
|
||||
char cmdline[CMD_SIZE] = "";
|
||||
sigset_t nmask, omask;
|
||||
char grnam[80];
|
||||
pid_t pid;
|
||||
size_t i;
|
||||
|
||||
@@ -586,6 +600,10 @@ static int service_start(svc_t *svc)
|
||||
if (is_norespawn())
|
||||
return 1;
|
||||
|
||||
/* Waiting for a run task to complete */
|
||||
if (run_block_pid)
|
||||
return 1;
|
||||
|
||||
/* Don't try and start service if it doesn't exist. */
|
||||
if (!whichp(svc->cmd)) {
|
||||
logit(LOG_WARNING, "%s: missing %s or not in $PATH", svc_ident(svc, NULL, 0), svc->cmd);
|
||||
@@ -610,13 +628,6 @@ static int service_start(svc_t *svc)
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't start if it conflicts with something else already started */
|
||||
if (svc_conflicts(svc)) {
|
||||
logit(LOG_INFO, "Not starting %s, conflicts with %s",
|
||||
svc_ident(svc, NULL, 0), svc->conflict);
|
||||
return 1;
|
||||
}
|
||||
|
||||
compose_cmdline(svc, cmdline, sizeof(cmdline));
|
||||
if (svc_is_sysv(svc))
|
||||
logit(LOG_CONSOLE | LOG_NOTICE, "Calling '%s start' ...", cmdline);
|
||||
@@ -651,19 +662,15 @@ static int service_start(svc_t *svc)
|
||||
goto fail;
|
||||
}
|
||||
if (pid > 1) {
|
||||
dbg("Starting %s as PID %d", svc_ident(svc, NULL, 0), pid);
|
||||
svc->pid = pid;
|
||||
svc->start_time = jiffies();
|
||||
} else if (pid == 0) {
|
||||
char *args[MAX_NUM_SVC_ARGS + 1];
|
||||
int status;
|
||||
|
||||
pid = getpid();
|
||||
if (svc_is_tty(svc)) {
|
||||
cgroup_user("getty", pid);
|
||||
} else {
|
||||
cgroup_service(group_name(svc, grnam, sizeof(grnam)), pid, &svc->cgroup);
|
||||
if (!svc_is_tty(svc))
|
||||
redirect(svc);
|
||||
}
|
||||
|
||||
if (!svc_is_sysv(svc)) {
|
||||
wordexp_t we = { 0 };
|
||||
@@ -795,7 +802,7 @@ static int service_start(svc_t *svc)
|
||||
*/
|
||||
pid = setsid();
|
||||
if (pid < 1)
|
||||
logit(LOG_ERR, "failed setsid(), pid %d: %s", pid, strerror(errno));
|
||||
syslog(LOG_ERR, "failed setsid(), pid %d: %s", pid, strerror(errno));
|
||||
|
||||
sig_unblock();
|
||||
|
||||
@@ -806,6 +813,8 @@ static int service_start(svc_t *svc)
|
||||
else
|
||||
status = execvp(args[0], &args[1]);
|
||||
|
||||
syslog(LOG_ERR, "failed starting %s, exit code %d: %s", svc_ident(svc, NULL, 0),
|
||||
status, strerror(errno));
|
||||
_exit(status);
|
||||
} else if (debug) {
|
||||
dbg("Starting PID %d: %s", svc->pid, cmdline);
|
||||
@@ -816,27 +825,11 @@ static int service_start(svc_t *svc)
|
||||
|
||||
switch (svc->type) {
|
||||
case SVC_TYPE_RUN:
|
||||
svc->status = complete(svc->cmd, pid);
|
||||
dbg("collected %s(%d), normal exit: %d, signaled: %d, exit code: %d",
|
||||
svc_ident(svc, NULL, 0), pid, WIFEXITED(svc->status),
|
||||
WIFSIGNALED(svc->status), WEXITSTATUS(svc->status));
|
||||
if (WIFEXITED(svc->status)) {
|
||||
svc->started = 1;
|
||||
result = WEXITSTATUS(svc->status);
|
||||
} else {
|
||||
svc->started = 0;
|
||||
result = 1;
|
||||
}
|
||||
svc->start_time = svc->pid = 0;
|
||||
svc->once++;
|
||||
svc_mark_clean(svc); /* done, regardless of exit status */
|
||||
svc_set_state(svc, SVC_STOPPING_STATE);
|
||||
run_block_pid = pid;
|
||||
break;
|
||||
|
||||
case SVC_TYPE_SERVICE:
|
||||
pid_file_create(svc);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -857,17 +850,26 @@ fail:
|
||||
*/
|
||||
static void service_kill(svc_t *svc)
|
||||
{
|
||||
char *nm, *id = svc_ident(svc, NULL, 0);
|
||||
|
||||
service_timeout_cancel(svc);
|
||||
|
||||
if (svc->pid <= 1) {
|
||||
/* Avoid killing ourselves or all processes ... */
|
||||
dbg("%s: Aborting SIGKILL, already terminated.", svc_ident(svc, NULL, 0));
|
||||
dbg("%s: Aborting SIGKILL, already terminated.", id);
|
||||
return;
|
||||
}
|
||||
|
||||
dbg("%s: Sending SIGKILL to pid:%d", pid_get_name(svc->pid, NULL, 0), svc->pid);
|
||||
logit(LOG_CONSOLE | LOG_NOTICE, "Stopping %s[%d], sending SIGKILL ...",
|
||||
svc_ident(svc, NULL, 0), svc->pid);
|
||||
nm = pid_get_name(svc->pid, NULL, 0);
|
||||
if (!nm) {
|
||||
/* PID possibly monitored by someone else? */
|
||||
dbg("%s: Aborting SIGKILL, PID[%d] no longer exists.", id, svc->pid);
|
||||
service_monitor(svc->pid, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
dbg("%s: Sending SIGKILL to process group %d", nm, svc->pid);
|
||||
logit(LOG_CONSOLE | LOG_NOTICE, "Stopping %s[%d], sending SIGKILL ...", id, svc->pid);
|
||||
if (runlevel != 1)
|
||||
print_desc("Killing ", svc->desc);
|
||||
|
||||
@@ -935,13 +937,21 @@ int service_stop(svc_t *svc)
|
||||
|
||||
compose_cmdline(svc, cmdline, sizeof(cmdline));
|
||||
if (!svc_is_sysv(svc)) {
|
||||
char *nm = pid_get_name(svc->pid, NULL, 0);
|
||||
const char *sig = sig_name(svc->sighalt);
|
||||
char *id = svc_ident(svc, NULL, 0);
|
||||
|
||||
if (svc->pid <= 1)
|
||||
return 1;
|
||||
if (!nm) {
|
||||
dbg("Skipping stop (%s) of %s, PID[%d] no longer exists.", sig, id, svc->pid);
|
||||
service_cleanup(svc);
|
||||
svc_set_state(svc, SVC_HALTED_STATE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dbg("Sending %s to pid:%d name:%s", sig_name(svc->sighalt),
|
||||
svc->pid, pid_get_name(svc->pid, NULL, 0));
|
||||
logit(LOG_CONSOLE | LOG_NOTICE, "Stopping %s[%d], sending %s ...",
|
||||
svc_ident(svc, NULL, 0), svc->pid, sig_name(svc->sighalt));
|
||||
dbg("Sending %s to pid:%d name:%s", sig, svc->pid, nm);
|
||||
logit(LOG_CONSOLE | LOG_NOTICE, "Stopping %s[%d], sending %s ...", id, svc->pid, sig);
|
||||
} else {
|
||||
logit(LOG_CONSOLE | LOG_NOTICE, "Calling '%s stop' ...", cmdline);
|
||||
}
|
||||
@@ -969,9 +979,14 @@ int service_stop(svc_t *svc)
|
||||
|
||||
if (!svc_is_sysv(svc)) {
|
||||
if (svc->pid > 1) {
|
||||
/* Kill all children in the same proess group, e.g. logit */
|
||||
rc = kill(-svc->pid, svc->sighalt);
|
||||
dbg("kill(-%d, %d) => rc %d, errno %d", svc->pid, svc->sighalt, rc, errno);
|
||||
/*
|
||||
* Send SIGTERM to parent process of process group, not to the
|
||||
* entire group. This gives the process time to properly stop
|
||||
* and/or forward TERM to its children. If it does not respond
|
||||
* in within a reasonable timeout we SIGKILL the entire group.
|
||||
*/
|
||||
rc = kill(svc->pid, svc->sighalt);
|
||||
dbg("kill(%d, %d) => rc %d, errno %d", svc->pid, svc->sighalt, rc, errno);
|
||||
/* PID lost or forking process never really started */
|
||||
if (rc == -1 && (errno == ESRCH || errno == ENOENT)) {
|
||||
service_cleanup(svc);
|
||||
@@ -1732,6 +1747,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
else
|
||||
memset(svc->ifstmt, 0, sizeof(svc->ifstmt));
|
||||
svc->manual = manual;
|
||||
svc->nowarn = nowarn;
|
||||
svc->respawn = respawn;
|
||||
svc->forking = forking;
|
||||
svc->restart_max = restart_max;
|
||||
@@ -1831,12 +1847,19 @@ void service_monitor(pid_t lost, int status)
|
||||
return;
|
||||
}
|
||||
|
||||
if (lost == run_block_pid) {
|
||||
svc_mark_clean(svc); /* done, regardless of exit status */
|
||||
run_block_pid = 0;
|
||||
}
|
||||
|
||||
switch (svc->state) {
|
||||
case SVC_CLEANUP_STATE:
|
||||
case SVC_SETUP_STATE:
|
||||
dbg("collected script %s(%d), normal exit: %d, signaled: %d, exit code: %d",
|
||||
svc->state == SVC_CLEANUP_STATE ? svc->post_script : svc->pre_script,
|
||||
lost, WIFEXITED(status), WIFSIGNALED(status), WEXITSTATUS(status));
|
||||
/* Kill all children in the same proess group, e.g. logit */
|
||||
dbg("Killing lingering children in same process group ...");
|
||||
kill(-svc->pid, SIGKILL);
|
||||
goto done;
|
||||
|
||||
@@ -1858,8 +1881,8 @@ void service_monitor(pid_t lost, int status)
|
||||
logit(LOG_CONSOLE | LOG_NOTICE, "Stopped %s[%d]", svc_ident(svc, NULL, 0), lost);
|
||||
}
|
||||
|
||||
|
||||
/* Terminate any children in the same proess group, e.g. logit */
|
||||
dbg("Killing lingering children in same process group ...");
|
||||
kill(-svc->pid, SIGKILL);
|
||||
|
||||
/* Try removing PID file (in case service does not clean up after itself) */
|
||||
@@ -2250,11 +2273,11 @@ void service_ready(svc_t *svc)
|
||||
*/
|
||||
int service_step(svc_t *svc)
|
||||
{
|
||||
cond_state_t cond;
|
||||
svc_state_t old_state;
|
||||
svc_cmd_t enabled;
|
||||
char *restart_cnt = (char *)&svc->restart_cnt;
|
||||
int changed = 0;
|
||||
int changed = 0, waiting = 0;
|
||||
svc_state_t old_state;
|
||||
cond_state_t cond;
|
||||
svc_cmd_t enabled;
|
||||
int err;
|
||||
|
||||
restart:
|
||||
@@ -2269,6 +2292,15 @@ restart:
|
||||
case SVC_HALTED_STATE:
|
||||
if (enabled)
|
||||
svc_set_state(svc, SVC_WAITING_STATE);
|
||||
else {
|
||||
if (svc_is_conflict(svc)) {
|
||||
logit(svc->nowarn ? LOG_DEBUG : LOG_INFO,
|
||||
"%s in conflict with %s, checking again ...",
|
||||
svc_ident(svc, NULL, 0), svc->conflict);
|
||||
if (!svc_conflicts(svc))
|
||||
svc_unblock(svc);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SVC_DONE_STATE:
|
||||
@@ -2335,6 +2367,16 @@ restart:
|
||||
if (sm_is_in_teardown(&sm))
|
||||
break;
|
||||
|
||||
/* Don't start if it conflicts with something else already started */
|
||||
if (svc_conflicts(svc)) {
|
||||
logit(svc->nowarn ? LOG_DEBUG : LOG_INFO,
|
||||
"Not starting %s, conflicts with %s",
|
||||
svc_ident(svc, NULL, 0), svc->conflict);
|
||||
svc_conflict(svc);
|
||||
svc_set_state(svc, SVC_HALTED_STATE);
|
||||
break;
|
||||
}
|
||||
|
||||
if (svc_has_pre(svc)) {
|
||||
svc_set_state(svc, SVC_SETUP_STATE);
|
||||
service_pre_script(svc);
|
||||
@@ -2352,6 +2394,10 @@ restart:
|
||||
|
||||
err = service_start(svc);
|
||||
if (err) {
|
||||
/* Busy, waiting for run task, try again later */
|
||||
if (run_block_pid)
|
||||
break;
|
||||
|
||||
if (svc_is_missing(svc)) {
|
||||
svc_set_state(svc, SVC_HALTED_STATE);
|
||||
break;
|
||||
@@ -2393,6 +2439,7 @@ restart:
|
||||
|
||||
if (svc_is_runtask(svc)) { /* only run/task, not sysv here */
|
||||
svc_set_state(svc, SVC_STOPPING_STATE);
|
||||
svc->restart_tot++;
|
||||
svc->once++;
|
||||
break;
|
||||
}
|
||||
@@ -2470,6 +2517,9 @@ restart:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Are we waiting for a run task to complete? */
|
||||
waiting = run_block_pid;
|
||||
|
||||
if (svc->state != old_state) {
|
||||
dbg("%20s(%4d): -> %8s", svc_ident(svc, NULL, 0), svc->pid, svc_status(svc));
|
||||
changed++;
|
||||
@@ -2481,7 +2531,7 @@ done:
|
||||
* When a run/task/service changes state, e.g. transitioning from
|
||||
* waiting to running, other services may need to change state too.
|
||||
*/
|
||||
if (changed)
|
||||
if (changed || waiting)
|
||||
schedule_work(&work);
|
||||
|
||||
return 0;
|
||||
@@ -2671,23 +2721,24 @@ static void service_interval_cb(uev_t *w, void *arg, int events)
|
||||
}
|
||||
}
|
||||
|
||||
service_init();
|
||||
service_init(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* The service_interval may change (conf) between invocations, so we
|
||||
* periodically reset the one-shot timer instead of using a periodic.
|
||||
*/
|
||||
void service_init(void)
|
||||
void service_init(uev_ctx_t *ctx)
|
||||
{
|
||||
static int initialized = 0;
|
||||
static uev_t watcher;
|
||||
|
||||
if (!initialized) {
|
||||
if (!initialized)
|
||||
uev_timer_init(ctx, &watcher, service_interval_cb, NULL, service_interval, 0);
|
||||
initialized = 1;
|
||||
} else
|
||||
else
|
||||
uev_timer_set(&watcher, service_interval, 0);
|
||||
|
||||
initialized = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ void service_worker (void *unused);
|
||||
int service_completed (void);
|
||||
void service_notify_reconf (void);
|
||||
|
||||
void service_init (void);
|
||||
void service_init (uev_ctx_t *ctx);
|
||||
|
||||
#endif /* FINIT_SERVICE_H_ */
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "conf.h"
|
||||
#include "helpers.h"
|
||||
#include "private.h"
|
||||
#include "schedule.h"
|
||||
#include "service.h"
|
||||
#include "sig.h"
|
||||
#include "tty.h"
|
||||
@@ -43,12 +44,53 @@ sm_t sm;
|
||||
#define FINIT_NOLOGIN_PATH _PATH_NOLOGIN /* Stop user logging in. */
|
||||
#endif
|
||||
|
||||
void sm_init(sm_t *sm)
|
||||
/*
|
||||
* Wait for system bootstrap to complete, all SVC_TYPE_RUNTASK must be
|
||||
* allowed to complete their work in [S], or timeout, before we switch
|
||||
* to the configured runlevel and call finalize(), should not take more
|
||||
* than 120 sec.
|
||||
*/
|
||||
static void sm_check_bootstrap(void *work)
|
||||
{
|
||||
sm->state = SM_BOOTSTRAP_STATE;
|
||||
sm->newlevel = -1;
|
||||
sm->reload = 0;
|
||||
sm->in_teardown = 0;
|
||||
static int cnt = 120 * 10; /* We run with 100ms period */
|
||||
int level = cfglevel;
|
||||
|
||||
dbg("Step all services ...");
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
|
||||
if (cnt-- > 0 && !service_completed()) {
|
||||
dbg("Not all bootstrap run/tasks have completed yet ... %d", cnt);
|
||||
schedule_work(work);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cnt > 0)
|
||||
dbg("All run/task have completed, resuming bootstrap.");
|
||||
else
|
||||
dbg("Timeout, resuming bootstrap.");
|
||||
|
||||
dbg("Flushing pending .conf file events ...");
|
||||
conf_flush_events();
|
||||
|
||||
/*
|
||||
* Start all tasks/services in the configured runlevel, or jump
|
||||
* into the runlevel selected from the command line.
|
||||
*/
|
||||
if (cmdlevel) {
|
||||
dbg("Runlevel %d requested from command line, starting all services ...", cmdlevel);
|
||||
level = cmdlevel;
|
||||
} else
|
||||
dbg("Change to default runlevel(%d), starting all services ...", cfglevel);
|
||||
|
||||
service_runlevel(level);
|
||||
|
||||
/* Clean up bootstrap-only tasks/services that never started */
|
||||
dbg("Clean up all bootstrap-only tasks/services ...");
|
||||
svc_prune_bootstrap();
|
||||
|
||||
/* All services/tasks/etc. in configure runlevel have started */
|
||||
dbg("Running svc up hooks ...");
|
||||
plugin_run_hooks(HOOK_SVC_UP);
|
||||
}
|
||||
|
||||
static char *sm_status(sm_state_t state)
|
||||
@@ -100,6 +142,22 @@ static void nologin(void)
|
||||
erase(FINIT_NOLOGIN_PATH);
|
||||
}
|
||||
|
||||
void sm_init(sm_t *sm)
|
||||
{
|
||||
static struct wq work = {
|
||||
.cb = sm_check_bootstrap,
|
||||
.delay = 1000
|
||||
};
|
||||
|
||||
sm->state = SM_BOOTSTRAP_STATE;
|
||||
sm->newlevel = -1;
|
||||
sm->reload = 0;
|
||||
sm->in_teardown = 0;
|
||||
|
||||
dbg("Starting bootstrap finalize timer ...");
|
||||
schedule_work(&work);
|
||||
}
|
||||
|
||||
void sm_set_runlevel(sm_t *sm, int newlevel)
|
||||
{
|
||||
sm->newlevel = newlevel;
|
||||
@@ -117,8 +175,8 @@ int sm_is_in_teardown(sm_t *sm)
|
||||
|
||||
void sm_step(sm_t *sm)
|
||||
{
|
||||
svc_t *svc;
|
||||
sm_state_t old_state;
|
||||
svc_t *svc;
|
||||
|
||||
restart:
|
||||
old_state = sm->state;
|
||||
@@ -130,10 +188,49 @@ restart:
|
||||
case SM_BOOTSTRAP_STATE:
|
||||
dbg("Bootstrapping all services in runlevel S from %s", finit_conf);
|
||||
service_step_all(SVC_TYPE_RUNTASK | SVC_TYPE_SERVICE);
|
||||
|
||||
sm->state = SM_BOOTSTRAP_WAIT_STATE;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Handle bootstrap transition to configured runlevel, start TTYs
|
||||
*
|
||||
* This is the final stage of bootstrap. It changes to the default
|
||||
* (configured) runlevel, calls all external start scripts and final
|
||||
* bootstrap hooks before bringing up TTYs.
|
||||
*
|
||||
* We must ensure that all declared `task [S]` and `run [S]` jobs in
|
||||
* finit.conf, or *.conf in finit.d/, run to completion before we
|
||||
* finalize the bootstrap process by calling this function.
|
||||
*/
|
||||
case SM_BOOTSTRAP_WAIT_STATE:
|
||||
/* We come here from bootstrap, runlevel change and conf reload */
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
|
||||
/* Allow runparts to start */
|
||||
cond_set("int/bootstrap");
|
||||
|
||||
if (sm->newlevel == -1)
|
||||
break;
|
||||
|
||||
/* Hooks that should run at the very end */
|
||||
dbg("Calling all system up hooks ...");
|
||||
plugin_run_hooks(HOOK_SYSTEM_UP);
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
|
||||
/* Disable progress output at normal runtime */
|
||||
enable_progress(0);
|
||||
|
||||
/* System bootrapped, launch TTYs et al */
|
||||
bootstrap = 0;
|
||||
service_step_all(SVC_TYPE_RESPAWN);
|
||||
sm->state = SM_RUNNING_STATE;
|
||||
break;
|
||||
|
||||
case SM_RUNNING_STATE:
|
||||
/* We come here from bootstrap, runlevel change and conf reload */
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
|
||||
/* runlevel changed? */
|
||||
if (sm->newlevel >= 0 && sm->newlevel <= 9) {
|
||||
if (runlevel == sm->newlevel) {
|
||||
@@ -143,6 +240,7 @@ restart:
|
||||
sm->state = SM_RUNLEVEL_CHANGE_STATE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* reload ? */
|
||||
if (sm->reload) {
|
||||
sm->reload = 0;
|
||||
@@ -210,17 +308,18 @@ restart:
|
||||
/* Cleanup stale services */
|
||||
svc_clean_dynamic(service_unregister);
|
||||
|
||||
/* Compat SysV init */
|
||||
if (prevlevel == INIT_LEVEL && !rescue)
|
||||
run_bg(FINIT_RC_LOCAL, NULL);
|
||||
|
||||
/*
|
||||
* "I've seen things you people wouldn't believe. Attack ships on fire off
|
||||
* the shoulder of Orion. I watched C-beams glitter in the dark near the
|
||||
* Tannhäuser Gate. All those .. moments .. will be lost in time, like
|
||||
* tears ... in ... rain."
|
||||
*/
|
||||
if (runlevel == 0 || runlevel == 6) {
|
||||
if (runlevel == 0 || runlevel == 6)
|
||||
do_shutdown(halt);
|
||||
sm->state = SM_RUNNING_STATE;
|
||||
break;
|
||||
}
|
||||
|
||||
sm->state = SM_RUNNING_STATE;
|
||||
break;
|
||||
@@ -266,9 +365,7 @@ restart:
|
||||
dbg("Update configuration generation of unmodified non-native services ...");
|
||||
service_notify_reconf();
|
||||
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
dbg("Reconfiguration done");
|
||||
|
||||
sm->state = SM_RUNNING_STATE;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
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 runlevel processes to be halted */
|
||||
|
||||
+1
-1
@@ -132,7 +132,7 @@ void stty(int fd, speed_t speed)
|
||||
dprint(fd, "\033[?25h", 6);
|
||||
|
||||
/* Enable line wrap, if disabled previously */
|
||||
dprint(fd, "\033[7h", 4);
|
||||
dprint(fd, "\033[?7h", 5);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+9
-3
@@ -21,6 +21,8 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <crypt.h>
|
||||
#include <err.h>
|
||||
#include <paths.h>
|
||||
@@ -32,6 +34,10 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#ifndef SULOGIN_USER
|
||||
#define SULOGIN_USER "root"
|
||||
#endif
|
||||
|
||||
/* getpwnam() cannot be used when statically linked */
|
||||
static int get_passwd(struct passwd *pw)
|
||||
{
|
||||
@@ -44,13 +50,13 @@ static int get_passwd(struct passwd *pw)
|
||||
return 1;
|
||||
|
||||
while ((tmp = fgets(buf, sizeof(buf), fp))) {
|
||||
if (!strstr(buf, ":0:0:"))
|
||||
continue; /* not uid 0 */
|
||||
|
||||
ptr = strsep(&tmp, ":");
|
||||
if (!ptr)
|
||||
break;
|
||||
|
||||
pw->pw_name = strdup(ptr);
|
||||
if (!pw->pw_name || strcmp(pw->pw_name, SULOGIN_USER))
|
||||
continue;
|
||||
|
||||
ptr = strsep(&tmp, ":");
|
||||
if (!ptr)
|
||||
|
||||
@@ -74,6 +74,7 @@ typedef enum {
|
||||
SVC_BLOCK_USER,
|
||||
SVC_BLOCK_BUSY,
|
||||
SVC_BLOCK_RESTARTING,
|
||||
SVC_BLOCK_CONFLICT,
|
||||
} svc_block_t;
|
||||
|
||||
typedef enum {
|
||||
@@ -84,6 +85,7 @@ typedef enum {
|
||||
|
||||
#define MAX_ID_LEN 16
|
||||
#define MAX_ARG_LEN 64
|
||||
#define MAX_CMD_LEN 256
|
||||
#define MAX_IDENT_LEN (MAX_ARG_LEN + MAX_ID_LEN + 1)
|
||||
#define MAX_STR_LEN 64
|
||||
#define MAX_COND_LEN (MAX_ARG_LEN * 3)
|
||||
@@ -117,7 +119,7 @@ typedef struct svc {
|
||||
int sighalt; /* Signal to stop process, default: SIGTERM */
|
||||
int killdelay; /* Delay in msec before sending SIGKILL */
|
||||
pid_t oldpid, pid;
|
||||
char pidfile[256];
|
||||
char pidfile[MAX_CMD_LEN];
|
||||
long start_time; /* Start time, as seconds since boot, from sysinfo() */
|
||||
int started; /* Set for run/task/sysv to track if started */
|
||||
int status; /* From waitpid() when process is collected */
|
||||
@@ -125,6 +127,7 @@ typedef struct svc {
|
||||
svc_type_t type; /* Service, run, task, ... */
|
||||
char protect; /* Services like dbus-daemon & udev by Finit */
|
||||
char manual; /* run/task that require `initctl start foo` */
|
||||
char nowarn; /* Skip or log warning if cmd missing or conflicts */
|
||||
const int dirty; /* 0: unmodified, 1: modified */
|
||||
const int removed;
|
||||
int starting; /* ... waiting for pidfile to be re-asserted */
|
||||
@@ -179,15 +182,15 @@ typedef struct svc {
|
||||
char group[MAX_USER_LEN];
|
||||
|
||||
/* Command, arguments and service description */
|
||||
char cmd[MAX_ARG_LEN];
|
||||
char args[MAX_NUM_SVC_ARGS][MAX_ARG_LEN];
|
||||
char cmd[MAX_CMD_LEN];
|
||||
char args[MAX_NUM_SVC_ARGS][MAX_CMD_LEN];
|
||||
int args_dirty;
|
||||
char conflict[MAX_ARG_LEN];
|
||||
char desc[MAX_STR_LEN];
|
||||
char env[MAX_ARG_LEN];
|
||||
char pre_script[MAX_ARG_LEN];
|
||||
char post_script[MAX_ARG_LEN];
|
||||
char ready_script[MAX_ARG_LEN];
|
||||
char env[MAX_CMD_LEN];
|
||||
char pre_script[MAX_CMD_LEN];
|
||||
char post_script[MAX_CMD_LEN];
|
||||
char ready_script[MAX_CMD_LEN];
|
||||
|
||||
/*
|
||||
* Used to forcefully kill services that won't shutdown on
|
||||
@@ -270,6 +273,7 @@ static inline int svc_is_busy (svc_t *svc) { return svc && svc->block == SV
|
||||
static inline int svc_is_missing (svc_t *svc) { return svc && svc->block == SVC_BLOCK_MISSING; }
|
||||
static inline int svc_is_crashing (svc_t *svc) { return svc && svc->block == SVC_BLOCK_CRASHING; }
|
||||
static inline int svc_is_restart (svc_t *svc) { return svc && svc->block == SVC_BLOCK_RESTARTING; }
|
||||
static inline int svc_is_conflict (svc_t *svc) { return svc && svc->block == SVC_BLOCK_CONFLICT; }
|
||||
|
||||
static inline void svc_unblock (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_NONE; }
|
||||
#define svc_start(svc) svc_unblock(svc)
|
||||
@@ -278,6 +282,7 @@ static inline void svc_busy (svc_t *svc) { if (svc) svc->block = SVC_BLOC
|
||||
static inline void svc_missing (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_MISSING; }
|
||||
static inline void svc_restarting (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_RESTARTING; }
|
||||
static inline void svc_crashing (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_CRASHING; }
|
||||
static inline void svc_conflict (svc_t *svc) { if (svc) svc->block = SVC_BLOCK_CONFLICT; }
|
||||
|
||||
/* Has condition in configuration and cond is allowed? */
|
||||
static inline int svc_has_cond(svc_t *svc)
|
||||
@@ -350,6 +355,9 @@ static inline char *svc_status(svc_t *svc)
|
||||
|
||||
case SVC_BLOCK_RESTARTING:
|
||||
return "restart";
|
||||
case SVC_BLOCK_CONFLICT:
|
||||
return "conflict";
|
||||
|
||||
}
|
||||
return "unknown";
|
||||
|
||||
|
||||
@@ -42,7 +42,10 @@ extern int ttcols;
|
||||
extern char *prognm;
|
||||
|
||||
/* Define for printheader() from conio.h, used in initctl */
|
||||
#ifndef SCREEN_WIDTH
|
||||
#define SCREEN_WIDTH ttcols
|
||||
#endif
|
||||
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/conio.h>
|
||||
# include <libite/lite.h>
|
||||
|
||||
@@ -60,7 +60,6 @@ static int init(char *progname, char *devnode)
|
||||
signal(SIGPWR, sighandler);
|
||||
|
||||
openlog(&progname[1], LOG_CONS | LOG_PID, LOG_DAEMON);
|
||||
syslog(LOG_INFO, "Finit v%s watchdog %s starting ...", VERSION, devnode);
|
||||
|
||||
fd = open(devnode, O_WRONLY);
|
||||
if (fd == -1)
|
||||
|
||||
+13
-1
@@ -2,7 +2,12 @@ SUBDIRS = lib src
|
||||
|
||||
EXTRA_DIST = skel/bin/busybox-x86_64.sha256 skel/sbin/service.sh skel/etc/env \
|
||||
skel/bin/pre.sh skel/bin/post.sh skel/bin/ready.sh skel/bin/slay \
|
||||
skel/sbin/fail.sh \
|
||||
skel/sbin/fail.sh skel/usr/share/runparts/ref.log \
|
||||
skel/usr/share/runparts/sysv.log \
|
||||
skel/etc/rc.d/foo.sh skel/etc/rc.d/S01abc.sh \
|
||||
skel/etc/rc.d/test.sh skel/etc/rc.d/S02def.sh \
|
||||
skel/etc/rcS.d/foo.sh skel/etc/rcS.d/test.sh \
|
||||
skel/etc/rcS.d/S01abc.sh skel/etc/rcS.d/S02def.sh \
|
||||
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 \
|
||||
@@ -37,6 +42,9 @@ EXTRA_DIST += ready-serv.sh
|
||||
EXTRA_DIST += restart-self.sh
|
||||
EXTRA_DIST += runlevel.sh
|
||||
EXTRA_DIST += run-restart-forever.sh
|
||||
EXTRA_DIST += run-task-tricks.sh
|
||||
EXTRA_DIST += runparts.sh
|
||||
EXTRA_DIST += sysvparts.sh
|
||||
EXTRA_DIST += start-stop-service.sh
|
||||
EXTRA_DIST += start-stop-service-sub-config.sh
|
||||
EXTRA_DIST += start-kill-service.sh
|
||||
@@ -61,6 +69,7 @@ TEST_EXTENSIONS = .sh
|
||||
TESTS = checkself.sh
|
||||
TESTS += add-remove-dynamic-service.sh
|
||||
TESTS += add-remove-dynamic-service-sub-config.sh
|
||||
TESTS += bootstrap-crash.sh
|
||||
TESTS += cond-start-task.sh
|
||||
TESTS += crashing.sh
|
||||
TESTS += depserv.sh
|
||||
@@ -75,7 +84,10 @@ TESTS += rclocal.sh
|
||||
TESTS += ready-serv.sh
|
||||
TESTS += restart-self.sh
|
||||
TESTS += runlevel.sh
|
||||
TESTS += sysvparts.sh
|
||||
TESTS += run-restart-forever.sh
|
||||
TESTS += run-task-tricks.sh
|
||||
TESTS += runparts.sh
|
||||
TESTS += start-stop-service.sh
|
||||
TESTS += start-stop-service-sub-config.sh
|
||||
TESTS += start-kill-service.sh
|
||||
|
||||
@@ -6,10 +6,10 @@ TEST_DIR=$(dirname "$0")
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Test done $(date)"
|
||||
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_RCSD/service.conf"
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_RCSD/service.conf"
|
||||
}
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
|
||||
@@ -6,10 +6,10 @@ TEST_DIR=$(dirname "$0")
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Test done $(date)"
|
||||
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
}
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
|
||||
+6
-10
@@ -4,7 +4,8 @@
|
||||
#set -eu
|
||||
|
||||
TEST_DIR=$(dirname "$0")
|
||||
DEBUG=1
|
||||
#DEBUG=1
|
||||
# shellcheck disable=SC2034
|
||||
BOOTSTRAP="run [S] crasher.sh -- Party crasher"
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
@@ -12,22 +13,17 @@ BOOTSTRAP="run [S] crasher.sh -- Party crasher"
|
||||
|
||||
test_setup()
|
||||
{
|
||||
say "Test start $(date)"
|
||||
say "Test start $(date)"
|
||||
}
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Running test teardown."
|
||||
run "rm -f $TEST_CONF"
|
||||
say "Test done $(date)"
|
||||
}
|
||||
|
||||
say "Hello SMTP Spoken here"
|
||||
run initctl
|
||||
run initctl status crasher.sh
|
||||
|
||||
sleep 10
|
||||
say "We are done"
|
||||
#run initctl
|
||||
#run initctl status crasher.sh
|
||||
|
||||
|
||||
exit 0
|
||||
|
||||
+53
-53
@@ -9,77 +9,77 @@ TEST_DIR=$(dirname "$0")
|
||||
|
||||
test_setup()
|
||||
{
|
||||
say "Test start $(date)"
|
||||
say "Test start $(date)"
|
||||
}
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Running test teardown."
|
||||
run "rm -f $TEST_CONF"
|
||||
say "Test done $(date)"
|
||||
say "Running test teardown."
|
||||
run "rm -f $TEST_CONF"
|
||||
}
|
||||
|
||||
test_one()
|
||||
{
|
||||
cond=$1
|
||||
stanza=$2
|
||||
cond=$1
|
||||
stanza=$2
|
||||
|
||||
sleep 5
|
||||
say 'Enable finit debug, try to figure out what is going on ...'
|
||||
run "initctl debug"
|
||||
sleep 5
|
||||
say 'Enable finit debug, try to figure out what is going on ...'
|
||||
run "initctl debug"
|
||||
|
||||
say "Add stanza '$stanza' to $TEST_CONF ..."
|
||||
run "echo '$stanza' > $TEST_CONF"
|
||||
say "Add stanza '$stanza' to $TEST_CONF ..."
|
||||
run "echo '$stanza' > $TEST_CONF"
|
||||
|
||||
run "ls -l /run/ /run/finit/"
|
||||
say 'Reload Finit'
|
||||
run "initctl ls"
|
||||
run "initctl reload"
|
||||
run "initctl status"
|
||||
run "ps"
|
||||
run "ls -l /run/ /run/finit/"
|
||||
say 'Reload Finit'
|
||||
run "initctl ls"
|
||||
run "initctl reload"
|
||||
run "initctl status"
|
||||
run "ps"
|
||||
|
||||
date
|
||||
sleep 2
|
||||
date
|
||||
run "ls -l /run/ /run/finit/"
|
||||
say 'Asserting condition'
|
||||
run "initctl cond set $cond"
|
||||
date
|
||||
sleep 2
|
||||
date
|
||||
run "ls -l /run/ /run/finit/"
|
||||
say 'Asserting condition'
|
||||
run "initctl cond set $cond"
|
||||
|
||||
date
|
||||
sleep 2
|
||||
date
|
||||
run "ls -l /run/ /run/finit/"
|
||||
run "initctl status"
|
||||
run "ps"
|
||||
run "initctl status task.sh"
|
||||
date
|
||||
sleep 2
|
||||
date
|
||||
run "ls -l /run/ /run/finit/"
|
||||
run "initctl status"
|
||||
run "ps"
|
||||
run "initctl status task.sh"
|
||||
|
||||
sleep 1
|
||||
run "echo Hej; cat /run/task.state"
|
||||
sleep 1
|
||||
run "echo Hej; cat /run/task.state"
|
||||
|
||||
assert_file_contains /run/task.state 1
|
||||
assert_file_contains /run/task.state 1
|
||||
|
||||
say 'Reload Finit'
|
||||
run "initctl reload"
|
||||
sleep 1
|
||||
say 'Ensure task has not run again ...'
|
||||
assert_file_contains /run/task.state 1
|
||||
say 'Reload Finit'
|
||||
run "initctl reload"
|
||||
sleep 1
|
||||
say 'Ensure task has not run again ...'
|
||||
assert_file_contains /run/task.state 1
|
||||
|
||||
say 'Switch to another runlevel ...'
|
||||
run "initctl runlevel 3"
|
||||
sleep 1
|
||||
say 'Ensure task has run again ...'
|
||||
assert_file_contains /run/task.state 2
|
||||
|
||||
say 'Touch task.sh .conf file and reload Finit ...'
|
||||
run "touch $TEST_CONF"
|
||||
run "initctl reload"
|
||||
sleep 1
|
||||
# run "initctl status task.sh"
|
||||
assert_file_contains /run/task.state 3
|
||||
say 'Switch to another runlevel ...'
|
||||
run "initctl runlevel 3"
|
||||
sleep 1
|
||||
say 'Ensure task has run again ...'
|
||||
assert_file_contains /run/task.state 2
|
||||
|
||||
say 'Touch task.sh .conf file and reload Finit ...'
|
||||
run "touch $TEST_CONF"
|
||||
run "initctl reload"
|
||||
sleep 1
|
||||
# run "initctl status task.sh"
|
||||
assert_file_contains /run/task.state 3
|
||||
|
||||
say "Done, drop stanza from $TEST_CONF ..."
|
||||
run "rm $TEST_CONF"
|
||||
run "initctl reload"
|
||||
say "Done, drop stanza from $TEST_CONF ..."
|
||||
run "rm $TEST_CONF"
|
||||
run "initctl reload"
|
||||
}
|
||||
|
||||
|
||||
|
||||
+33
-33
@@ -7,57 +7,57 @@ TEST_DIR=$(dirname "$0")
|
||||
|
||||
test_setup()
|
||||
{
|
||||
say "Test start $(date)"
|
||||
say "Test start $(date)"
|
||||
}
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Test done $(date)"
|
||||
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF" "/tmp/post"
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF" "/tmp/post"
|
||||
}
|
||||
|
||||
crashit()
|
||||
{
|
||||
nm=$1
|
||||
nm=$1
|
||||
|
||||
say 'Simulate service crash (kill -9 ..)'
|
||||
i=0
|
||||
laps=100
|
||||
while [ $i -lt $laps ]; do
|
||||
i=$((i + 1))
|
||||
say "Lap $i/$laps, killing service $nm ..." # we have this, no sleep needed
|
||||
if ! run "slay $nm"; then
|
||||
break;
|
||||
fi
|
||||
done
|
||||
say 'Simulate service crash (kill -9 ..)'
|
||||
i=0
|
||||
laps=100
|
||||
while [ $i -lt $laps ]; do
|
||||
i=$((i + 1))
|
||||
say "Lap $i/$laps, killing service $nm ..." # we have this, no sleep needed
|
||||
if ! run "slay $nm"; then
|
||||
break;
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
test_one()
|
||||
{
|
||||
type=$1
|
||||
shift
|
||||
nm=$1
|
||||
shift
|
||||
args=$*
|
||||
type=$1
|
||||
shift
|
||||
nm=$1
|
||||
shift
|
||||
args=$*
|
||||
|
||||
say "Add service stanza in $FINIT_CONF"
|
||||
run "echo service log:stderr oncrash:script post:/bin/post.sh $nm $args > $FINIT_CONF"
|
||||
say "Add service stanza in $FINIT_CONF"
|
||||
run "echo service log:stderr oncrash:script post:/bin/post.sh $nm $args > $FINIT_CONF"
|
||||
|
||||
say 'Reload Finit'
|
||||
run "initctl reload"
|
||||
say 'Reload Finit'
|
||||
run "initctl reload"
|
||||
|
||||
if [ "$type" = "sig" ]; then
|
||||
retry "assert_num_children 1 $nm"
|
||||
run "initctl status $nm"
|
||||
crashit "$nm"
|
||||
fi
|
||||
if [ "$type" = "sig" ]; then
|
||||
retry "assert_num_children 1 $nm"
|
||||
run "initctl status $nm"
|
||||
crashit "$nm"
|
||||
fi
|
||||
|
||||
retry "assert_status $nm crashed" 500
|
||||
run "cat /tmp/post"
|
||||
assert_file_contains "/tmp/post" "POST"
|
||||
run "rm -f /tmp/post"
|
||||
retry "assert_status $nm crashed" 500
|
||||
run "cat /tmp/post"
|
||||
assert_file_contains "/tmp/post" "POST"
|
||||
run "rm -f /tmp/post"
|
||||
}
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
|
||||
+30
-30
@@ -16,15 +16,15 @@ TEST_DIR=$(dirname "$0")
|
||||
|
||||
test_setup()
|
||||
{
|
||||
say "Test start $(date)"
|
||||
say "Test start $(date)"
|
||||
}
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Running test teardown."
|
||||
say "Test done $(date)"
|
||||
say "Running test teardown."
|
||||
|
||||
run "rm -f $FINIT_CONF" "/tmp/post"
|
||||
run "rm -f $FINIT_CONF" "/tmp/post"
|
||||
}
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
@@ -35,36 +35,36 @@ test_teardown()
|
||||
|
||||
test_one()
|
||||
{
|
||||
cond=$1
|
||||
say "Verifying foo -> <$cond> bar ..."
|
||||
run "echo service log:stderr name:foo serv -np -i foo -f /tmp/arrakis > $FINIT_CONF"
|
||||
run "echo service log:stderr name:bar \<!$cond\> serv -np -i bar -F /tmp/arrakis >> $FINIT_CONF"
|
||||
run "cat $FINIT_CONF"
|
||||
cond=$1
|
||||
say "Verifying foo -> <$cond> bar ..."
|
||||
run "echo service log:stderr name:foo serv -np -i foo -f /tmp/arrakis > $FINIT_CONF"
|
||||
run "echo service log:stderr name:bar \<!$cond\> serv -np -i bar -F /tmp/arrakis >> $FINIT_CONF"
|
||||
run "cat $FINIT_CONF"
|
||||
|
||||
say 'Reload Finit'
|
||||
run "initctl reload"
|
||||
say 'Reload Finit'
|
||||
run "initctl reload"
|
||||
|
||||
run "initctl status"
|
||||
assert_status "foo" "running"
|
||||
assert_cond "$cond"
|
||||
assert_status "bar" "running"
|
||||
run "initctl status"
|
||||
assert_status "foo" "running"
|
||||
assert_cond "$cond"
|
||||
assert_status "bar" "running"
|
||||
|
||||
say "Verify bar is restarted when foo is ..."
|
||||
pid=$(texec initctl |grep bar | awk '{print $1;}')
|
||||
run "initctl restart foo"
|
||||
run "initctl status"
|
||||
assert "bar is restarted" "$(texec initctl |grep bar | awk '{print $1;}')" != "$pid"
|
||||
say "Verify bar is restarted when foo is ..."
|
||||
pid=$(texec initctl |grep bar | awk '{print $1;}')
|
||||
run "initctl restart foo"
|
||||
run "initctl status"
|
||||
assert "bar is restarted" "$(texec initctl |grep bar | awk '{print $1;}')" != "$pid"
|
||||
|
||||
# Wait for spice to be stolen by the Harkonnen
|
||||
sleep 3
|
||||
# bar should now have detected the loss of spice and be in restart
|
||||
run "initctl status"
|
||||
assert_status "bar" "restart"
|
||||
# verify bar is stopped->waiting and no longer in restart after stopping foo
|
||||
run "initctl stop foo"
|
||||
run "initctl status"
|
||||
run "initctl status bar"
|
||||
assert_status "bar" "waiting"
|
||||
# Wait for spice to be stolen by the Harkonnen
|
||||
sleep 3
|
||||
# bar should now have detected the loss of spice and be in restart
|
||||
run "initctl status"
|
||||
assert_status "bar" "restart"
|
||||
# verify bar is stopped->waiting and no longer in restart after stopping foo
|
||||
run "initctl stop foo"
|
||||
run "initctl status"
|
||||
run "initctl status bar"
|
||||
assert_status "bar" "waiting"
|
||||
}
|
||||
|
||||
sep
|
||||
|
||||
+22
-22
@@ -9,52 +9,52 @@ TEST_DIR=$(dirname "$0")
|
||||
|
||||
test_setup()
|
||||
{
|
||||
say "Test start $(date)"
|
||||
say "Test start $(date)"
|
||||
}
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Running test teardown."
|
||||
say "Test done $(date)"
|
||||
say "Running test teardown."
|
||||
|
||||
run "rm -f $FINIT_CONF /tmp/post"
|
||||
run "rm -f $FINIT_CONF /tmp/post"
|
||||
}
|
||||
|
||||
# Cannot run mknod as non-root even in a chroot
|
||||
# touch is close enough for our needs
|
||||
mkdev()
|
||||
{
|
||||
dir=$(dirname "$1")
|
||||
run "mkdir -p $dir"
|
||||
run "touch $1"
|
||||
dir=$(dirname "$1")
|
||||
run "mkdir -p $dir"
|
||||
run "touch $1"
|
||||
}
|
||||
|
||||
rmdev()
|
||||
{
|
||||
run "rm $1"
|
||||
run "rm $1"
|
||||
}
|
||||
|
||||
test_one()
|
||||
{
|
||||
cond="$1"
|
||||
node="/$cond"
|
||||
cond="$1"
|
||||
node="/$cond"
|
||||
|
||||
say "Checking cond $cond and device $node ..."
|
||||
run "echo service log:null \<$cond\> serv -np >> $FINIT_CONF"
|
||||
run "cat $FINIT_CONF"
|
||||
run "initctl reload"
|
||||
say "Checking cond $cond and device $node ..."
|
||||
run "echo service log:null \<$cond\> serv -np >> $FINIT_CONF"
|
||||
run "cat $FINIT_CONF"
|
||||
run "initctl reload"
|
||||
|
||||
assert_status "serv" "waiting"
|
||||
assert_status "serv" "waiting"
|
||||
|
||||
mkdev "$node"
|
||||
assert_status "serv" "running"
|
||||
mkdev "$node"
|
||||
assert_status "serv" "running"
|
||||
|
||||
rmdev "$node"
|
||||
assert_status "serv" "waiting"
|
||||
rmdev "$node"
|
||||
assert_status "serv" "waiting"
|
||||
|
||||
say "Cleaning up ..."
|
||||
run "rm $FINIT_CONF"
|
||||
run "initctl reload"
|
||||
say "Cleaning up ..."
|
||||
run "rm $FINIT_CONF"
|
||||
run "initctl reload"
|
||||
}
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
|
||||
@@ -8,16 +8,16 @@ TEST_DIR=$(dirname "$0")
|
||||
|
||||
test_setup()
|
||||
{
|
||||
say "Test start $(date)"
|
||||
run "mkdir -p /etc/default"
|
||||
say "Test start $(date)"
|
||||
run "mkdir -p /etc/default"
|
||||
}
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Test done $(date)"
|
||||
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
}
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
|
||||
+4
-4
@@ -5,15 +5,15 @@ TEST_DIR=$(dirname "$0")
|
||||
|
||||
test_setup()
|
||||
{
|
||||
say "Test start $(date)"
|
||||
say "Test start $(date)"
|
||||
}
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Test done $(date)"
|
||||
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
}
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
|
||||
@@ -9,28 +9,28 @@ TEST_DIR=$(dirname "$0")
|
||||
|
||||
test_setup()
|
||||
{
|
||||
say "Test start $(date)"
|
||||
say "Test start $(date)"
|
||||
}
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Test done $(date)"
|
||||
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
}
|
||||
|
||||
test_init()
|
||||
{
|
||||
run "echo '# Three foo and one bar enter Finit' > $FINIT_CONF"
|
||||
run "echo '# Three foo and one bar enter Finit' > $FINIT_CONF"
|
||||
}
|
||||
|
||||
test_add_one()
|
||||
{
|
||||
service=$1
|
||||
service=$1
|
||||
|
||||
say "Add service stanza '$service' to $FINIT_CONF ..."
|
||||
run "echo '$service' >> $FINIT_CONF"
|
||||
say "Add service stanza '$service' to $FINIT_CONF ..."
|
||||
run "echo '$service' >> $FINIT_CONF"
|
||||
}
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
|
||||
+7
-7
@@ -4,10 +4,10 @@ set -eu
|
||||
|
||||
cmd=""
|
||||
if [ "$#" -lt 1 ]; then
|
||||
cmd="/bin/sh"
|
||||
cmd="/bin/sh"
|
||||
else
|
||||
cmd=$1
|
||||
shift
|
||||
cmd=$1
|
||||
shift
|
||||
fi
|
||||
|
||||
TEST_DIR=$(dirname "$0")/..
|
||||
@@ -15,11 +15,11 @@ SYSROOT="${SYSROOT:-$(pwd)/${TEST_DIR}/sysroot}"
|
||||
PID_FILE="$SYSROOT/running_test.pid"
|
||||
|
||||
if [ -f "$PID_FILE" ] ; then
|
||||
target=$(cat "$PID_FILE")
|
||||
target=$(pgrep -P "$target")
|
||||
target=$(cat "$PID_FILE")
|
||||
target=$(pgrep -P "$target")
|
||||
else
|
||||
echo "No test running!"
|
||||
exit 1
|
||||
echo "No test running!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC1091
|
||||
|
||||
+12
-12
@@ -24,9 +24,9 @@
|
||||
set -eu
|
||||
|
||||
if [ "$#" -lt 2 ]; then
|
||||
echo "Usage:"
|
||||
echo " $0 [target-pid] [command [arguments]]"
|
||||
exit 1
|
||||
echo "Usage:"
|
||||
echo " $0 [target-pid] [command [arguments]]"
|
||||
exit 1
|
||||
fi
|
||||
target="$1"
|
||||
shift
|
||||
@@ -46,12 +46,12 @@ PATH="$TESTENV_PATH"
|
||||
export PATH
|
||||
|
||||
"$nsenter" \
|
||||
--preserve-credentials \
|
||||
--user \
|
||||
--mount \
|
||||
--uts \
|
||||
--ipc \
|
||||
--net \
|
||||
--pid \
|
||||
-w -t "$target" \
|
||||
"$chroot" "$SYSROOT" "$@"
|
||||
--preserve-credentials \
|
||||
--user \
|
||||
--mount \
|
||||
--uts \
|
||||
--ipc \
|
||||
--net \
|
||||
--pid \
|
||||
-w -t "$target" \
|
||||
"$chroot" "$SYSROOT" "$@"
|
||||
|
||||
+47
-20
@@ -52,6 +52,11 @@ assert_new_pid()
|
||||
assert "Finit has registered new PID" "$(texec initctl |grep $1 | awk '{print $1;}')" -eq "$(texec cat $2)"
|
||||
}
|
||||
|
||||
assert_pidiff()
|
||||
{
|
||||
assert "PID has changed (old PID $2)" "$(texec initctl |awk -v svc="$1" '$0 ~ svc {print $1}')" -ne "$2"
|
||||
}
|
||||
|
||||
assert_restarts()
|
||||
{
|
||||
assert "Finit has registered restarts" "$(texec initctl status "$2" | awk '/Restarts/{print $3;}')" -ge "$1"
|
||||
@@ -59,7 +64,7 @@ assert_restarts()
|
||||
|
||||
assert_restart_cnt()
|
||||
{
|
||||
assert "Finit restart cnt $1" "$(texec initctl status "$2" | awk '/Restarts/{print $4;}')" = "($1)"
|
||||
assert "Finit restart total $1 cnt $2" "$(texec initctl status "$3" | awk '/Restarts/{print $3 $4;}')" = "$1($2)"
|
||||
}
|
||||
|
||||
assert_norestart()
|
||||
@@ -226,7 +231,8 @@ wdstart()
|
||||
|
||||
wdkill()
|
||||
{
|
||||
kill -KILL $wdpid
|
||||
say "Stopping test watchdog, pid $wdpid"
|
||||
kill -KILL $wdpid
|
||||
}
|
||||
|
||||
teardown()
|
||||
@@ -247,11 +253,15 @@ teardown()
|
||||
log "$fg_red" 'TEST FAIL' ''
|
||||
fi
|
||||
|
||||
say "Telling Finit to shut down (set -$-) ..."
|
||||
set +e
|
||||
if [ -n "${finit_pid+x}" ]; then
|
||||
texec kill -SIGUSR2 1
|
||||
fi
|
||||
say "Telling Finit to shut down (set -$-) ..."
|
||||
while [ -n "${finit_pid+x}" ]; do
|
||||
if ! kill -USR2 "${finit_pid}" 2>/dev/null; then
|
||||
break
|
||||
fi
|
||||
say "Retrying shutdown ..."
|
||||
sleep 1
|
||||
done
|
||||
|
||||
say "Waiting for Finit to shut down ..."
|
||||
wait
|
||||
@@ -259,6 +269,7 @@ teardown()
|
||||
say "Final cleanup ..."
|
||||
rm -f "$SYSROOT"/running_test.pid
|
||||
rm -f "$SYSROOT$FINIT_CONF"
|
||||
rm -f "$SYSROOT/etc/rc.local"
|
||||
|
||||
say "EXIT: $test_status"
|
||||
exit $test_status
|
||||
@@ -287,14 +298,30 @@ else
|
||||
fi
|
||||
|
||||
set +u
|
||||
rm -f "$SYSROOT$FINIT_CONF"
|
||||
touch "$SYSROOT$FINIT_CONF"
|
||||
|
||||
if [ -n "$BOOTSTRAP" ]; then
|
||||
say "Setting up bootstrap tasks ..."
|
||||
echo "$BOOTSTRAP" > "$SYSROOT$FINIT_CONF"
|
||||
say "Setting up bootstrap tasks ..."
|
||||
echo "$BOOTSTRAP" >> "$SYSROOT$FINIT_CONF"
|
||||
fi
|
||||
|
||||
if [ -n "$RUNPARTS" ]; then
|
||||
say "Setting up runparts task ..."
|
||||
echo "runparts /etc/rc.d" >> "$SYSROOT$FINIT_CONF"
|
||||
mkdir "$SYSROOT/etc/rc.d"
|
||||
echo "$RUNPARTS" > "$SYSROOT/etc/rc.d/start.sh"
|
||||
chmod +x "$SYSROOT/etc/rc.d/start.sh"
|
||||
fi
|
||||
|
||||
if [ -n "$RCLOCAL" ]; then
|
||||
say "Setting up /etc/rc.local ..."
|
||||
echo "$RCLOCAL" > "$SYSROOT/etc/rc.local"
|
||||
chmod +x "$SYSROOT/etc/rc.local"
|
||||
while [ -f "$SYSROOT/etc/rc.local" ]; do
|
||||
echo "$SYSROOT/etc/rc.local busy ... waiting ..."
|
||||
sleep 1
|
||||
done
|
||||
say "Setting up /etc/rc.local ..."
|
||||
echo "$RCLOCAL" > "$SYSROOT/etc/rc.local"
|
||||
chmod +x "$SYSROOT/etc/rc.local"
|
||||
fi
|
||||
set -u
|
||||
|
||||
@@ -307,7 +334,7 @@ echo "$finit_ppid" > "$SYSROOT"/running_test.pid
|
||||
log "$color_reset" 'Setup of test environment done, waiting for Finit ...' ''
|
||||
|
||||
finit_pid=$(retry "pgrep -P $finit_ppid")
|
||||
echo "Finit running as $finit_pid"
|
||||
echo "Finit running as PID $finit_pid"
|
||||
#tty=/dev/$(texec cat /sys/class/tty/console/active)
|
||||
#texec cat "$tty" &
|
||||
|
||||
@@ -315,17 +342,17 @@ echo "Finit running as $finit_pid"
|
||||
i=0
|
||||
set +u
|
||||
while [ -z "$BOOTSTRAP" ] && [ $i -lt 10 ]; do
|
||||
lvl=$(texec sh -c "initctl runlevel | awk '{print \$2;}'")
|
||||
if [ "$lvl" = "$FINIT_RUNLEVEL" ]; then
|
||||
say "Reached runlevel $FINIT_RUNLEVEL, releasing test."
|
||||
break;
|
||||
fi
|
||||
i=$((i + 1))
|
||||
sleep 1
|
||||
lvl=$(texec sh -c "initctl runlevel | awk '{print \$2;}'")
|
||||
if [ "$lvl" = "$FINIT_RUNLEVEL" ]; then
|
||||
say "Reached runlevel $FINIT_RUNLEVEL, releasing test."
|
||||
break;
|
||||
fi
|
||||
i=$((i + 1))
|
||||
sleep 1
|
||||
done
|
||||
set -u
|
||||
|
||||
if type test_setup > /dev/null 2>&1 ; then
|
||||
test_setup
|
||||
test_setup
|
||||
fi
|
||||
wdstart $TEST_TIMEOUT
|
||||
|
||||
+18
-18
@@ -8,16 +8,16 @@ TEST_DIR=$(dirname "$0")
|
||||
|
||||
test_setup()
|
||||
{
|
||||
say "Test start $(date)"
|
||||
run "mkdir -p /etc/default"
|
||||
say "Test start $(date)"
|
||||
run "mkdir -p /etc/default"
|
||||
}
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Running test teardown."
|
||||
say "Test done $(date)"
|
||||
say "Running test teardown."
|
||||
|
||||
run "rm -f $FINIT_CONF"
|
||||
run "rm -f $FINIT_CONF"
|
||||
}
|
||||
|
||||
test_one()
|
||||
@@ -37,11 +37,11 @@ test_one()
|
||||
run "initctl reload"
|
||||
|
||||
sleep 1
|
||||
# run "initctl status serv"
|
||||
# run "initctl status serv"
|
||||
assert_status "serv" "running"
|
||||
|
||||
sleep 2
|
||||
# run "initctl cond dump"
|
||||
# run "initctl cond dump"
|
||||
assert_cond "service/serv/ready"
|
||||
|
||||
say "Verify 'ready' is set after SIGHUP ..."
|
||||
@@ -52,7 +52,7 @@ test_one()
|
||||
|
||||
# Issue #343
|
||||
say "Verify 'ready' is reasserted if service crashes and is restarted ..."
|
||||
# run "initctl status serv"
|
||||
# run "initctl status serv"
|
||||
run "initctl signal serv 9"
|
||||
retry 'assert_status "serv" "running"' 2 1
|
||||
retry 'assert_cond "service/serv/ready"' 3 1
|
||||
@@ -67,7 +67,7 @@ test_one()
|
||||
say "Verify 'ready' is reasserted on 'initctl reload' ..."
|
||||
run "initctl reload"
|
||||
sleep 1
|
||||
# run "initctl; initctl cond dump"
|
||||
# run "initctl; initctl cond dump"
|
||||
assert_status "serv" "running"
|
||||
assert_cond "service/serv/ready"
|
||||
|
||||
@@ -75,12 +75,12 @@ test_one()
|
||||
# 'started' when they created their PID file. The serv test daemon
|
||||
# waits 3 sec between pidfile and notify to trigger this bug.
|
||||
if [ "$type" != "native" ]; then
|
||||
say "Verify 'ready' is *not* asserted immediately on restart + reload"
|
||||
run "initctl restart serv"
|
||||
run "initctl reload"
|
||||
sleep 1
|
||||
assert_nocond "service/serv/ready"
|
||||
retry 'assert_cond "service/serv/ready"' 5 0.5
|
||||
say "Verify 'ready' is *not* asserted immediately on restart + reload"
|
||||
run "initctl restart serv"
|
||||
run "initctl reload"
|
||||
sleep 1
|
||||
assert_nocond "service/serv/ready"
|
||||
retry 'assert_cond "service/serv/ready"' 5 0.5
|
||||
fi
|
||||
|
||||
say "Verify 'ready' is deasserted on stop ..."
|
||||
@@ -93,9 +93,9 @@ test_one()
|
||||
run "rm -f $FINIT_CONF"
|
||||
run "initctl reload"
|
||||
|
||||
# sleep 2
|
||||
# num=$(run "find /proc/1/fd |wc -l")
|
||||
# say "finit: number of open file descriptors after test: $num"
|
||||
# sleep 2
|
||||
# num=$(run "find /proc/1/fd |wc -l")
|
||||
# say "finit: number of open file descriptors after test: $num"
|
||||
}
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
|
||||
+14
-14
@@ -7,32 +7,32 @@ TEST_DIR=$(dirname "$0")
|
||||
|
||||
test_setup()
|
||||
{
|
||||
say "Test start $(date)"
|
||||
say "Test start $(date)"
|
||||
}
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Running test teardown."
|
||||
say "Test done $(date)"
|
||||
say "Running test teardown."
|
||||
|
||||
run "rm -f $FINIT_CONF" "/tmp/post"
|
||||
run "rm -f $FINIT_CONF" "/tmp/post"
|
||||
}
|
||||
|
||||
test_one()
|
||||
{
|
||||
pidfn=$1
|
||||
service=$2
|
||||
pidfn=$1
|
||||
service=$2
|
||||
|
||||
sep
|
||||
say "Add service stanza '$service' to $FINIT_CONF ..."
|
||||
run "echo '$service' > $FINIT_CONF"
|
||||
run "initctl reload"
|
||||
sep
|
||||
say "Add service stanza '$service' to $FINIT_CONF ..."
|
||||
run "echo '$service' > $FINIT_CONF"
|
||||
run "initctl reload"
|
||||
|
||||
assert_is_pidfile "serv" "$pidfn"
|
||||
assert_is_pidfile "serv" "$pidfn"
|
||||
|
||||
say "Done, drop service from $FINIT_CONF ..."
|
||||
run "rm $FINIT_CONF"
|
||||
run "initctl reload"
|
||||
say "Done, drop service from $FINIT_CONF ..."
|
||||
run "rm $FINIT_CONF"
|
||||
run "initctl reload"
|
||||
}
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
|
||||
+28
-28
@@ -5,49 +5,49 @@ TEST_DIR=$(dirname "$0")
|
||||
|
||||
test_setup()
|
||||
{
|
||||
say "Test start $(date)"
|
||||
say "Test start $(date)"
|
||||
}
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Test done $(date)"
|
||||
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
}
|
||||
|
||||
test_one()
|
||||
{
|
||||
pre=$1
|
||||
precont=$2
|
||||
service=$3
|
||||
post=$4
|
||||
postcont=$5
|
||||
pre=$1
|
||||
precont=$2
|
||||
service=$3
|
||||
post=$4
|
||||
postcont=$5
|
||||
|
||||
say "Add service stanza '$service' to $FINIT_CONF ..."
|
||||
run "echo '$service' > $FINIT_CONF"
|
||||
say "Add service stanza '$service' to $FINIT_CONF ..."
|
||||
run "echo '$service' > $FINIT_CONF"
|
||||
|
||||
say 'Reload Finit'
|
||||
run "initctl reload"
|
||||
say 'Reload Finit'
|
||||
run "initctl reload"
|
||||
|
||||
retry 'assert_num_children 1 serv'
|
||||
if [ -n "$pre" ]; then
|
||||
assert_file_contains "$pre" "$precont"
|
||||
run "rm -f $pre"
|
||||
fi
|
||||
retry 'assert_num_children 1 serv'
|
||||
if [ -n "$pre" ]; then
|
||||
assert_file_contains "$pre" "$precont"
|
||||
run "rm -f $pre"
|
||||
fi
|
||||
|
||||
say 'Stop the service'
|
||||
run "initctl stop serv"
|
||||
say 'Stop the service'
|
||||
run "initctl stop serv"
|
||||
|
||||
retry 'assert_num_children 0 serv'
|
||||
if [ -n "$post" ]; then
|
||||
assert_file_contains "$post" "$postcont"
|
||||
run "rm -f $post"
|
||||
fi
|
||||
retry 'assert_num_children 0 serv'
|
||||
if [ -n "$post" ]; then
|
||||
assert_file_contains "$post" "$postcont"
|
||||
run "rm -f $post"
|
||||
fi
|
||||
|
||||
say "Done, drop service from $FINIT_CONF ..."
|
||||
run "rm $FINIT_CONF"
|
||||
run "initctl reload"
|
||||
say "Done, drop service from $FINIT_CONF ..."
|
||||
run "rm $FINIT_CONF"
|
||||
run "initctl reload"
|
||||
}
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
|
||||
+2
-3
@@ -12,13 +12,12 @@ RCLOCAL="echo 'KILROY WAS HERE' > /tmp/rclocal"
|
||||
|
||||
test_setup()
|
||||
{
|
||||
say "Test start $(date)"
|
||||
say "Test start $(date)"
|
||||
}
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
run "rm -f $SYSROOT/etc/rc.local"
|
||||
say "Test done $(date)"
|
||||
}
|
||||
|
||||
sleep 1
|
||||
|
||||
+19
-19
@@ -6,39 +6,39 @@ TEST_DIR=$(dirname "$0")
|
||||
|
||||
test_setup()
|
||||
{
|
||||
say "Test start $(date)"
|
||||
say "Test start $(date)"
|
||||
}
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Test done $(date)"
|
||||
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
}
|
||||
|
||||
test_one()
|
||||
{
|
||||
service=$1
|
||||
file=/tmp/ready
|
||||
service=$1
|
||||
file=/tmp/ready
|
||||
|
||||
say "Add service stanza '$service' to $FINIT_CONF ..."
|
||||
run "echo '$service' > $FINIT_CONF"
|
||||
say "Add service stanza '$service' to $FINIT_CONF ..."
|
||||
run "echo '$service' > $FINIT_CONF"
|
||||
|
||||
say 'Reload Finit'
|
||||
run "initctl reload"
|
||||
say 'Reload Finit'
|
||||
run "initctl reload"
|
||||
|
||||
retry 'assert_num_children 1 serv'
|
||||
assert_file_contains "$file" "READY"
|
||||
run "rm -f $file"
|
||||
retry 'assert_num_children 1 serv'
|
||||
assert_file_contains "$file" "READY"
|
||||
run "rm -f $file"
|
||||
|
||||
say 'Stop the service'
|
||||
run "initctl stop serv"
|
||||
retry 'assert_num_children 0 serv'
|
||||
say 'Stop the service'
|
||||
run "initctl stop serv"
|
||||
retry 'assert_num_children 0 serv'
|
||||
|
||||
say "Done, drop service from $FINIT_CONF ..."
|
||||
run "rm $FINIT_CONF"
|
||||
run "initctl reload"
|
||||
say "Done, drop service from $FINIT_CONF ..."
|
||||
run "rm $FINIT_CONF"
|
||||
run "initctl reload"
|
||||
}
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
|
||||
@@ -6,21 +6,21 @@ TEST_DIR=$(dirname "$0")
|
||||
|
||||
test_setup()
|
||||
{
|
||||
say "Test start $(date)"
|
||||
run "mkdir -p /etc/default"
|
||||
say "Test start $(date)"
|
||||
run "mkdir -p /etc/default"
|
||||
}
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Test done $(date)"
|
||||
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
}
|
||||
|
||||
check_restarts()
|
||||
{
|
||||
assert "serv restarts" "$(texec cat "$1" | awk '{print $1;}')" -ge "$2"
|
||||
assert "serv restarts" "$(texec cat "$1" | awk '{print $1;}')" -ge "$2"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -9,25 +9,19 @@ TEST_DIR=$(dirname "$0")
|
||||
|
||||
test_setup()
|
||||
{
|
||||
say "Test start $(date)"
|
||||
run "mkdir -p /etc/default"
|
||||
export TEST_TIMEOUT=5
|
||||
say "Test start $(date)"
|
||||
run "mkdir -p /etc/default"
|
||||
export TEST_TIMEOUT=5
|
||||
}
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Test done $(date)"
|
||||
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
}
|
||||
|
||||
check_restarts()
|
||||
{
|
||||
assert "serv restarts" "$(texec cat "$1" | awk '{print $1;}')" -ge "$2"
|
||||
}
|
||||
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
. "$TEST_DIR/lib/setup.sh"
|
||||
|
||||
@@ -43,7 +37,7 @@ test_one()
|
||||
run "initctl reload"
|
||||
# run "initctl status fail.sh"
|
||||
|
||||
assert_restart_cnt "$num/10" fail.sh
|
||||
assert_restart_cnt "$num" "0/10" fail.sh
|
||||
}
|
||||
|
||||
sep
|
||||
|
||||
Executable
+59
@@ -0,0 +1,59 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Verifies that a run task can call initctl at bootstrap and runlevel 2,
|
||||
# without blocking, performing serveral tasks:
|
||||
#
|
||||
# 1. Query running services
|
||||
# 2. Stop/Start a running service
|
||||
# 3. Restart a service
|
||||
#
|
||||
|
||||
TEST_DIR=$(dirname "$0")
|
||||
#DEBUG=1
|
||||
|
||||
# shellcheck disable=SC2034
|
||||
BOOTSTRAP="run [S] /bin/ready.sh -- Ready steady go\n\
|
||||
run [S] name:one initctl -- Query status\n\
|
||||
service [S234] /sbin/service.sh -- Background service\n\
|
||||
run [2] name:two initctl stop service.sh -- Stopping service\n\
|
||||
run [3] name:three initctl start service.sh -- Starting service again\n\
|
||||
run [4] name:four initctl restart service.sh -- Restart service"
|
||||
# shellcheck disable=SC2034
|
||||
RCLOCAL="echo \"$0 ==============\" &1>2"
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
. "$TEST_DIR/lib/setup.sh"
|
||||
|
||||
test_setup()
|
||||
{
|
||||
say "Test start $(date)"
|
||||
}
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
}
|
||||
|
||||
say "$FINIT_CONF:"
|
||||
run "cat $FINIT_CONF"
|
||||
say "/etc/rc.local:"
|
||||
run "cat /etc/rc.local"
|
||||
|
||||
say "Waiting for runlevel 2"
|
||||
sleep 2
|
||||
assert_status "service.sh" "stopped"
|
||||
|
||||
say "Changing to runlevel 3"
|
||||
run "initctl runlevel 3"
|
||||
sleep 2
|
||||
assert_status "service.sh" "running"
|
||||
run "initctl"
|
||||
oldpid=$(texec initctl |awk '/service.sh/{print $1}')
|
||||
|
||||
say "Changing to runlevel 4"
|
||||
run "initctl runlevel 4"
|
||||
sleep 2
|
||||
assert_status "service.sh" "running"
|
||||
assert_pidiff "service.sh" "$oldpid"
|
||||
|
||||
run "initctl"
|
||||
+3
-3
@@ -9,12 +9,12 @@ FINIT_RUNLEVEL=9
|
||||
|
||||
test_setup()
|
||||
{
|
||||
say "Test start $(date)"
|
||||
say "Test start $(date)"
|
||||
}
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Test done $(date)"
|
||||
}
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
@@ -23,7 +23,7 @@ test_teardown()
|
||||
say 'Check runlevel'
|
||||
lvl=$(run "initctl runlevel | awk '{print \$2;}'")
|
||||
if [ "$lvl" -eq "9" ]; then
|
||||
return 0
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Verifies basic runparts behavior: to run all scripts in a directory at
|
||||
# the end of system bootstrap, right before calling /etc/rc.local:
|
||||
#
|
||||
# - only executable scripts should be called
|
||||
# - always in alphabetical order
|
||||
# - SNNfoo should be called with a 'start' argument
|
||||
# - KNNfoo should be called with a 'stop' argument
|
||||
#
|
||||
|
||||
TEST_DIR=$(dirname "$0")
|
||||
#DEBUG=1
|
||||
|
||||
# shellcheck disable=SC2034
|
||||
BOOTSTRAP="runparts /etc/rc.d"
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
. "$TEST_DIR/lib/setup.sh"
|
||||
|
||||
test_setup()
|
||||
{
|
||||
say "Test start $(date)"
|
||||
}
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
}
|
||||
|
||||
while true; do
|
||||
lvl=$(texec initctl runlevel)
|
||||
say "Current runlevel $lvl"
|
||||
if [ "$lvl" = "N 2" ]; then
|
||||
break;
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
texec diff -u /usr/share/runparts/ref.log /tmp/runparts.log
|
||||
texec cmp /usr/share/runparts/ref.log /tmp/runparts.log || fail "runparts in wrong order"
|
||||
@@ -13,11 +13,11 @@ FINITBIN="$(pwd)/$top_builddir/src/finit" DEST="$SYSROOT" make -f "$srcdir/lib/s
|
||||
|
||||
# Drop plugins we don't need in test, only causes confusing FAIL in logs.
|
||||
for plugin in tty.so urandom.so rtc.so modprobe.so hotplug.so; do
|
||||
find "$SYSROOT" -name $plugin -delete
|
||||
find "$SYSROOT" -name $plugin -delete
|
||||
done
|
||||
|
||||
# Drop system .conf files we don't need in test, same as above
|
||||
for conf in hotplug.conf; do
|
||||
find "$SYSROOT" -name $conf -delete
|
||||
find "$SYSROOT" -name $conf -delete
|
||||
done
|
||||
|
||||
|
||||
@@ -7,10 +7,10 @@ TEST_DIR=$(dirname "$0")
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Test done $(date)"
|
||||
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
}
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
|
||||
+32
-31
@@ -2,50 +2,51 @@
|
||||
|
||||
nm=$1
|
||||
|
||||
# shellcheck disable=SC2046
|
||||
getpid()
|
||||
{
|
||||
initctl status "$1" |awk '/PID :/{ print $3; }'
|
||||
initctl status "$1" |awk '/PID :/{ print $3; }'
|
||||
}
|
||||
|
||||
pid=$(getpid "$nm")
|
||||
if [ -f oldpid ]; then
|
||||
oldpid=$(cat oldpid)
|
||||
oldpid=$(cat oldpid)
|
||||
if [ "$oldpid" = "$pid" ]; then
|
||||
echo "Looks bad, wait for it ..."
|
||||
sleep 3
|
||||
pid=$(getpid "$nm")
|
||||
if [ "$oldpid" = "$pid" ]; then
|
||||
echo "Looks bad, wait for it ..."
|
||||
sleep 3
|
||||
pid=$(getpid "$nm")
|
||||
if [ "$oldpid" = "$pid" ]; then
|
||||
echo "Finit did not deregister old PID $oldpid vs $pid"
|
||||
initctl status "$nm"
|
||||
ps
|
||||
echo "Reloading finit ..."
|
||||
initctl reload
|
||||
sleep 1
|
||||
initctl status "$nm"
|
||||
exit 1
|
||||
fi
|
||||
echo "Finit did not deregister old PID $oldpid vs $pid"
|
||||
initctl status "$nm"
|
||||
ps
|
||||
echo "Reloading finit ..."
|
||||
initctl reload
|
||||
sleep 1
|
||||
initctl status "$nm"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
timeout=50
|
||||
while [ "$pid" -le 1 ]; do
|
||||
sleep 0.1
|
||||
pid=$(getpid "$nm")
|
||||
if [ "$pid" -le 1 ]; then
|
||||
timeout=$((timeout - 1))
|
||||
if [ "$timeout" -gt 0 ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
echo "Got a bad PID: $pid, aborting ..."
|
||||
ps
|
||||
sleep 1
|
||||
initctl status "$nm"
|
||||
ps
|
||||
exit 1
|
||||
sleep 0.1
|
||||
pid=$(getpid "$nm")
|
||||
if [ "$pid" -le 1 ]; then
|
||||
timeout=$((timeout - 1))
|
||||
if [ "$timeout" -gt 0 ]; then
|
||||
continue
|
||||
fi
|
||||
break
|
||||
|
||||
if [ $pid -ne 0 ]; then
|
||||
echo "Got a bad PID: $pid, aborting ..."
|
||||
ps
|
||||
sleep 1
|
||||
initctl status "$nm"
|
||||
ps
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
break
|
||||
done
|
||||
|
||||
echo "$pid" > /tmp/oldpid
|
||||
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "$0 $*" >> /tmp/runparts.log
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
S01abc.sh
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "$0" >> /tmp/runparts.log
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "$0" >> /tmp/runparts.log
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "$0 $*" >> /tmp/sysv.log
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
S01abc.sh
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "$0" >> /tmp/sysv.log
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "$0" >> /tmp/sysv.log
|
||||
@@ -0,0 +1,4 @@
|
||||
/etc/rc.d/S01abc.sh start
|
||||
/etc/rc.d/S02def.sh start
|
||||
/etc/rc.d/foo.sh
|
||||
/etc/rc.d/test.sh
|
||||
@@ -0,0 +1,2 @@
|
||||
/etc/rcS.d/S01abc.sh start
|
||||
/etc/rcS.d/S02def.sh start
|
||||
+13
-13
@@ -21,7 +21,7 @@
|
||||
|
||||
#define err(rc, fmt, args...) do {fprintf(stderr, "%s: " fmt ": %s\n", ident, ##args, strerror(errno)); exit(rc);} while(0)
|
||||
#define errx(rc, fmt, args...) do {fprintf(stderr, "%s: " fmt "\n", ident, ##args); exit(rc);} while(0)
|
||||
#define log(fmt, args...) do {fprintf(stderr, "%s: " fmt "\n", ident, ##args);} while(0)
|
||||
#define inf(fmt, args...) do {fprintf(stderr, "%s: " fmt "\n", ident, ##args);} while(0)
|
||||
|
||||
volatile sig_atomic_t reloading = 1;
|
||||
volatile sig_atomic_t running = 1;
|
||||
@@ -89,7 +89,7 @@ static void cleanup(void)
|
||||
|
||||
static void sig(int signo)
|
||||
{
|
||||
log("Got signal %d ...", signo);
|
||||
inf("Got signal %d ...", signo);
|
||||
|
||||
switch (signo) {
|
||||
case SIGHUP:
|
||||
@@ -120,7 +120,7 @@ static int checkfn(char *fn)
|
||||
|
||||
static void mine(char *fn)
|
||||
{
|
||||
log("Mining for spice in %s", fn);
|
||||
inf("Mining for spice in %s", fn);
|
||||
writefn(fn, 4711);
|
||||
}
|
||||
|
||||
@@ -136,11 +136,11 @@ static void pidfile(char *pidfn)
|
||||
pid_t pid;
|
||||
|
||||
pid = getpid();
|
||||
log("Creating PID file %s with %d", pidfn, pid);
|
||||
inf("Creating PID file %s with %d", pidfn, pid);
|
||||
writefn(pidfn, pid);
|
||||
atexit(cleanup);
|
||||
} else {
|
||||
log("Touching PID file %s", pidfn);
|
||||
inf("Touching PID file %s", pidfn);
|
||||
utimensat(0, fn, NULL, 0);
|
||||
}
|
||||
}
|
||||
@@ -265,27 +265,27 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
if (do_crash) {
|
||||
log("Simulating crash, exiting with code %d", EX_SOFTWARE);
|
||||
inf("Simulating crash, exiting with code %d", EX_SOFTWARE);
|
||||
exit(EX_SOFTWARE);
|
||||
}
|
||||
|
||||
log("Entering while(1) loop");
|
||||
inf("Entering while(1) loop");
|
||||
while (running) {
|
||||
if (spice) {
|
||||
log("Checking for spice in %s ...", spice);
|
||||
inf("Checking for spice in %s ...", spice);
|
||||
if (!checkfn(spice))
|
||||
err(1, "Melange");
|
||||
}
|
||||
|
||||
if (reloading) {
|
||||
if (do_notify > 0) {
|
||||
log("Delaying notify by 3 seconds for notify.sh ...");
|
||||
inf("Delaying notify by 3 seconds for notify.sh ...");
|
||||
sleep(3);
|
||||
log("Notifying Finit on socket %d, READY=1", do_notify);
|
||||
inf("Notifying Finit on socket %d, READY=1", do_notify);
|
||||
if (write(do_notify, "READY=1\n", 8) == -1)
|
||||
err(1, "Failed sending ready notification to Finit");
|
||||
if (notify_s6) {
|
||||
log("s6 notify, closing socket %d ...", do_notify);
|
||||
inf("s6 notify, closing socket %d ...", do_notify);
|
||||
close(do_notify);
|
||||
do_notify = 0;
|
||||
}
|
||||
@@ -305,12 +305,12 @@ int main(int argc, char *argv[])
|
||||
|
||||
if (melange && vanish++ > 0) {
|
||||
if (checkfn(melange)) {
|
||||
log("Oh no, sandworms! Harvest interrupted ...");
|
||||
inf("Oh no, sandworms! Harvest interrupted ...");
|
||||
remove(melange);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log("Leaving ...");
|
||||
inf("Leaving ...");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -8,10 +8,10 @@ TEST_DIR=$(dirname "$0")
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Test done $(date)"
|
||||
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
}
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
@@ -35,9 +35,9 @@ say 'Simulate service crash (kill -9 ..)'
|
||||
i=0
|
||||
laps=1000
|
||||
while [ $i -lt $laps ]; do
|
||||
i=$((i + 1))
|
||||
say "Lap $i/$laps, killing service ..." # we have this, no sleep needed
|
||||
run "slay service.sh"
|
||||
i=$((i + 1))
|
||||
say "Lap $i/$laps, killing service ..." # we have this, no sleep needed
|
||||
run "slay service.sh"
|
||||
done
|
||||
|
||||
retry 'assert_new_pid service.sh /run/service.pid'
|
||||
|
||||
+27
-27
@@ -5,51 +5,51 @@ TEST_DIR=$(dirname "$0")
|
||||
|
||||
test_setup()
|
||||
{
|
||||
say "Test start $(date)"
|
||||
say "Test start $(date)"
|
||||
}
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Test done $(date)"
|
||||
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
}
|
||||
|
||||
test_one()
|
||||
{
|
||||
pidfn=$1
|
||||
service=$2
|
||||
pidfn=$1
|
||||
service=$2
|
||||
|
||||
say "Add service stanza '$service' to $FINIT_CONF ..."
|
||||
run "echo '$service' > $FINIT_CONF"
|
||||
say "Add service stanza '$service' to $FINIT_CONF ..."
|
||||
run "echo '$service' > $FINIT_CONF"
|
||||
|
||||
say 'Reload Finit'
|
||||
#run "initctl debug"
|
||||
run "initctl reload"
|
||||
#run "initctl status"
|
||||
#run "ps"
|
||||
say 'Reload Finit'
|
||||
#run "initctl debug"
|
||||
run "initctl reload"
|
||||
#run "initctl status"
|
||||
#run "ps"
|
||||
|
||||
#run "initctl status"
|
||||
#run "ps"
|
||||
#run "initctl status serv"
|
||||
#run "initctl status"
|
||||
#run "ps"
|
||||
#run "initctl status serv"
|
||||
|
||||
retry 'assert_num_children 1 serv'
|
||||
retry "assert_has_pidfile $pidfn" 1
|
||||
retry 'assert_num_children 1 serv'
|
||||
retry "assert_has_pidfile $pidfn" 1
|
||||
|
||||
say 'Stop the service'
|
||||
run "initctl stop serv"
|
||||
say 'Stop the service'
|
||||
run "initctl stop serv"
|
||||
|
||||
retry 'assert_num_children 0 serv'
|
||||
retry 'assert_num_children 0 serv'
|
||||
|
||||
say 'Start the service again'
|
||||
run "initctl start serv"
|
||||
say 'Start the service again'
|
||||
run "initctl start serv"
|
||||
|
||||
retry 'assert_num_children 1 serv'
|
||||
retry 'assert_num_children 1 serv'
|
||||
|
||||
say "Done, drop service from $FINIT_CONF ..."
|
||||
run "rm $FINIT_CONF"
|
||||
run "initctl reload"
|
||||
say "Done, drop service from $FINIT_CONF ..."
|
||||
run "rm $FINIT_CONF"
|
||||
run "initctl reload"
|
||||
}
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
|
||||
@@ -6,10 +6,10 @@ TEST_DIR=$(dirname "$0")
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Test done $(date)"
|
||||
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_RCSD/service.conf"
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_RCSD/service.conf"
|
||||
}
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
|
||||
@@ -6,10 +6,10 @@ TEST_DIR=$(dirname "$0")
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Test done $(date)"
|
||||
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
}
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
|
||||
@@ -6,10 +6,10 @@ TEST_DIR=$(dirname "$0")
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Test done $(date)"
|
||||
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
say "Running test teardown."
|
||||
run "rm -f $FINIT_CONF"
|
||||
}
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Verifies SysV runparts behavior: to run all scripts in a directory at
|
||||
# the end of system bootstrap, right before calling /etc/rc.local:
|
||||
#
|
||||
# - only SNNfoo or KNNfoo executable scripts should be called
|
||||
# - always in alphabetical order
|
||||
# - SNNfoo should be called with a 'start' argument
|
||||
# - KNNfoo should be called with a 'stop' argument
|
||||
#
|
||||
|
||||
TEST_DIR=$(dirname "$0")
|
||||
#DEBUG=1
|
||||
|
||||
# shellcheck disable=SC2034
|
||||
BOOTSTRAP="runparts sysv /etc/rcS.d"
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
. "$TEST_DIR/lib/setup.sh"
|
||||
|
||||
test_setup()
|
||||
{
|
||||
say "Test start $(date)"
|
||||
}
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
}
|
||||
|
||||
while true; do
|
||||
lvl=$(texec initctl runlevel)
|
||||
say "Current runlevel $lvl"
|
||||
if [ "$lvl" = "N 2" ]; then
|
||||
break;
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
texec cat /tmp/sysv.log
|
||||
texec diff -u /usr/share/runparts/sysv.log /tmp/sysv.log
|
||||
texec cmp /usr/share/runparts/sysv.log /tmp/sysv.log || fail "runparts sysv in wrong order"
|
||||
Reference in New Issue
Block a user