mirror of
https://github.com/troglobit/finit.git
synced 2026-10-12 10:12:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5d8fcfdf13 | ||
|
|
e4830c5614 | ||
|
|
f33261af6b | ||
|
|
e7516f2b63 | ||
|
|
d18167fe1d | ||
|
|
7d3f95c0a9 | ||
|
|
86c5bbb03d | ||
|
|
7530bb74f6 | ||
|
|
54dd726d16 | ||
|
|
bd9bb92ca0 | ||
|
|
01cb088e51 | ||
|
|
3d91112e0d | ||
|
|
16aef80682 | ||
|
|
fd34914936 | ||
|
|
21a890a04e | ||
|
|
7f5f7e8ef6 | ||
|
|
ff937576ea | ||
|
|
7d831170ae | ||
|
|
6a21ac55ad | ||
|
|
a0820c7f20 | ||
|
|
6d58c9ed0b | ||
|
|
bc2ffbc767 | ||
|
|
4c1fc2410e | ||
|
|
70e1aa889a | ||
|
|
c8c5e4e88a | ||
|
|
86c1398778 | ||
|
|
b37fa2b417 | ||
|
|
a91e197553 | ||
|
|
5adb92ca1b | ||
|
|
cfc99c4e8b | ||
|
|
3e51ed1c55 | ||
|
|
b5df0a6274 | ||
|
|
cbe8d56042 | ||
|
|
a3ec792b44 | ||
|
|
c24855d4d5 | ||
|
|
014e457fda | ||
|
|
21d89c7e24 | ||
|
|
639fb76f5a | ||
|
|
30c189b116 | ||
|
|
e2a8803f7a | ||
|
|
209e140ddd | ||
|
|
2e3fa72924 | ||
|
|
1502838a0d | ||
|
|
377c8bce8c | ||
|
|
a39d958d25 | ||
|
|
7f8a96a73e | ||
|
|
5c2577214d | ||
|
|
f03206a694 | ||
|
|
f0e328edc9 | ||
|
|
13342f2bd9 | ||
|
|
c926160853 | ||
|
|
462d5b22b4 | ||
|
|
b1bfab08f3 | ||
|
|
aeb48ef04b | ||
|
|
b8b200ad75 | ||
|
|
c148d8d783 | ||
|
|
27ba3b27f5 | ||
|
|
b4af86255d | ||
|
|
01a007b388 | ||
|
|
0e28741dcb | ||
|
|
c993feeb44 | ||
|
|
ec17f0aa23 | ||
|
|
6baf2990e8 | ||
|
|
6416e2a1a4 | ||
|
|
7c42986800 | ||
|
|
6f802a7ff1 | ||
|
|
879721839e | ||
|
|
20290a4166 | ||
|
|
ba77e4f217 | ||
|
|
e7b18feca5 | ||
|
|
4a90a3e8ef | ||
|
|
6d14ff84d3 | ||
|
|
89cc6017df | ||
|
|
f6fafdbd23 | ||
|
|
3480e42687 | ||
|
|
053c1643a7 | ||
|
|
2018cac050 | ||
|
|
f9090f535d | ||
|
|
10577f3e48 | ||
|
|
07f7caef0d | ||
|
|
093b3ba467 | ||
|
|
c63279630b | ||
|
|
4755e5206b | ||
|
|
2002157032 | ||
|
|
094e00d405 | ||
|
|
e01836c506 | ||
|
|
685f332c6e | ||
|
|
ae09272bcc | ||
|
|
d16f7e0c88 | ||
|
|
063d645d95 | ||
|
|
f87e9d8880 | ||
|
|
e8099f1bfa | ||
|
|
7dc7f9a968 | ||
|
|
996ab8c6c6 | ||
|
|
16c2198304 | ||
|
|
ecca01dea0 | ||
|
|
bda3cdd3ad | ||
|
|
4811f76294 | ||
|
|
0aba704312 | ||
|
|
57329832d0 | ||
|
|
078a1d0c95 | ||
|
|
0e695aa0c7 | ||
|
|
f7a1514131 | ||
|
|
11bc87ecc3 | ||
|
|
e1c59a2515 | ||
|
|
2faefd44a2 | ||
|
|
6fa3aa41df | ||
|
|
ef9e9ec786 | ||
|
|
d77e3a6113 | ||
|
|
0b1258b44c | ||
|
|
62dad82ba8 | ||
|
|
5423b5b0a2 | ||
|
|
6b10174bcb | ||
|
|
ec94f4d321 | ||
|
|
69800537f2 | ||
|
|
61faedb0b5 | ||
|
|
61014431aa | ||
|
|
49bd63994c | ||
|
|
85b29d9407 | ||
|
|
b83fdea49b | ||
|
|
beec0ee590 | ||
|
|
4121113688 | ||
|
|
62da379472 | ||
|
|
3c9053b055 | ||
|
|
71b07ce2bd | ||
|
|
ebea3d273e | ||
|
|
f3a76b8a63 | ||
|
|
ba93791077 | ||
|
|
b994858907 | ||
|
|
74ad34a0c5 | ||
|
|
1b5b37c06b | ||
|
|
c8e1bd0e9a | ||
|
|
e9c8d3d740 | ||
|
|
f567b866a0 | ||
|
|
3471d3ee2d | ||
|
|
6e197f5751 | ||
|
|
b568c18346 | ||
|
|
1b29876ba8 | ||
|
|
4c6f3d2d69 | ||
|
|
8d3f7eded2 | ||
|
|
0222feeda1 | ||
|
|
f10cf1a9a0 | ||
|
|
85b2089fd3 | ||
|
|
885808c64c | ||
|
|
78069b42e7 | ||
|
|
3e0063e874 | ||
|
|
6ec1ab3d4f | ||
|
|
33b4540ad9 | ||
|
|
a434b51653 | ||
|
|
222d8d3575 | ||
|
|
8e2d006048 | ||
|
|
fd9f204b6d | ||
|
|
f0f358a138 | ||
|
|
cfffcd4513 | ||
|
|
e51587c66e | ||
|
|
f930953e6a | ||
|
|
ebdc10d1c5 | ||
|
|
d12370568f | ||
|
|
176125deca | ||
|
|
cb934ca39f | ||
|
|
4fd95fdcbe | ||
|
|
cb62349054 | ||
|
|
1b72119673 | ||
|
|
add474e825 |
@@ -15,7 +15,7 @@ jobs:
|
||||
build:
|
||||
# Verify we can build on latest Ubuntu with both gcc and clang
|
||||
name: ${{ matrix.compiler }}
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-18.04
|
||||
strategy:
|
||||
matrix:
|
||||
compiler: [gcc, clang]
|
||||
@@ -60,7 +60,9 @@ jobs:
|
||||
/tmp/sbin/initctl -h
|
||||
- name: Run Unit Tests
|
||||
run: |
|
||||
make -j1 distcheck
|
||||
ver=$(/tmp/sbin/initctl -V | awk '/Finit.*/ {print $2;}')
|
||||
dir=finit-$ver/_build/sub
|
||||
make -j1 distcheck || (cat $dir/test/setup-root.log; cat $dir/test/test-suite.log; false)
|
||||
- name: Upload Test Results
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
|
||||
@@ -3,7 +3,7 @@ name: Release General
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '[0-9]+.[0-9]+'
|
||||
- '[0-9]+.[0-9]+*'
|
||||
|
||||
jobs:
|
||||
release:
|
||||
|
||||
@@ -45,3 +45,6 @@ GTAGS
|
||||
/.autoconf
|
||||
/.automake
|
||||
/.built
|
||||
|
||||
# VS Code user settings
|
||||
.vscode
|
||||
|
||||
+64
-2
@@ -4,6 +4,67 @@ Change Log
|
||||
All relevant changes are documented in this file.
|
||||
|
||||
|
||||
[4.3][UNRELEASED]
|
||||
--------------------
|
||||
|
||||
Critical bug fix release. If you run a 32-bit target with GLIBC 2.34
|
||||
you *need* to upgrade!
|
||||
|
||||
> **Note:** system verbosity on console at start and shutdown has been
|
||||
> increased. Now the output of all commands is logged to the
|
||||
> system logger, for early services `/dev/kmsg` is used.
|
||||
>
|
||||
> **Also:** please notice the updated support for enabling and disabling
|
||||
> kernel and Finit debug messages on the system console. Very
|
||||
> useful when debugging either of them, e.g., a kernel module.
|
||||
> For details, see [cmdline.md](doc/cmdline.md).
|
||||
|
||||
### Changes
|
||||
* Loading `module`s no longer shows arguments in progress output
|
||||
* Warning messages in progress output now in yellow, not red, issue #214
|
||||
* `initctl`, new command line option `-v,--version` for ease of use
|
||||
* Extended environment variables for pre/post scripts, issue #189
|
||||
* New condition `done` for run task, issue #207 by Ming Liu, Atlas Copco
|
||||
* Refactor parts of shutdown and reboot sequence for PREEMPT-RT kernels,
|
||||
by Robert Andersson, Mathias Thore, and Ming Liu, Atlas Copco
|
||||
* Conditions for run/task/sysv status, e.g. `run/foo/success` and
|
||||
`task/bar/failure`. Issue #232, by Ming Liu, Atlas Copco
|
||||
* initctl support for sending signals to services, by Jörgen
|
||||
Sigvardsson, issue #225
|
||||
* `[WARN]` messages on console now printed in yellow, issue #214
|
||||
* Network services now also stopped when going to runlevel 6 (reboot),
|
||||
not just runlevel 0 (shutdown) or 1 (single-user)
|
||||
* When `ifup` is missing on the system, bring at least `lo` up at boot
|
||||
* Log output from `ifup -a` (and `ifdown -a`), to syslog
|
||||
* Avoid blocking PID 1 when starting SysV init scripts
|
||||
* Allow custom `pid:` for SysV init scripts
|
||||
* Document supported types of forking/non-forking services
|
||||
* Auto-detect running in some common forms of containers
|
||||
* Simplify shutdown/reboot when running in a container
|
||||
* Log to `stderr` when running in a container w/o syslog daemon
|
||||
* Add support for `type:forking` to services, already supported but
|
||||
with a very difficult `pid:` syntax. Documentation updated
|
||||
|
||||
### Fixes
|
||||
* Fix nasty 32/64-bit alignment issue between finit and its plugins,
|
||||
applicable to 32-bit targets with GLIBC 2.34 and later. External
|
||||
plugins must make sure to use, at least: `-D_TIME_BITS=64`
|
||||
* Fix #215: disable cgroup support at runtime if kernel lacks support
|
||||
or does not have the required controllers (cpu)
|
||||
* Fix #217: iwatcher initialization issue, by Ming Liu, Atlas Copco
|
||||
* Fix #218: initctl matches too many services, by Ming Liu, Atlas Copco
|
||||
* Fix #219: not all filesystems unmounted at shutdown, by Ming Liu,
|
||||
Mathias Thore, and Robert Andersson, Atlas Copco
|
||||
* Fix #226: initctl shows wrong PID for crashing services
|
||||
* Fix #227: reboot stalls if process stopped with `[WARN]`
|
||||
* Fix #233: initctl shows wrong status for run/task, by Sergio Morlans
|
||||
and Ming Liu, Atlas Copco
|
||||
* Fix start/stop of SysV init scripts
|
||||
* Fix call to `swapoff` at shutdown, does not support `-e` flag
|
||||
* Fix suspend to RAM issue. Previously `reboot(RB_SW_SUSPEND)` was
|
||||
used, now the modern `/sys/power/state` API is used instead.
|
||||
|
||||
|
||||
[4.2][] - 2022-01-16
|
||||
--------------------
|
||||
|
||||
@@ -756,7 +817,7 @@ The inetd release.
|
||||
### Changes
|
||||
* Add support for built-in inetd super server -- launch services on
|
||||
demand. Supports filtering per interface and custom Inet ports.
|
||||
* Upgrade to [libuEv] v1.1.0 to better handle error conditions.
|
||||
* Upgrade to [libuEv][] v1.1.0 to better handle error conditions.
|
||||
* Allow mixed case config directives in `finit.conf`
|
||||
* Add support for RFC 868 (rdate) time plugin, start as inetd service.
|
||||
* Load plugins before parsing `finit.conf`, this makes it possible to
|
||||
@@ -787,7 +848,7 @@ The inetd release.
|
||||
[1.11][] - 2015-01-24 [YANKED]
|
||||
------------------------------
|
||||
|
||||
The [libuEv] release.
|
||||
The [libuEv][] release.
|
||||
|
||||
**Note:** This release has been *yanked* from distribution due to a
|
||||
regression in launching background processes and TTY's. Fixed in
|
||||
@@ -1039,6 +1100,7 @@ Major bug fix release.
|
||||
* Initial release
|
||||
|
||||
[UNRELEASED]: https://github.com/troglobit/finit/compare/4.2...HEAD
|
||||
[4.3]: https://github.com/troglobit/finit/compare/4.2...4.3
|
||||
[4.2]: https://github.com/troglobit/finit/compare/4.1...4.2
|
||||
[4.1]: https://github.com/troglobit/finit/compare/4.0...4.1
|
||||
[4.0]: https://github.com/troglobit/finit/compare/3.1...4.0
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[![License Badge][]][License] [![GitHub Status]][GitHub] [![Coverity Status]][Coverity Scan]
|
||||
[![License Badge][]][License] [![GitHub Status][]][GitHub] [![Coverity Status][]][Coverity Scan]
|
||||
<img align="right" src="img/finit3.png" alt="Finit: Fast Init">
|
||||
|
||||
* [Introduction](#introduction)
|
||||
@@ -54,6 +54,11 @@ on server and desktop systems as well. For working examples, see the
|
||||
* [Alpine Linux](contrib/alpine/), and
|
||||
* [Debian GNU/Linux](contrib/debian/)
|
||||
|
||||
> **Note:** support for various Linux distributions does not mean Finit
|
||||
> installs easily on all architectures. The bundled install scripts are
|
||||
> examples for standard installations, tested on x86_64 systems. Custom
|
||||
> setups, targeted at embedded systems, can be found in [myLinux][].
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
@@ -598,7 +603,8 @@ and proposed extensions.
|
||||
[Joachim Wiberg]: https://troglobit.com
|
||||
[License]: https://en.wikipedia.org/wiki/MIT_License
|
||||
[License Badge]: https://img.shields.io/badge/License-MIT-teal.svg
|
||||
[GitHub]: https://travis-ci.org/troglobit/finit
|
||||
[GitHub Status]: https://travis-ci.org/troglobit/finit.svg?branch=master
|
||||
[GitHub]: https://github.com/troglobit/myLinux/
|
||||
[GitHub]: https://github.com/troglobit/finit/actions/workflows/build.yml/
|
||||
[GitHub Status]: https://github.com/troglobit/finit/actions/workflows/build.yml/badge.svg
|
||||
[Coverity Scan]: https://scan.coverity.com/projects/3545
|
||||
[Coverity Status]: https://scan.coverity.com/projects/3545/badge.svg
|
||||
|
||||
+5
-3
@@ -1,4 +1,4 @@
|
||||
AC_INIT(Finit, 4.2, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/finit.html)
|
||||
AC_INIT(Finit, 4.3-rc1, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/finit.html)
|
||||
AC_CONFIG_AUX_DIR(aux)
|
||||
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
|
||||
AM_SILENT_RULES([yes])
|
||||
@@ -14,8 +14,8 @@ AC_CONFIG_FILES([Makefile
|
||||
man/Makefile
|
||||
plugins/Makefile
|
||||
src/Makefile
|
||||
test/test.env
|
||||
test/Makefile])
|
||||
test/test.env test/Makefile
|
||||
test/tenv/Makefile test/common/Makefile])
|
||||
|
||||
# Older versions of autoconf (<2.58) do not have AC_CONFIG_MACRO_DIR()
|
||||
#m4_include([m4/plugin.m4])
|
||||
@@ -86,11 +86,13 @@ enable_all_plugins=auto
|
||||
AC_PLUGIN([alsa-utils], [no], [Save and restore ALSA sound settings using alsactl])
|
||||
AC_PLUGIN([dbus], [no], [Setup and start system message bus, D-Bus])
|
||||
AC_PLUGIN([modules-load], [no], [Scans /etc/modules-load.d for modules to load])
|
||||
AC_PLUGIN([modprobe], [yes], [Coldplug modules using modalias magic])
|
||||
AC_PLUGIN([resolvconf], [no], [Setup necessary files for resolvconf])
|
||||
AC_PLUGIN([x11-common], [no], [Console setup (for X)])
|
||||
AC_PLUGIN([netlink], [yes], [Basic netlink plugin for IFUP/IFDN and GW events. Can be replaced with externally built plugin that links with libnl or similar.])
|
||||
AC_PLUGIN([hotplug], [yes], [Setup and start udev or mdev hotplug daemon])
|
||||
AC_PLUGIN([rtc], [yes], [Save and restore RTC using hwclock])
|
||||
AC_PLUGIN([tty], [yes], [Automatically activate new TTYs, e.g. USB-to-serial])
|
||||
AC_PLUGIN([urandom], [yes], [Setup and save random seed at boot/shutdown])
|
||||
|
||||
# Check for extra arguments or packages
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
In Finit issue #196 we were reminded [1] of a missing inotify flag in
|
||||
Linux older kernels, IN_MASK_CREATE. Finit makes use of this internally
|
||||
for monitoring PID conditions, and more. This is a central mechanism to
|
||||
synchronize services at boot and reload at runtime.
|
||||
|
||||
The following patch for Linux 4.9.0, was provided by Andy Savage for
|
||||
other people that may want to run Finit on slightly older kernels.
|
||||
|
||||
[1]: https://github.com/troglobit/finit/issues/196
|
||||
|
||||
Index: fs/notify/inotify/inotify_user.c
|
||||
===================================================================
|
||||
--- fs.orig/notify/inotify/inotify_user.c
|
||||
+++ fs/notify/inotify/inotify_user.c
|
||||
@@ -522,6 +522,7 @@ static int inotify_update_existing_watch
|
||||
__u32 old_mask, new_mask;
|
||||
__u32 mask;
|
||||
int add = (arg & IN_MASK_ADD);
|
||||
+ int create = (arg & IN_MASK_CREATE);
|
||||
int ret;
|
||||
|
||||
mask = inotify_arg_to_mask(arg);
|
||||
@@ -529,6 +530,8 @@ static int inotify_update_existing_watch
|
||||
fsn_mark = fsnotify_find_inode_mark(group, inode);
|
||||
if (!fsn_mark)
|
||||
return -ENOENT;
|
||||
+ else if (create)
|
||||
+ return -EEXIST;
|
||||
|
||||
i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);
|
||||
|
||||
@@ -726,6 +729,10 @@ SYSCALL_DEFINE3(inotify_add_watch, int,
|
||||
if (unlikely(!f.file))
|
||||
return -EBADF;
|
||||
|
||||
+ /* IN_MASK_ADD and IN_MASK_CREATE don't make sense together */
|
||||
+ if (unlikely((mask & IN_MASK_ADD) && (mask & IN_MASK_CREATE)))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
/* verify that this is indeed an inotify instance */
|
||||
if (unlikely(f.file->f_op != &inotify_fops)) {
|
||||
ret = -EINVAL;
|
||||
@@ -814,7 +821,7 @@ static int __init inotify_user_setup(voi
|
||||
BUILD_BUG_ON(IN_ISDIR != FS_ISDIR);
|
||||
BUILD_BUG_ON(IN_ONESHOT != FS_IN_ONESHOT);
|
||||
|
||||
- BUG_ON(hweight32(ALL_INOTIFY_BITS) != 21);
|
||||
+ BUG_ON(hweight32(ALL_INOTIFY_BITS) != 22);
|
||||
|
||||
inotify_inode_mark_cachep = KMEM_CACHE(inotify_inode_mark, SLAB_PANIC);
|
||||
|
||||
Index: include/linux/inotify.h
|
||||
===================================================================
|
||||
--- include.orig/linux/inotify.h
|
||||
+++ include/linux/inotify.h
|
||||
@@ -17,6 +17,6 @@ extern struct ctl_table inotify_table[];
|
||||
IN_DELETE_SELF | IN_MOVE_SELF | IN_UNMOUNT | \
|
||||
IN_Q_OVERFLOW | IN_IGNORED | IN_ONLYDIR | \
|
||||
IN_DONT_FOLLOW | IN_EXCL_UNLINK | IN_MASK_ADD | \
|
||||
- IN_ISDIR | IN_ONESHOT)
|
||||
+ IN_MASK_CREATE | IN_ISDIR | IN_ONESHOT)
|
||||
|
||||
#endif /* _LINUX_INOTIFY_H */
|
||||
Index: include/uapi/linux/inotify.h
|
||||
===================================================================
|
||||
--- include.orig/uapi/linux/inotify.h
|
||||
+++ include/uapi/linux/inotify.h
|
||||
@@ -52,6 +52,7 @@ struct inotify_event {
|
||||
#define IN_ONLYDIR 0x01000000 /* only watch the path if it is a directory */
|
||||
#define IN_DONT_FOLLOW 0x02000000 /* don't follow a sym link */
|
||||
#define IN_EXCL_UNLINK 0x04000000 /* exclude events on unlinked objects */
|
||||
+#define IN_MASK_CREATE 0x10000000 /* only create watches */
|
||||
#define IN_MASK_ADD 0x20000000 /* add to the mask of an already existing watch */
|
||||
#define IN_ISDIR 0x40000000 /* event occurred against dir */
|
||||
#define IN_ONESHOT 0x80000000 /* only send event once */
|
||||
+19
-10
@@ -29,8 +29,8 @@ optional plugins to enable. It depends on two external libraries:
|
||||
The configure script checks for all dependencies, including the correct
|
||||
version of the above mentioned libraries. Currently required versions:
|
||||
|
||||
- libite v2.2.0
|
||||
- libuEv v2.2.0
|
||||
- libite v2.2.0, or later
|
||||
- libuEv v2.2.0, or later
|
||||
|
||||
|
||||
Configure
|
||||
@@ -54,7 +54,7 @@ Below are a few of the main switches to configure:
|
||||
will be linked statically.
|
||||
|
||||
* `--enable-kernel-cmdline`: Enable Finit pre-4.1 parsing of init args from
|
||||
`/proc/cmdline`, this is not recommended since Finit may be running as the
|
||||
`/proc/cmdline`, this is *not recommended* since Finit may be running as the
|
||||
init for container apps that can see the host's `/proc` filesystem
|
||||
|
||||
* `--enable-alsa-utils-plugin`: Enable the optional `alsa-utils.so` sound plugin.
|
||||
@@ -67,6 +67,13 @@ Below are a few of the main switches to configure:
|
||||
|
||||
For more configure flags, see <kbd>./configure --help</kbd>
|
||||
|
||||
> **Note:** the configure script is not available in the GIT sources. It is
|
||||
> however included in (officially supported) released tarballs. The
|
||||
> idea is that you should not need GNU autotools to build, only the
|
||||
> above mentioned dependencies, a POSIX shell, a C compiler and make.
|
||||
> Any contributing to Finit can generate it from `configure.ac` using
|
||||
> the `autogen.sh` script.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
@@ -74,8 +81,8 @@ Example
|
||||
First, unpack the archive:
|
||||
|
||||
```shell
|
||||
$ tar xf finit-4.1.tar.gz
|
||||
$ cd finit-4.1/
|
||||
$ tar xf finit-4.3.tar.gz
|
||||
$ cd finit-4.3/
|
||||
```
|
||||
|
||||
Then configure, build and install:
|
||||
@@ -83,7 +90,7 @@ Then configure, build and install:
|
||||
```shell
|
||||
$ ./configure --prefix=/usr --exec-prefix= \
|
||||
--sysconfdir=/etc --localstatedir=/var \
|
||||
--with-keventd --with-watchdog
|
||||
--with-keventd --with-watchdog
|
||||
$ make
|
||||
.
|
||||
.
|
||||
@@ -91,7 +98,7 @@ $ make
|
||||
$ DESTDIR=/tmp/finit make install
|
||||
```
|
||||
|
||||
In this example the [finit-4.1.tar.gz][1] archive is unpacked to the
|
||||
In this example the [finit-4.3.tar.gz][1] archive is unpacked to the
|
||||
user's home directory, configured, built and installed to a temporary
|
||||
staging directory. The environment variable `DESTDIR` controls the
|
||||
destination directory when installing, very useful for building binary
|
||||
@@ -151,12 +158,14 @@ Debugging
|
||||
---------
|
||||
|
||||
Edit, or append to, the kernel command line: remove `quiet` to enable
|
||||
kernel messages and add `debug` to enable Finit debug messages.
|
||||
kernel messages and add `finit.debug` to enable Finit debug messages.
|
||||
|
||||
```shell
|
||||
append="init=/sbin/finit debug"
|
||||
append="init=/sbin/finit -- finit.debug"
|
||||
```
|
||||
|
||||
Notice the `--` separator.
|
||||
|
||||
To debug startup issues, in particular issues with getty/login, add
|
||||
the following to your Finit .conf file:
|
||||
|
||||
@@ -175,6 +184,6 @@ it only for debugging start up issues when Finit crashes.
|
||||
systems since they can potentially give a user root access.
|
||||
|
||||
|
||||
[1]: ftp://troglobit.com/finit/finit-4.1.tar.gz
|
||||
[1]: ftp://troglobit.com/finit/finit-4.3.tar.gz
|
||||
[libuEv]: https://github.com/troglobit/libuev
|
||||
[libite]: https://github.com/troglobit/libite
|
||||
|
||||
+13
-6
@@ -10,13 +10,13 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
|
||||
> parameters to init. E.g., `init=/sbin/finit -- finit.debug rescue`
|
||||
|
||||
* `debug`: Enable kernel debug. Debug messages are printed to the
|
||||
console until Finit starts up.
|
||||
console until Finit starts up, unless `loglevel=7` (below) is used.
|
||||
|
||||
* `finit.debug[=bool]`: Enable finit debug. This is operated
|
||||
independently of the kernel debug setting. New as of Finit v4.
|
||||
independently of the kernel `debug` setting. New as of Finit v4.
|
||||
|
||||
* `finit.show_status[=bool]`: Control finit boot progress, including
|
||||
banner.
|
||||
* `finit.status[=bool]`: Control finit boot progress, including banner.
|
||||
(Used to be `finit.show_status`, which works but is deprecated.)
|
||||
|
||||
* `finit.status_style=<classic,modern>`: Set Finit boot progress style,
|
||||
when enabled.
|
||||
@@ -26,11 +26,18 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
|
||||
signals and has no job control. Recommend using, and modifying,
|
||||
`rescue` mode instead.
|
||||
|
||||
* `loglevel=<0-7>`, sets the kernel's log level, which is more granular
|
||||
than `debug`. Also, when `loglevel=7`, Finit will *not disable*
|
||||
kernel logs to the console. This is very useful when debugging the
|
||||
kernel at system bring-up. Since `loglevel=7` is the same as `debug`
|
||||
this means you have to use `quiet` for a quiet boot, until sysklogd
|
||||
takes over logging of kernel events.
|
||||
|
||||
* `panic=SEC`: By default the kernel does not reboot after a kernel
|
||||
panic. This setting will cause a kernel reboot after SEC seconds.
|
||||
|
||||
* `quiet`: Suppress kernel logging to console, except for warnings and
|
||||
errors.
|
||||
errors. Also, see `loglevel` and `quiet` above.
|
||||
|
||||
* `rescue`: Start rescue/maintenance mode. If your system comes with
|
||||
the bundled `sulogin` program (Finit, or from util-linux/Busybox),
|
||||
@@ -46,5 +53,5 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
|
||||
|
||||
For more on kernel boot parameters, see the man page [bootparam(7)][].
|
||||
|
||||
[config.md][]: config.md#rescue-mode
|
||||
[config.md]: config.md#rescue-mode
|
||||
[bootparam(7)]: https://www.man7.org/linux/man-pages/man7/bootparam.7.html
|
||||
|
||||
+17
-3
@@ -323,6 +323,10 @@ calls `init-script restart` on `initctl reload`. Similar to how
|
||||
|
||||
Forking services started with `sysv` scripts can be monitored by Finit
|
||||
by declaring the PID file to look for: `pid:!/path/to/pidfile.pid`.
|
||||
Notice the leading `!`, it signifies Finit should not try to create the
|
||||
file, but rather watch that file for the resulting forked-off PID. This
|
||||
syntax also works for forking daemons that do not have a command line
|
||||
option to run it in the foreground, more on this below in `service`.
|
||||
|
||||
> `<COND>` is described in the [Services](#services) section.
|
||||
|
||||
@@ -344,9 +348,19 @@ prevent them from forking off a sub-process in the background. This is
|
||||
the most reliable way to monitor a service.
|
||||
|
||||
However, not all daemons support running in the foreground, or they may
|
||||
start logging to the foreground as well, these are called forking
|
||||
services and are supported using the same syntax as forking `sysv`
|
||||
services, using the `pid:!/path/to/pidfile.pid` syntax.
|
||||
start logging to the foreground as well, these are forking daemons and
|
||||
are supported using the same syntax as forking `sysv` services, using
|
||||
the `pid:!/path/to/pidfile.pid` syntax. There is an alternative syntax
|
||||
that may be more intuitive, where Finit can also guess the PID file
|
||||
based on the daemon's command name:
|
||||
|
||||
service type:forking ntpd -- NTP daemon
|
||||
|
||||
This example lets BusyBox `ntpd` daemonize itself. Finit uses the
|
||||
basename of the binary to guess the PID file to watch for the PID:
|
||||
`/var/run/ntpd.pid`. If Finit guesses wrong, you have to submit the
|
||||
full `pid:!/path/to/file.pid`.
|
||||
|
||||
|
||||
**Example:**
|
||||
|
||||
|
||||
+6
-4
@@ -35,25 +35,27 @@ For your convenience a set of *optional* plugins are available:
|
||||
_Optional plugin._
|
||||
|
||||
* *hotplug.so*: Setup and start either udev or mdev hotplug daemon, if
|
||||
available.
|
||||
available. Enabled by default.
|
||||
|
||||
* *rtc.so*: Restore and save system clock from/to RTC on boot/halt.
|
||||
Enabled by default.
|
||||
|
||||
* *modules-load.so*: Scans /etc/modules-load.d for modules to modprobe.
|
||||
|
||||
* *netlink.so*: Listens to Linux kernel Netlink events for gateway and
|
||||
interfaces. These events are then sent to the Finit service monitor
|
||||
for services that may want to be SIGHUP'ed on new default route or
|
||||
interfaces going up/down.
|
||||
interfaces going up/down. Enabled by default.
|
||||
|
||||
* *resolvconf.so*: Setup necessary files for `resolvconf` at startup.
|
||||
_Optional plugin._
|
||||
|
||||
* *tty.so*: Watches `/dev`, using inotify, for new device nodes (TTY's)
|
||||
to start/stop getty consoles on them on demand. Useful when plugging
|
||||
in a usb2serial converter to login to your embedded device.
|
||||
in a usb2serial converter to login to your embedded device. Enabled
|
||||
by default.
|
||||
|
||||
* *urandom.so*: Setup random seed at startup.
|
||||
* *urandom.so*: Setup random seed at startup. Enabled by default.
|
||||
|
||||
* *x11-common.so*: Setup necessary files for X-Window. _Optional plugin._
|
||||
|
||||
|
||||
+55
-1
@@ -1,7 +1,59 @@
|
||||
Finit Services
|
||||
==============
|
||||
|
||||

|
||||
Starting & Monitoring
|
||||
---------------------
|
||||
|
||||
Finit can start and monitor the following types of daemons:
|
||||
|
||||
* Forks to background, creates a PID file
|
||||
* Runs in foreground:
|
||||
- creates a PID file
|
||||
- does not create a PID file -- Finit can create it for you (optional)
|
||||
|
||||
Finit can *not* start and monitor a daemon that:
|
||||
|
||||
* Forks to background and does *not* create a PID file
|
||||
|
||||
| | Forking | Creates PID File | Finit creates PID File |
|
||||
|---|---------|------------------|------------------------|
|
||||
| ✔ | Yes | Yes | No |
|
||||
| ✔ | No | Yes | No |
|
||||
| ✔ | No | No | Yes, optionally |
|
||||
| ✘ | Yes | No | No |
|
||||
|
||||
> **Note:** PID files is one mechanism used to assert conditions to
|
||||
> synchronize the start and stop of other, dependent, services.
|
||||
|
||||
### Forks to Background w/ PID File
|
||||
|
||||
There are two syntax variants, type 1 and type 2. The former is the
|
||||
traditional one used also for `sysv` start/stop scripts, and the latter
|
||||
is inspired by systemd, with a twist -- it lets Finit guess the pifdile
|
||||
to look for based on the standard path and the basename of the command.
|
||||
|
||||
service pid:!/run/serv.pid serv -- Forking service, type 1
|
||||
service type:forking serv -- Forking service, type 2
|
||||
|
||||
In this example the resulting files to watch for are `/run/serv.pid` and
|
||||
`/var/run/serv.pid`, respectively. On most modern Linux systems this is
|
||||
the same directory (`/var/run` is a symlink to `../run`).
|
||||
|
||||
### Runs in Foreground w/ PID File
|
||||
|
||||
service serv -n -p -- Foreground service w/ PID file
|
||||
|
||||
### Runs in Foreground w/o PID File
|
||||
|
||||
Same as previous, but we tell Finit to create the PID file, because we
|
||||
need it to synchronize start/stop of a dependent service.
|
||||
|
||||
service pid:/run/serv.pid serv -n -- Foreground service w/o PID file
|
||||
|
||||
### Runs in Foreground w/ Custom PID File
|
||||
|
||||
service pid:/run/servy.pid serv -n -p -P /run/servy.pid -- Foreground service w/ custom PID file
|
||||
|
||||
|
||||
State Machine
|
||||
-------------
|
||||
@@ -11,6 +63,8 @@ For `run`s and `task`s there is an additional end state called `DONE`,
|
||||
not shown in the diagram for brevity. Services start in the `HALTED`
|
||||
state.
|
||||
|
||||

|
||||
|
||||
The current state depends on the two following conditions:
|
||||
|
||||
* `E`: Service enabled. In order for `E` to be satisfied, the service
|
||||
|
||||
+3
-2
@@ -11,8 +11,9 @@
|
||||
.Nd Fast init for Linux systems
|
||||
.Sh SYNOPSIS
|
||||
.Nm /sbin/finit
|
||||
.Op finit.status_style=classic
|
||||
.Op finit.show_status=[on,off]
|
||||
.Op --
|
||||
.Op finit.status=[on,off]
|
||||
.Op finit.status_style=[classic,modern]
|
||||
.Op finit.debug
|
||||
.Op rescue | recover
|
||||
.Op single | S
|
||||
|
||||
+15
-1
@@ -194,7 +194,21 @@ services and are supported using the same syntax as forking
|
||||
.Cm sysv
|
||||
services, using the
|
||||
.Cm pid:!/path/to/pidfile.pid
|
||||
command modifier syntax.
|
||||
command modifier syntax. There is an alternative syntax that may be
|
||||
more intuitive, where Finit can also guess the PID file based on the
|
||||
daemon's command name:
|
||||
.Bd -unfilled -offset indent
|
||||
service type:forking ntpd -- NTP daemon
|
||||
.Ed
|
||||
.Pp
|
||||
Here we let BusyBox
|
||||
.Nm ntpd
|
||||
daemonize itself. Finit uses the basename of the binary to guess the
|
||||
PID file to watch for the PID:
|
||||
.Pa /var/run/ntpd.pid .
|
||||
If Finit guesses wrong, you have to submit the full
|
||||
.Cm pid:!/path/to/file.pid
|
||||
option to your service stanza.
|
||||
.Pp
|
||||
.Sy Example: in the case of
|
||||
.Cm ospfd
|
||||
|
||||
+11
-3
@@ -11,7 +11,7 @@
|
||||
.Nd Control tool for Finit
|
||||
.Sh SYNOPSIS
|
||||
.Nm /sbin/initctl
|
||||
.Op Fl bcfhlpqtv
|
||||
.Op Fl bcfhlpqtvV
|
||||
.Op COMMAND
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
@@ -41,16 +41,20 @@ Silent, only return status of command.
|
||||
Skip table headings.
|
||||
.It Fl v, -verbose
|
||||
Verbose output, where applicable.
|
||||
.It Fl V, -version
|
||||
Show program version.
|
||||
.El
|
||||
.Sh COMMANDS
|
||||
.Bl -tag -width Ds
|
||||
.It Nm Ar debug
|
||||
Toggle finit (daemon) debug to
|
||||
Toggle
|
||||
.Nm finit
|
||||
(daemon) debug to
|
||||
.Pa /dev/console
|
||||
.It Nm Ar help
|
||||
Show built-in help text
|
||||
.It Nm Ar version
|
||||
Show Finit (daemon) version
|
||||
Show program version
|
||||
.It Nm Ar ls | list
|
||||
List all
|
||||
.Cm *.conf
|
||||
@@ -136,6 +140,10 @@ Start service by name, with optional ID, e.g.,
|
||||
Stop/Pause a running service by name
|
||||
.It Nm Ar reload Cm NAME[:ID]
|
||||
Reload service by name (SIGHUP or restart)
|
||||
.It Nm Ar signal Cm NAME:[ID] S
|
||||
Send signal S to service, by name.
|
||||
.Cm S
|
||||
may be a complete signal name such as SIGHUP, or short name such as HUP, or the signal number such as 1 (SIGHUP).
|
||||
.It Nm Ar restart Cm NAME[:ID]
|
||||
Restart (stop/start) service by name
|
||||
.It Nm Ar status Cm NAME[:ID]
|
||||
|
||||
+19
-3
@@ -3,11 +3,11 @@ AM_LDFLAGS = -module -avoid-version -shared
|
||||
AM_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/src -U_FORTIFY_SOURCE
|
||||
AM_CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE
|
||||
AM_CPPFLAGS += $(lite_CFLAGS)
|
||||
AM_CPPFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
|
||||
|
||||
if STATIC
|
||||
noinst_LTLIBRARIES = libplug.la
|
||||
libplug_la_SOURCES = bootmisc.c modprobe.c pidfile.c procps.c sys.c tty.c usr.c
|
||||
libplug_la_SOURCES = bootmisc.c pidfile.c procps.c sys.c usr.c
|
||||
|
||||
if BUILD_ALSA_UTILS_PLUGIN
|
||||
libplug_la_SOURCES += alsa-utils.c
|
||||
@@ -25,6 +25,10 @@ if BUILD_MODULES_LOAD_PLUGIN
|
||||
libplug_la_SOURCES += modules-load.c
|
||||
endif
|
||||
|
||||
if BUILD_MODPROBE_PLUGIN
|
||||
libplug_la_SOURCES += modprobe.c
|
||||
endif
|
||||
|
||||
if BUILD_NETLINK_PLUGIN
|
||||
libplug_la_SOURCES += netlink.c
|
||||
endif
|
||||
@@ -37,6 +41,10 @@ if BUILD_RTC_PLUGIN
|
||||
libplug_la_SOURCES += rtc.c
|
||||
endif
|
||||
|
||||
if BUILD_TTY_PLUGIN
|
||||
libplug_la_SOURCES += tty.c
|
||||
endif
|
||||
|
||||
if BUILD_URANDOM_PLUGIN
|
||||
libplug_la_SOURCES += urandom.c
|
||||
endif
|
||||
@@ -46,7 +54,7 @@ libplug_la_SOURCES += x11-common.c
|
||||
endif
|
||||
|
||||
else
|
||||
pkglib_LTLIBRARIES = bootmisc.la modprobe.la pidfile.la procps.la sys.la tty.la usr.la
|
||||
pkglib_LTLIBRARIES = bootmisc.la pidfile.la procps.la sys.la usr.la
|
||||
|
||||
if BUILD_ALSA_UTILS_PLUGIN
|
||||
pkglib_LTLIBRARIES += alsa-utils.la
|
||||
@@ -64,6 +72,10 @@ if BUILD_MODULES_LOAD_PLUGIN
|
||||
pkglib_LTLIBRARIES += modules-load.la
|
||||
endif
|
||||
|
||||
if BUILD_MODPROBE_PLUGIN
|
||||
pkglib_LTLIBRARIES += modprobe.la
|
||||
endif
|
||||
|
||||
if BUILD_NETLINK_PLUGIN
|
||||
pkglib_LTLIBRARIES += netlink.la
|
||||
endif
|
||||
@@ -76,6 +88,10 @@ if BUILD_RTC_PLUGIN
|
||||
pkglib_LTLIBRARIES += rtc.la
|
||||
endif
|
||||
|
||||
if BUILD_TTY_PLUGIN
|
||||
pkglib_LTLIBRARIES += tty.la
|
||||
endif
|
||||
|
||||
if BUILD_URANDOM_PLUGIN
|
||||
pkglib_LTLIBRARIES += urandom.la
|
||||
endif
|
||||
|
||||
+7
-7
@@ -104,9 +104,9 @@ static void clean(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
static void ln(const char *target, const char *linkpath, int ignerr)
|
||||
static void ln(const char *target, const char *linkpath)
|
||||
{
|
||||
if (symlink(target, linkpath) && !ignerr)
|
||||
if (symlink(target, linkpath) && errno != EEXIST)
|
||||
_pe("Failed creating %s -> %s symlink", target, linkpath);
|
||||
}
|
||||
|
||||
@@ -131,11 +131,11 @@ static void setup(void *arg)
|
||||
_d("System with new /run tmpfs ...");
|
||||
if (!fisdir("/run/lock"))
|
||||
makedir("/run/lock", 1777);
|
||||
ln("/run/lock", "/var/lock", 0);
|
||||
ln("/dev/shm", "/run/shm", 0);
|
||||
ln("/run/lock", "/var/lock");
|
||||
ln("/dev/shm", "/run/shm");
|
||||
|
||||
/* compat only, should really be set up by OS/dist */
|
||||
ln("/run", "/var/run", 1);
|
||||
ln("/run", "/var/run");
|
||||
} else {
|
||||
makedir("/var/lock", 1777);
|
||||
makedir("/var/run", 0755);
|
||||
@@ -189,7 +189,7 @@ static void setup(void *arg)
|
||||
makedir("/var/run/sshd", 01755); /* OpenSSH */
|
||||
|
||||
if (!fexist("/etc/mtab"))
|
||||
ln("../proc/self/mounts", "/etc/mtab", 1);
|
||||
ln("../proc/self/mounts", "/etc/mtab");
|
||||
|
||||
/* Void Linux has a uuidd that runs as uuid:uuid and needs /run/uuid */
|
||||
mksubsys("/var/run/uuidd", 0755, "uuidd", "uuidd");
|
||||
@@ -198,7 +198,7 @@ static void setup(void *arg)
|
||||
mksubsys("/var/run/sudo", 0711, "root", "root");
|
||||
mksubsys("/var/run/sudo/ts", 0700, "root", "root");
|
||||
if (whichp("restorecon"))
|
||||
run("restorecon /var/run/sudo /var/run/sudo/ts");
|
||||
run("restorecon /var/run/sudo /var/run/sudo/ts", "restorecon");
|
||||
|
||||
umask(prev);
|
||||
}
|
||||
|
||||
+3
-1
@@ -1,3 +1,4 @@
|
||||
|
||||
/* Netlink plugin for IFUP/IFDN and GW events
|
||||
*
|
||||
* Copyright (C) 2009-2011 Mårten Wikström <marten.wikstrom@keystream.se>
|
||||
@@ -252,7 +253,7 @@ static int nl_parse(int sd)
|
||||
return -1;
|
||||
}
|
||||
|
||||
_d("recv %lld bytes", len);
|
||||
_d("recv %zd bytes", len);
|
||||
l = (size_t)len;
|
||||
for (nh = (struct nlmsghdr *)nl_buf; NLMSG_OK(nh, l); nh = NLMSG_NEXT(nh, l)) {
|
||||
struct nlmsgerr *nle;
|
||||
@@ -449,6 +450,7 @@ PLUGIN_INIT(plugin_init)
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
close(plugin.io.fd);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -305,8 +305,8 @@ PLUGIN_INIT(plugin_init)
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
iwatch_exit(&iw_pidfile);
|
||||
plugin_unregister(&plugin);
|
||||
iwatch_exit(&iw_pidfile);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+6
-4
@@ -34,9 +34,7 @@
|
||||
|
||||
static void setup(void *arg)
|
||||
{
|
||||
size_t i;
|
||||
glob_t gl;
|
||||
char buf[160];
|
||||
|
||||
if (rescue) {
|
||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
||||
@@ -51,9 +49,13 @@ static void setup(void *arg)
|
||||
glob("/mnt/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||
glob("/etc/sysctl.conf", GLOB_APPEND, NULL, &gl);
|
||||
if (gl.gl_pathc > 0) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < gl.gl_pathc; i++) {
|
||||
snprintf(buf, sizeof(buf), "/sbin/sysctl -e -p %s >/dev/null", gl.gl_pathv[i]);
|
||||
run(buf);
|
||||
char cmd[160];
|
||||
|
||||
snprintf(cmd, sizeof(cmd), "/sbin/sysctl -e -p %s >/dev/null", gl.gl_pathv[i]);
|
||||
run(cmd, "sysctl");
|
||||
}
|
||||
globfree(&gl);
|
||||
}
|
||||
|
||||
+1
-1
@@ -197,8 +197,8 @@ PLUGIN_INIT(plugin_init)
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
iwatch_exit(&iw_sys);
|
||||
plugin_unregister(&plugin);
|
||||
iwatch_exit(&iw_sys);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-2
@@ -116,10 +116,9 @@ PLUGIN_INIT(plugin_init)
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
if (plugin.io.fd)
|
||||
close(plugin.io.fd);
|
||||
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -123,8 +123,8 @@ PLUGIN_INIT(plugin_init)
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
iwatch_exit(&iw_usr);
|
||||
plugin_unregister(&plugin);
|
||||
iwatch_exit(&iw_usr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -58,7 +58,7 @@ static void setup(void *arg)
|
||||
if ((fd = open("/var/run/console/console.lock", O_CREAT|O_WRONLY|O_TRUNC, 0644)) >= 0) {
|
||||
write(fd, username, strlen(username));
|
||||
close(fd);
|
||||
run("pam_console_apply");
|
||||
run("pam_console_apply", "pam-console");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -66,7 +66,7 @@ static void setup(void *arg)
|
||||
makedir("/tmp/.ICE-unix", 01777);
|
||||
|
||||
if (whichp("restorecon"))
|
||||
run("restorecon /tmp/.ICE-unix /tmp/.X11-unix");
|
||||
run("restorecon /tmp/.ICE-unix /tmp/.X11-unix", "restorecon");
|
||||
|
||||
umask(prev);
|
||||
}
|
||||
|
||||
@@ -51,12 +51,12 @@
|
||||
extern svc_t *wdog;
|
||||
static uev_t api_watcher;
|
||||
|
||||
static int call(int (*action)(svc_t *), char *buf, size_t len)
|
||||
static int call(int (*action)(svc_t *, void *), char *buf, size_t len)
|
||||
{
|
||||
return svc_parse_jobstr(buf, len, action, NULL);
|
||||
return svc_parse_jobstr(buf, len, NULL, action, NULL);
|
||||
}
|
||||
|
||||
static int stop(svc_t *svc)
|
||||
static int stop(svc_t *svc, void *user_data)
|
||||
{
|
||||
if (!svc)
|
||||
return 1;
|
||||
@@ -67,7 +67,7 @@ static int stop(svc_t *svc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int start(svc_t *svc)
|
||||
static int start(svc_t *svc, void *user_data)
|
||||
{
|
||||
if (!svc)
|
||||
return 1;
|
||||
@@ -83,7 +83,7 @@ static int start(svc_t *svc)
|
||||
* responsibility of initctl to do. Otherwise we'd block PID 1,
|
||||
* or introduce some nasty race conditions.
|
||||
*/
|
||||
static int restart(svc_t *svc)
|
||||
static int restart(svc_t *svc, void *user_data)
|
||||
{
|
||||
if (!svc)
|
||||
return 1;
|
||||
@@ -95,7 +95,7 @@ static int restart(svc_t *svc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reload(svc_t *svc)
|
||||
static int reload(svc_t *svc, void *user_data)
|
||||
{
|
||||
if (!svc)
|
||||
return 1;
|
||||
@@ -114,8 +114,28 @@ static int do_start (char *buf, size_t len) { return call(start, buf, len); }
|
||||
static int do_restart(char *buf, size_t len) { return call(restart, buf, len); }
|
||||
static int do_reload (char *buf, size_t len) { return call(reload, buf, len); }
|
||||
|
||||
static int do_signal_svc(svc_t *svc, void *user_data)
|
||||
{
|
||||
int signo;
|
||||
|
||||
if (!svc || !user_data || !svc_is_running(svc))
|
||||
return 1;
|
||||
|
||||
signo = *(int *)user_data;
|
||||
return !!kill(svc->pid, signo);
|
||||
}
|
||||
|
||||
static int do_signal(char *buf, size_t len, int sig)
|
||||
{
|
||||
/* Sanity check: do we know this signal? */
|
||||
if (!*sig2str(sig))
|
||||
return 1;
|
||||
|
||||
return svc_parse_jobstr(buf, len, &sig, do_signal_svc, NULL);
|
||||
}
|
||||
|
||||
static char query_buf[368];
|
||||
static int missing(char *job, char *id)
|
||||
static int missing(char *job, char *id, void *user_data)
|
||||
{
|
||||
char buf[20];
|
||||
|
||||
@@ -133,7 +153,7 @@ static int missing(char *job, char *id)
|
||||
static int do_query(char *buf, size_t len)
|
||||
{
|
||||
query_buf[0] = 0;
|
||||
if (svc_parse_jobstr(buf, len, NULL, missing)) {
|
||||
if (svc_parse_jobstr(buf, len, NULL, NULL, missing)) {
|
||||
memcpy(buf, query_buf, len);
|
||||
return 1;
|
||||
}
|
||||
@@ -230,10 +250,10 @@ static int do_reboot(int cmd, char *buf, size_t len)
|
||||
case INIT_CMD_SUSPEND:
|
||||
_d("suspend");
|
||||
sync();
|
||||
rc = reboot(RB_SW_SUSPEND);
|
||||
rc = suspend();
|
||||
if (rc) {
|
||||
if (errno == EINVAL)
|
||||
snprintf(buf, len, "Kernel does not support suspend.");
|
||||
snprintf(buf, len, "Kernel does not support suspend to RAM.");
|
||||
else
|
||||
snprintf(buf, len, "Failed: %s", strerror(errno));
|
||||
}
|
||||
@@ -407,7 +427,7 @@ static void api_cb(uev_t *w, void *arg, int events)
|
||||
|
||||
if (wdog->protect) {
|
||||
logit(LOG_NOTICE, "Stopping and deleting built-in watchdog.");
|
||||
stop(wdog);
|
||||
stop(wdog, NULL);
|
||||
svc_del(wdog);
|
||||
}
|
||||
}
|
||||
@@ -443,6 +463,13 @@ static void api_cb(uev_t *w, void *arg, int events)
|
||||
send_svc(sd, do_find_byc(rq.data, sizeof(rq.data)));
|
||||
goto leave;
|
||||
|
||||
case INIT_CMD_SIGNAL:
|
||||
/* runlevel is reused for signal */
|
||||
_d("svc signal %d: %s", rq.runlevel, rq.data);
|
||||
strterm(rq.data, sizeof(rq.data));
|
||||
result = do_signal(rq.data, sizeof(rq.data), rq.runlevel);
|
||||
break;
|
||||
|
||||
default:
|
||||
_d("Unsupported cmd: %d", rq.cmd);
|
||||
break;
|
||||
|
||||
+27
-9
@@ -466,8 +466,10 @@ void cgroup_init(uev_ctx_t *ctx)
|
||||
if (mount("none", FINIT_CGPATH, "cgroup2", opts, NULL)) {
|
||||
if (errno == ENOENT)
|
||||
logit(LOG_NOTICE, "Kernel does not support cgroups v2, disabling.");
|
||||
else if (errno == EPERM) /* Probably inside an unpriviliged container */
|
||||
logit(LOG_NOTICE, "Not allowed to mount cgroups v2, disabling.");
|
||||
else
|
||||
_pe("Failed mounting cgroup v2, disabling.");
|
||||
_pe("Failed mounting cgroup v2");
|
||||
avail = 0;
|
||||
return;
|
||||
}
|
||||
@@ -477,6 +479,7 @@ void cgroup_init(uev_ctx_t *ctx)
|
||||
fp = fopen(FINIT_CGPATH "/cgroup.controllers", "r");
|
||||
if (!fp) {
|
||||
_pe("Failed opening %s", FINIT_CGPATH "/cgroup.controllers");
|
||||
abort:
|
||||
umount(FINIT_CGPATH);
|
||||
avail = 0;
|
||||
return;
|
||||
@@ -494,9 +497,26 @@ void cgroup_init(uev_ctx_t *ctx)
|
||||
|
||||
fclose(fp);
|
||||
|
||||
/* Check for cpu controller, abort if missing */
|
||||
if (!strstr(controllers, "+cpu")) {
|
||||
logit(LOG_NOTICE, "Missing CPU controller, disabling cgroup support.");
|
||||
goto abort;
|
||||
}
|
||||
|
||||
/* Enable all controllers */
|
||||
if (fnwrite(controllers, FINIT_CGPATH "/cgroup.subtree_control"))
|
||||
if (fnwrite(controllers, FINIT_CGPATH "/cgroup.subtree_control")) {
|
||||
_pe("Failed enabling %s for %s", controllers, FINIT_CGPATH "/cgroup.subtree_control");
|
||||
goto abort;
|
||||
}
|
||||
|
||||
/* prepare cgroup.events watcher */
|
||||
fd = iwatch_init(&iw_cgroup);
|
||||
if (uev_io_init(ctx, &cgw, cgroup_events_cb, NULL, fd, UEV_READ)) {
|
||||
_pe("Failed setting up cgroup.events watcher");
|
||||
iwatch_exit(&iw_cgroup);
|
||||
close(fd);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
/* Default (protected) groups, PID 1, services, and user/login processes */
|
||||
cgroup_add("init", "cpu.weight:100", 1);
|
||||
@@ -505,14 +525,12 @@ void cgroup_init(uev_ctx_t *ctx)
|
||||
cgroup_config();
|
||||
|
||||
/* Move ourselves to init (best effort, otherwise run in 'root' group */
|
||||
if (fnwrite("1", FINIT_CGPATH "/init/cgroup.procs"))
|
||||
_pe("Failed moving PID 1 to cgroup ", FINIT_CGPATH "/init");
|
||||
|
||||
/* prepare cgroup.events watcher */
|
||||
fd = iwatch_init(&iw_cgroup);
|
||||
if (uev_io_init(ctx, &cgw, cgroup_events_cb, NULL, fd, UEV_READ)) {
|
||||
_pe("Failed setting up cgroup.events watcher");
|
||||
if (fnwrite("1", FINIT_CGPATH "/init/cgroup.procs")) {
|
||||
_pe("Failed moving PID 1 to cgroup %s", FINIT_CGPATH "/init");
|
||||
uev_io_stop(&cgw);
|
||||
iwatch_exit(&iw_cgroup);
|
||||
close(fd);
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-3
@@ -86,11 +86,13 @@ int client_send(struct init_request *rq, ssize_t len)
|
||||
}
|
||||
|
||||
pfd.fd = sd;
|
||||
pfd.events = POLLIN;
|
||||
pfd.events = POLLIN | POLLERR | POLLHUP;
|
||||
if ((rc = poll(&pfd, 1, 2000)) <= 0) {
|
||||
if (rc)
|
||||
if (rc) {
|
||||
if (errno == EINTR) /* shutdown/reboot */
|
||||
goto exit;
|
||||
warn("poll(), errno %d", errno);
|
||||
else
|
||||
} else
|
||||
warnx("Timed out waiting for reply from Finit.");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
+18
-20
@@ -86,8 +86,8 @@ fallback:
|
||||
}
|
||||
|
||||
/*
|
||||
* finit.debug = [on,off]
|
||||
* finit.show_status = [on,off]
|
||||
* finit.debug = [on,off]
|
||||
* finit.status = [on,off] (compat finit.show_status)
|
||||
* finit.status_style = [old,classic,modern]
|
||||
*/
|
||||
static void parse_finit_opts(char *opt)
|
||||
@@ -116,7 +116,7 @@ static void parse_finit_opts(char *opt)
|
||||
return;
|
||||
}
|
||||
|
||||
if (string_compare(opt, "show_status")) {
|
||||
if (string_compare(opt, "status") || string_compare(opt, "show_status")) {
|
||||
show_progress(get_bool(arg, 1) ? PROGRESS_DEFAULT : PROGRESS_SILENT);
|
||||
return;
|
||||
}
|
||||
@@ -205,28 +205,22 @@ void conf_parse_cmdline(int argc, char *argv[])
|
||||
|
||||
parse_kernel_cmdline();
|
||||
parse_kernel_loglevel();
|
||||
|
||||
log_init();
|
||||
}
|
||||
|
||||
static int kmod_exists(char *mod)
|
||||
{
|
||||
char buf[256];
|
||||
int found = 0;
|
||||
FILE *fp;
|
||||
char buf[256];
|
||||
size_t len;
|
||||
|
||||
for (len = 0; mod[len]; len++) {
|
||||
if (mod[len] == ' ' || mod[len] == '\t')
|
||||
break;
|
||||
}
|
||||
|
||||
fp = fopen("/proc/modules", "r");
|
||||
if (!fp)
|
||||
return 0;
|
||||
|
||||
while (!found && (fgets(buf, sizeof(buf), fp))) {
|
||||
if (!strncmp(buf, mod, len))
|
||||
while (!found && fgets(buf, sizeof(buf), fp)) {
|
||||
char *kmod = strtok(buf, " \t");
|
||||
|
||||
if (kmod && !strcmp(kmod, mod))
|
||||
found = 1;
|
||||
}
|
||||
fclose(fp);
|
||||
@@ -234,22 +228,26 @@ static int kmod_exists(char *mod)
|
||||
return found;
|
||||
}
|
||||
|
||||
static void kmod_load(char *line)
|
||||
static void kmod_load(char *mod)
|
||||
{
|
||||
char *mod;
|
||||
char module[64] = { 0 };
|
||||
char cmd[CMD_SIZE];
|
||||
|
||||
if (runlevel != 0)
|
||||
return;
|
||||
|
||||
mod = strip_line(line);
|
||||
if (kmod_exists(mod))
|
||||
/* Strip args for progress below and kmod_exists() */
|
||||
strlcpy(module, mod, sizeof(module));
|
||||
if (!strtok(module, " \t"))
|
||||
return;
|
||||
|
||||
if (kmod_exists(module))
|
||||
return;
|
||||
|
||||
strcpy(cmd, "modprobe ");
|
||||
strlcat(cmd, mod, sizeof(cmd));
|
||||
|
||||
run_interactive(cmd, "Loading kernel module %s", mod);
|
||||
run_interactive(cmd, "Loading kernel module %s", module);
|
||||
}
|
||||
|
||||
/* Convert optional "[!123456789S]" string into a bitmask */
|
||||
@@ -502,7 +500,7 @@ static void parse_static(char *line, int is_rcsd)
|
||||
|
||||
/* Kernel module to load */
|
||||
if (BOOTSTRAP && MATCH_CMD(line, "module ", x)) {
|
||||
kmod_load(x);
|
||||
kmod_load(strip_line(x));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+88
-48
@@ -28,6 +28,7 @@
|
||||
#include <dirent.h>
|
||||
#include <err.h>
|
||||
#include <stdarg.h>
|
||||
#include <sysexits.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/wait.h>
|
||||
@@ -70,89 +71,128 @@ int complete(char *cmd, int pid)
|
||||
return status;
|
||||
}
|
||||
|
||||
int run(char *cmd)
|
||||
static int do_redirect(void)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen("/dev/null", "w");
|
||||
if (fp) {
|
||||
int fd = fileno(fp);
|
||||
|
||||
dup2(fd, STDIN_FILENO);
|
||||
dup2(fd, STDOUT_FILENO);
|
||||
dup2(fd, STDERR_FILENO);
|
||||
|
||||
return fclose(fp);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run 'cmd' and wait for completion. If 'log' is not NULL any output
|
||||
* from the command is logged with the given string as prefix, use "" to
|
||||
* skip. If 'log' is NULL all output is redirected to /dev/null, which
|
||||
* is what this function originally did.
|
||||
*/
|
||||
int run(char *cmd, char *log)
|
||||
{
|
||||
char *args[NUM_ARGS + 1] = { 0 };
|
||||
int status, result, i = 0;
|
||||
char *args[NUM_ARGS + 1], *arg, *backup;
|
||||
char *backup = NULL;
|
||||
pid_t pid;
|
||||
|
||||
/* We must create a copy that is possible to modify. */
|
||||
backup = arg = strdup(cmd);
|
||||
if (!arg)
|
||||
return 1; /* Failed allocating a string to be modified. */
|
||||
if (!log) {
|
||||
char *arg;
|
||||
|
||||
/* Split command line into tokens of an argv[] array. */
|
||||
args[i++] = strsep(&arg, "\t ");
|
||||
while (arg && i < NUM_ARGS) {
|
||||
/* Handle run("su -c \"dbus-daemon --system\" messagebus");
|
||||
* => "su", "-c", "\"dbus-daemon --system\"", "messagebus" */
|
||||
if (*arg == '\'' || *arg == '"') {
|
||||
char *p, delim[2] = " ";
|
||||
/* We must create a copy that is possible to modify. */
|
||||
backup = arg = strdup(cmd);
|
||||
if (!arg)
|
||||
return 1;
|
||||
|
||||
delim[0] = arg[0];
|
||||
args[i++] = arg++;
|
||||
strsep(&arg, delim);
|
||||
p = arg - 1;
|
||||
*p = *delim;
|
||||
*arg++ = 0;
|
||||
} else {
|
||||
args[i++] = strsep(&arg, "\t ");
|
||||
/* Split command line into tokens of an argv[] array. */
|
||||
args[i++] = strsep(&arg, "\t ");
|
||||
while (arg && i < NUM_ARGS) {
|
||||
/* Handle run("su -c \"dbus-daemon --system\" messagebus");
|
||||
* => "su", "-c", "\"dbus-daemon --system\"", "messagebus" */
|
||||
if (*arg == '\'' || *arg == '"') {
|
||||
char *p, delim[2] = " ";
|
||||
|
||||
delim[0] = arg[0];
|
||||
args[i++] = arg++;
|
||||
strsep(&arg, delim);
|
||||
p = arg - 1;
|
||||
*p = *delim;
|
||||
*arg++ = 0;
|
||||
} else {
|
||||
args[i++] = strsep(&arg, "\t ");
|
||||
}
|
||||
}
|
||||
}
|
||||
args[i] = NULL;
|
||||
args[i] = NULL;
|
||||
|
||||
if (i == NUM_ARGS && arg) {
|
||||
_e("Command too long: %s", cmd);
|
||||
free(backup);
|
||||
errno = EOVERFLOW;
|
||||
return 1;
|
||||
if (i == NUM_ARGS && arg) {
|
||||
_e("Command too long: %s", cmd);
|
||||
free(backup);
|
||||
errno = EOVERFLOW;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (0 == pid) {
|
||||
FILE *fp;
|
||||
int rc = EX_OSERR;
|
||||
|
||||
setsid();
|
||||
sig_unblock();
|
||||
if (!log) {
|
||||
do_redirect();
|
||||
execvp(args[0], args);
|
||||
} else {
|
||||
char *pfx = *log ? ": " : "";
|
||||
FILE *pp;
|
||||
|
||||
/* Always redirect stdio for run() */
|
||||
fp = fopen("/dev/null", "w");
|
||||
if (fp) {
|
||||
int fd = fileno(fp);
|
||||
pp = popen(cmd, "r");
|
||||
if (pp) {
|
||||
char buf[256];
|
||||
|
||||
dup2(fd, STDIN_FILENO);
|
||||
dup2(fd, STDOUT_FILENO);
|
||||
dup2(fd, STDERR_FILENO);
|
||||
while (fgets(buf, sizeof(buf), pp)) {
|
||||
chomp(buf);
|
||||
logit(LOG_NOTICE, "%s%s%s", log, pfx, buf);
|
||||
}
|
||||
|
||||
rc = pclose(pp);
|
||||
}
|
||||
}
|
||||
|
||||
sig_unblock();
|
||||
execvp(args[0], args);
|
||||
|
||||
_exit(1); /* Only if execv() fails. */
|
||||
_exit(rc);
|
||||
} else if (-1 == pid) {
|
||||
_pe("%s", args[0]);
|
||||
free(backup);
|
||||
_pe("%s", !log ? args[0] : cmd);
|
||||
if (backup)
|
||||
free(backup);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = complete(args[0], pid);
|
||||
if (-1 == status) {
|
||||
free(backup);
|
||||
if (backup)
|
||||
free(backup);
|
||||
return 1;
|
||||
}
|
||||
|
||||
result = WEXITSTATUS(status);
|
||||
if (WIFEXITED(status)) {
|
||||
_d("Started %s and ended OK: %d", args[0], result);
|
||||
_d("Started '%s' and exit without signal, status: %d", cmd, result);
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
_d("Process %s terminated by signal %d", args[0], WTERMSIG(status));
|
||||
_d("Process '%s' terminated by signal %d", cmd, WTERMSIG(status));
|
||||
if (!result)
|
||||
result = 1; /* Must alert callee that the command did complete successfully.
|
||||
* This is necessary since not all programs trap signals and
|
||||
* change their return code accordingly. --Jocke */
|
||||
}
|
||||
|
||||
free(backup);
|
||||
if (backup)
|
||||
free(backup);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -186,7 +226,7 @@ int run_interactive(char *cmd, char *fmt, ...)
|
||||
}
|
||||
|
||||
/* Run cmd ... */
|
||||
status = run(cmd);
|
||||
status = run(cmd, "");
|
||||
|
||||
/* Restore stderr/stdout */
|
||||
if (fp && !debug) {
|
||||
@@ -222,7 +262,6 @@ int run_interactive(char *cmd, char *fmt, ...)
|
||||
|
||||
int exec_runtask(char *cmd, char *args[])
|
||||
{
|
||||
size_t i;
|
||||
char buf[1024] = "";
|
||||
char *argv[4] = {
|
||||
"sh",
|
||||
@@ -230,6 +269,7 @@ int exec_runtask(char *cmd, char *args[])
|
||||
buf,
|
||||
NULL
|
||||
};
|
||||
size_t i;
|
||||
|
||||
strlcat(buf, cmd, sizeof(buf));
|
||||
for (i = 1; args[i]; i++) {
|
||||
|
||||
+5
-4
@@ -333,7 +333,8 @@ static void fs_mount_all(void)
|
||||
_d("Calling extra mount hook, after mount -a ...");
|
||||
plugin_run_hooks(HOOK_MOUNT_POST);
|
||||
|
||||
run("swapon -ea");
|
||||
if (whichp("swapon"))
|
||||
run_interactive("swapon -ea", "Enabling system swap");
|
||||
|
||||
_d("Finalize, ensure common file systems are available ...");
|
||||
fs_finalize();
|
||||
@@ -569,7 +570,7 @@ int main(int argc, char *argv[])
|
||||
};
|
||||
uev_ctx_t loop;
|
||||
|
||||
/* telinit or stand-alone process monitor */
|
||||
/* user calling telinit or init */
|
||||
if (getpid() != 1)
|
||||
return telinit(argc, argv);
|
||||
|
||||
@@ -580,12 +581,12 @@ int main(int argc, char *argv[])
|
||||
|
||||
/*
|
||||
* Parse /proc/cmdline (debug, rescue, console=, etc.)
|
||||
* Also calls log_init() to set correct log level
|
||||
*/
|
||||
conf_parse_cmdline(argc, argv);
|
||||
|
||||
/*
|
||||
* Figure out system console(s)
|
||||
* Figure out system console(s) and call log_init() to set
|
||||
* correct log level, possibly finit.debug enabled.
|
||||
*/
|
||||
console_init();
|
||||
|
||||
|
||||
@@ -95,6 +95,7 @@
|
||||
#define INIT_CMD_SVC_QUERY 130
|
||||
#define INIT_CMD_SVC_FIND 131
|
||||
#define INIT_CMD_SVC_FIND_BYC 132
|
||||
#define INIT_CMD_SIGNAL 133
|
||||
#define INIT_CMD_NACK 254
|
||||
#define INIT_CMD_ACK 255
|
||||
|
||||
|
||||
+73
-8
@@ -30,6 +30,7 @@
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdarg.h>
|
||||
#include <sysexits.h>
|
||||
#include <sys/ioctl.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
# include <libite/lite.h>
|
||||
@@ -40,6 +41,7 @@
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "private.h"
|
||||
#include "sig.h"
|
||||
#include "util.h"
|
||||
#include "utmp-api.h"
|
||||
|
||||
@@ -57,7 +59,7 @@ static pstyle_t progress_style = PROGRESS_DEFAULT;
|
||||
#define STATUS_CLASS { \
|
||||
CHOOSE(" OK ", " OK ", "\e[1;32m"), /* Green */ \
|
||||
CHOOSE("FAIL", "FAIL", "\e[1;31m"), /* Red */ \
|
||||
CHOOSE("WARN", "WARN", "\e[1;31m"), /* Red */ \
|
||||
CHOOSE("WARN", "WARN", "\e[1;33m"), /* Yellow */ \
|
||||
CHOOSE(" \\/ ", " ⋯ ", "\e[1;33m"), /* Yellow */ \
|
||||
}
|
||||
|
||||
@@ -79,7 +81,7 @@ char *console(void)
|
||||
|
||||
void console_init(void)
|
||||
{
|
||||
ttinit();
|
||||
log_init();
|
||||
}
|
||||
|
||||
ssize_t cprintf(const char *fmt, ...)
|
||||
@@ -493,27 +495,52 @@ void networking(int updown)
|
||||
|
||||
/* Debian/Ubuntu/Busybox/RH/Suse */
|
||||
if (!whichp("ifup"))
|
||||
goto done;
|
||||
goto fallback;
|
||||
|
||||
if (fexist("/etc/network/interfaces")) {
|
||||
pid_t pid;
|
||||
|
||||
pid = fork();
|
||||
if (pid == 0) {
|
||||
int rc = EX_OSERR;
|
||||
const char *cmd;
|
||||
FILE *pp;
|
||||
|
||||
setsid();
|
||||
sig_unblock();
|
||||
|
||||
if (updown)
|
||||
run("ifup -a");
|
||||
cmd = "ifup -a 2>&1";
|
||||
else if (whichp("ifquery"))
|
||||
/* Regular ifodwn supports --force but not -f */
|
||||
cmd = "ifdown -a --force 2>&1";
|
||||
else
|
||||
run("ifdown -a");
|
||||
_exit(0);
|
||||
/* Busybox ifdown support -f, but not --force */
|
||||
cmd = "ifdown -a -f 2>&1";
|
||||
|
||||
pp = popen(cmd, "r");
|
||||
if (pp) {
|
||||
char buf[256];
|
||||
|
||||
while (fgets(buf, sizeof(buf), pp))
|
||||
logit(LOG_NOTICE, "network: %s", buf);
|
||||
|
||||
rc = pclose(pp);
|
||||
}
|
||||
|
||||
_exit(rc);
|
||||
}
|
||||
cgroup_service("network", pid, NULL);
|
||||
print(pid > 0 ? 0 : 1, "%s network interfaces ...",
|
||||
updown ? "Bringing up" : "Taking down");
|
||||
|
||||
print(pid > 0 ? 0 : 1, "%s networking", updown ? "Starting" : "Stopping");
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
fallback:
|
||||
/* Fall back to bring up at least loopback */
|
||||
ifconfig("lo", "127.0.0.1", "255.0.0.0", updown);
|
||||
done:
|
||||
|
||||
/* Hooks that rely on loopback, or basic networking being up. */
|
||||
if (updown) {
|
||||
@@ -522,6 +549,44 @@ done:
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Very basic, and incomplete, check if we're running in a container.
|
||||
*/
|
||||
int in_container(void)
|
||||
{
|
||||
const char *containers[] = {
|
||||
"lxc",
|
||||
"docker",
|
||||
"kubepod",
|
||||
"unshare"
|
||||
};
|
||||
const char *files[] = {
|
||||
"/run/.containerenv",
|
||||
"/.dockerenv"
|
||||
};
|
||||
static int incont = -1;
|
||||
size_t i;
|
||||
char *c;
|
||||
|
||||
if (incont > 0)
|
||||
return incont;
|
||||
|
||||
c = getenv("container");
|
||||
if (c) {
|
||||
for (i = 0; i < NELEMS(containers); i++) {
|
||||
if (!strcmp(containers[i], c))
|
||||
return incont = 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < NELEMS(files); i++) {
|
||||
if (!access(files[i], F_OK))
|
||||
return incont = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef HAVE_GETFSENT
|
||||
static lfile_t *fstab = NULL;
|
||||
|
||||
|
||||
+5
-4
@@ -65,7 +65,7 @@ struct fstab *getfsent (void);
|
||||
|
||||
char *console (void);
|
||||
void console_init (void);
|
||||
ssize_t cprintf (const char *fmt, ...);
|
||||
ssize_t cprintf (const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
||||
|
||||
char *strip_line (char *line);
|
||||
|
||||
@@ -79,7 +79,7 @@ void stty (int fd, speed_t speed);
|
||||
|
||||
void print_banner (const char *heading);
|
||||
void printv (const char *fmt, va_list ap);
|
||||
void print (int action, const char *fmt, ...);
|
||||
void print (int action, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
void print_desc (char *action, char *desc);
|
||||
int print_result (int fail);
|
||||
|
||||
@@ -93,10 +93,11 @@ int mksubsys (const char *dir, mode_t mode, char *user, char *group);
|
||||
|
||||
void set_hostname (char **hostname);
|
||||
void networking (int updown);
|
||||
int in_container (void);
|
||||
|
||||
int complete (char *cmd, int pid);
|
||||
int run (char *cmd);
|
||||
int run_interactive (char *cmd, char *fmt, ...);
|
||||
int run (char *cmd, char *log);
|
||||
int run_interactive (char *cmd, char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
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[]);
|
||||
|
||||
+128
-48
@@ -52,6 +52,7 @@ struct cmd {
|
||||
struct cmd *ctx;
|
||||
int (*cb)(char *arg);
|
||||
int *cond;
|
||||
int (*cb_multiarg)(int argc, char **argv);
|
||||
};
|
||||
|
||||
int icreate = 0;
|
||||
@@ -160,8 +161,11 @@ static int do_log(char *svc)
|
||||
if (!svc || !svc[0])
|
||||
svc = "finit";
|
||||
|
||||
if (!fexist(logfile))
|
||||
if (!fexist(logfile)) {
|
||||
logfile = "/var/log/messages";
|
||||
if (!fexist(logfile))
|
||||
return 0; /* bail out, maybe in container */
|
||||
}
|
||||
|
||||
return systemf("cat %s | grep %s | tail -10", logfile, svc);
|
||||
}
|
||||
@@ -275,6 +279,61 @@ static int do_restart(char *arg)
|
||||
return do_startstop(INIT_CMD_RESTART_SVC, arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* do_signal - Ask finit to send a signal to a service.
|
||||
* @argv: must point to an array of strings, containing a service
|
||||
* and signal name, in that order.
|
||||
* @argc: must be 2.
|
||||
*
|
||||
* A signal can be a complete signal name such as "SIGHUP", or
|
||||
* it can be the shortest unique name, such as "HUP" (no SIG prefix).
|
||||
* It can also be a raw signal number, such as "9" (SIGKILL).
|
||||
*/
|
||||
int do_signal(int argc, char *argv[])
|
||||
{
|
||||
struct init_request rq = {
|
||||
.magic = INIT_MAGIC,
|
||||
.cmd = INIT_CMD_SVC_QUERY
|
||||
};
|
||||
int signo;
|
||||
|
||||
if (argc != 2)
|
||||
errx(1, "invalid number of arguments to signal");
|
||||
|
||||
/* Validate service name */
|
||||
strlcpy(rq.data, argv[0], sizeof(rq.data));
|
||||
if (client_send(&rq, sizeof(rq))) {
|
||||
fprintf(stderr, "No such task or service(s): %s\n\n", argv[0]);
|
||||
goto show_usage;
|
||||
}
|
||||
|
||||
/* Validate signal name (or number) */
|
||||
signo = str2sig(argv[1]);
|
||||
if (signo == -1) {
|
||||
/* Not a signal name, is it an actual signal number? */
|
||||
errno = 0;
|
||||
signo = (int)strtol(argv[1], NULL, 10);
|
||||
|
||||
/* Was it a number? Was it a signo that finit recognizes? */
|
||||
if (errno || !*(sig2str(signo))) {
|
||||
fprintf(stderr, "Not a valid signal (or signo): %s\n", argv[1]);
|
||||
goto show_usage;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reuse runlevel for signal number. */
|
||||
rq.magic = INIT_MAGIC;
|
||||
rq.cmd = INIT_CMD_SIGNAL;
|
||||
rq.runlevel = signo;
|
||||
strlcpy(rq.data, argv[0], sizeof(rq.data));
|
||||
|
||||
return client_send(&rq, sizeof(rq));
|
||||
|
||||
show_usage:
|
||||
fprintf(stderr, "Usage: initctl signal <NAME>[:ID] <S>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dump_one_cond(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftwbuf)
|
||||
{
|
||||
const char *cond, *asserted;
|
||||
@@ -292,7 +351,7 @@ static int dump_one_cond(const char *fpath, const struct stat *sb, int tflag, st
|
||||
if (strncmp("pid/", cond, 4) == 0) {
|
||||
svc_t *svc;
|
||||
|
||||
svc= client_svc_find_by_cond(cond);
|
||||
svc = client_svc_find_by_cond(cond);
|
||||
if (!svc) {
|
||||
nm = "unknown";
|
||||
pid = 0;
|
||||
@@ -722,7 +781,7 @@ static int show_status(char *arg)
|
||||
|
||||
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
|
||||
svc_ident(svc, ident, sizeof(ident));
|
||||
if (string_match(ident, arg))
|
||||
if (string_compare(ident, arg))
|
||||
num++;
|
||||
if (string_case_compare(ident, arg))
|
||||
exact++;
|
||||
@@ -735,8 +794,15 @@ static int show_status(char *arg)
|
||||
if (!svc)
|
||||
return 255;
|
||||
|
||||
if (quiet)
|
||||
return svc->state != SVC_RUNNING_STATE;
|
||||
if (quiet) {
|
||||
if (svc_is_runtask(svc))
|
||||
if (svc->started)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
else
|
||||
return svc->state != SVC_RUNNING_STATE;
|
||||
}
|
||||
|
||||
pidfn = svc->pidfile;
|
||||
if (pidfn[0] == '!')
|
||||
@@ -765,6 +831,8 @@ static int show_status(char *arg)
|
||||
char *group;
|
||||
|
||||
group = pid_cgroup(svc->pid, grbuf, sizeof(grbuf));
|
||||
if (!group)
|
||||
goto no_cgroup; /* ... or PID doesn't exist (anymore) */
|
||||
snprintf(path, sizeof(path), "%s/%s", FINIT_CGPATH, group);
|
||||
cg = cg_conf(path);
|
||||
|
||||
@@ -774,6 +842,7 @@ static int show_status(char *arg)
|
||||
cg->cg_mem.min, cg->cg_mem.max);
|
||||
show_cgroup_tree(group, " ");
|
||||
}
|
||||
no_cgroup:
|
||||
printf("\n");
|
||||
|
||||
return do_log(svc->cmd);
|
||||
@@ -797,7 +866,7 @@ static int show_status(char *arg)
|
||||
char *lvls;
|
||||
|
||||
svc_ident(svc, ident, sizeof(ident));
|
||||
if (num && !string_match(ident, arg))
|
||||
if (num && !string_compare(ident, arg))
|
||||
continue;
|
||||
|
||||
printf("%-*d ", pw, svc->pid);
|
||||
@@ -891,12 +960,13 @@ static int usage(int rc)
|
||||
" -q, --quiet Silent, only return status of command\n"
|
||||
" -t, --no-heading Skip table headings\n"
|
||||
" -v, --verbose Verbose output\n"
|
||||
" -V, --version Show program version\n"
|
||||
" -h, --help This help text\n"
|
||||
"\n"
|
||||
"Commands:\n"
|
||||
" debug Toggle Finit (daemon) debug\n"
|
||||
" help This help text\n"
|
||||
" version Show Finit version\n"
|
||||
" version Show program version\n"
|
||||
"\n", prognm);
|
||||
|
||||
if (has_rcsd)
|
||||
@@ -920,10 +990,10 @@ static int usage(int rc)
|
||||
" disable <CONF> Disable .conf in %s\n", ena);
|
||||
if (has_rcsd)
|
||||
fprintf(stderr,
|
||||
" reload Reload *.conf in " FINIT_RCSD " (activate changes)\n");
|
||||
" reload Reload *.conf in " FINIT_RCSD " (activate changes)\n");
|
||||
else
|
||||
fprintf(stderr,
|
||||
" reload Reload " FINIT_CONF " (activate changes)\n");
|
||||
" reload Reload " FINIT_CONF " (activate changes)\n");
|
||||
|
||||
fprintf(stderr,
|
||||
// " reload <NAME>[:ID] Reload (SIGHUP) service by name\n"
|
||||
@@ -938,6 +1008,7 @@ static int usage(int rc)
|
||||
" stop <NAME>[:ID] Stop/Pause a running service by name\n"
|
||||
" reload <NAME>[:ID] Reload service by name (SIGHUP or restart)\n"
|
||||
" restart <NAME>[:ID] Restart (stop/start) service by name\n"
|
||||
" signal <NAME>[:ID] <S> Send signal S to service by name, with optional ID\n"
|
||||
" ident [NAME] Show matching identities for NAME, or all\n"
|
||||
" status <NAME>[:ID] Show service status, by name\n"
|
||||
" status Show status of services, default command\n");
|
||||
@@ -994,12 +1065,15 @@ static int cmd_parse(int argc, char *argv[], struct cmd *command)
|
||||
if (!cmd_cond(&command[i]))
|
||||
continue;
|
||||
|
||||
if (!string_match(command[i].cmd, argv[0]))
|
||||
if (!string_compare(command[i].cmd, argv[0]))
|
||||
continue;
|
||||
|
||||
if (command[i].ctx)
|
||||
return cmd_parse(argc - 1, &argv[1], command[i].ctx);
|
||||
|
||||
if (command[i].cb_multiarg)
|
||||
return command[i].cb_multiarg(argc - 1, argv + 1);
|
||||
|
||||
if (command[i].cb) {
|
||||
int rc = 0;
|
||||
|
||||
@@ -1018,6 +1092,7 @@ static int cmd_parse(int argc, char *argv[], struct cmd *command)
|
||||
|
||||
return command[0].cb(NULL); /* default cmd */
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct option long_options[] = {
|
||||
@@ -1031,55 +1106,57 @@ int main(int argc, char *argv[])
|
||||
{ "quiet", 0, NULL, 'q' },
|
||||
{ "no-heading", 0, NULL, 't' },
|
||||
{ "verbose", 0, NULL, 'v' },
|
||||
{ "version", 0, NULL, 'V' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
struct cmd cond[] = {
|
||||
{ "status", NULL, do_cond_show, NULL }, /* default cmd */
|
||||
{ "dump", NULL, do_cond_dump, NULL },
|
||||
{ "set", NULL, do_cond_set, NULL },
|
||||
{ "clr", NULL, do_cond_clr, NULL },
|
||||
{ "clear", NULL, do_cond_clr, NULL },
|
||||
{ NULL, NULL, NULL, NULL }
|
||||
{ "status", NULL, do_cond_show, NULL, NULL }, /* default cmd */
|
||||
{ "dump", NULL, do_cond_dump, NULL, NULL },
|
||||
{ "set", NULL, do_cond_set, NULL, NULL },
|
||||
{ "clr", NULL, do_cond_clr, NULL, NULL },
|
||||
{ "clear", NULL, do_cond_clr, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL, NULL }
|
||||
};
|
||||
struct cmd command[] = {
|
||||
{ "status", NULL, show_status, NULL }, /* default cmd */
|
||||
{ "ident", NULL, show_ident, NULL },
|
||||
{ "status", NULL, show_status, NULL, NULL }, /* default cmd */
|
||||
{ "ident", NULL, show_ident, NULL, NULL },
|
||||
|
||||
{ "debug", NULL, toggle_debug, NULL },
|
||||
{ "devel", NULL, do_devel, NULL },
|
||||
{ "help", NULL, do_help, NULL },
|
||||
{ "version", NULL, show_version, NULL },
|
||||
{ "debug", NULL, toggle_debug, NULL, NULL },
|
||||
{ "devel", NULL, do_devel, NULL, NULL },
|
||||
{ "help", NULL, do_help, NULL, NULL },
|
||||
{ "version", NULL, show_version, NULL, NULL },
|
||||
|
||||
{ "list", NULL, serv_list, NULL },
|
||||
{ "ls", NULL, serv_list, NULL },
|
||||
{ "enable", NULL, serv_enable, NULL },
|
||||
{ "disable", NULL, serv_disable, NULL },
|
||||
{ "touch", NULL, serv_touch, NULL },
|
||||
{ "show", NULL, serv_show, NULL },
|
||||
{ "edit", NULL, serv_edit, NULL },
|
||||
{ "create", NULL, serv_creat, NULL },
|
||||
{ "delete", NULL, serv_delete, NULL },
|
||||
{ "reload", NULL, do_reload, NULL },
|
||||
{ "list", NULL, serv_list, NULL, NULL },
|
||||
{ "ls", NULL, serv_list, NULL, NULL },
|
||||
{ "enable", NULL, serv_enable, NULL, NULL },
|
||||
{ "disable", NULL, serv_disable, NULL, NULL },
|
||||
{ "touch", NULL, serv_touch, NULL, NULL },
|
||||
{ "show", NULL, serv_show, NULL, NULL },
|
||||
{ "edit", NULL, serv_edit, NULL, NULL },
|
||||
{ "create", NULL, serv_creat, NULL, NULL },
|
||||
{ "delete", NULL, serv_delete, NULL, NULL },
|
||||
{ "reload", NULL, do_reload, NULL, NULL },
|
||||
|
||||
{ "cond", cond, NULL, NULL },
|
||||
{ "cond", cond, NULL, NULL, NULL },
|
||||
|
||||
{ "log", NULL, do_log, NULL },
|
||||
{ "start", NULL, do_start, NULL },
|
||||
{ "stop", NULL, do_stop, NULL },
|
||||
{ "restart", NULL, do_restart, NULL },
|
||||
{ "log", NULL, do_log, NULL, NULL },
|
||||
{ "start", NULL, do_start, NULL, NULL },
|
||||
{ "stop", NULL, do_stop, NULL, NULL },
|
||||
{ "restart", NULL, do_restart, NULL, NULL },
|
||||
{ "signal", NULL, NULL, NULL, do_signal },
|
||||
|
||||
{ "cgroup", NULL, show_cgroup, &cgrp },
|
||||
{ "ps", NULL, show_cgps, &cgrp },
|
||||
{ "top", NULL, show_cgtop, &cgrp },
|
||||
{ "cgroup", NULL, show_cgroup, &cgrp, NULL },
|
||||
{ "ps", NULL, show_cgps, &cgrp, NULL },
|
||||
{ "top", NULL, show_cgtop, &cgrp, NULL },
|
||||
|
||||
{ "runlevel", NULL, do_runlevel, NULL },
|
||||
{ "reboot", NULL, do_reboot, NULL },
|
||||
{ "halt", NULL, do_halt, NULL },
|
||||
{ "poweroff", NULL, do_poweroff, NULL },
|
||||
{ "suspend", NULL, do_suspend, NULL },
|
||||
{ "runlevel", NULL, do_runlevel, NULL, NULL },
|
||||
{ "reboot", NULL, do_reboot, NULL, NULL },
|
||||
{ "halt", NULL, do_halt, NULL, NULL },
|
||||
{ "poweroff", NULL, do_poweroff, NULL, NULL },
|
||||
{ "suspend", NULL, do_suspend, NULL, NULL },
|
||||
|
||||
{ "utmp", NULL, do_utmp, &utmp },
|
||||
{ NULL, NULL, NULL, NULL }
|
||||
{ "utmp", NULL, do_utmp, &utmp, NULL },
|
||||
{ NULL, NULL, NULL, NULL, NULL }
|
||||
};
|
||||
int interactive = 1, c;
|
||||
|
||||
@@ -1090,7 +1167,7 @@ int main(int argc, char *argv[])
|
||||
cgrp = cgroup_avail();
|
||||
utmp = has_utmp();
|
||||
|
||||
while ((c = getopt_long(argc, argv, "1bcdfh?pqtv", long_options, NULL)) != EOF) {
|
||||
while ((c = getopt_long(argc, argv, "1bcdfh?pqtvV", long_options, NULL)) != EOF) {
|
||||
switch(c) {
|
||||
case '1':
|
||||
ionce = 1;
|
||||
@@ -1131,6 +1208,9 @@ int main(int argc, char *argv[])
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
return show_version(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ extern int heading; /* initctl -t */
|
||||
extern int verbose; /* initctl -v */
|
||||
extern int plain; /* initctl -p */
|
||||
|
||||
extern void print_header(const char *fmt, ...);
|
||||
extern void print_header(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
||||
|
||||
#endif /* FINIT_INITCTL_H_ */
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "iwatch.h"
|
||||
@@ -39,6 +40,9 @@ static int initialized = 0;
|
||||
|
||||
int iwatch_init(struct iwatch *iw)
|
||||
{
|
||||
socklen_t len;
|
||||
int sz;
|
||||
|
||||
if (!iw) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
@@ -51,6 +55,18 @@ int iwatch_init(struct iwatch *iw)
|
||||
_pe("Failed creating inotify descriptor");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Double the size of the socket's receive buffer to address
|
||||
* issues with lost events in some cases, e.g. bootstrap and
|
||||
* reconf of systems with lots of services.
|
||||
*/
|
||||
len = sizeof(sz);
|
||||
if (!getsockopt(iw->fd, SOL_SOCKET, SO_RCVBUF, &sz, &len)) {
|
||||
if (setsockopt(iw->fd, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)))
|
||||
_pe("Failed increasing size of inotify socket");
|
||||
}
|
||||
|
||||
initialized = 1;
|
||||
|
||||
return iw->fd;
|
||||
|
||||
+41
-5
@@ -24,6 +24,7 @@
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
@@ -52,6 +53,10 @@
|
||||
static int num_ac_online;
|
||||
static int num_ac;
|
||||
|
||||
static int running = 1;
|
||||
static int level;
|
||||
static int logon;
|
||||
|
||||
int debug; /* debug in other modules as well */
|
||||
|
||||
void logit(int prio, const char *fmt, ...)
|
||||
@@ -59,9 +64,9 @@ void logit(int prio, const char *fmt, ...)
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
if (!debug)
|
||||
if (logon)
|
||||
vsyslog(prio, fmt, ap);
|
||||
else {
|
||||
else if (prio <= level) {
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
@@ -179,6 +184,26 @@ static void init(void)
|
||||
sys_cond("pwr/ac", 1);
|
||||
}
|
||||
|
||||
static void set_logging(int prio)
|
||||
{
|
||||
setlogmask(LOG_UPTO(prio));
|
||||
level = prio;
|
||||
}
|
||||
|
||||
static void toggle_debug(int signo)
|
||||
{
|
||||
(void)signo;
|
||||
|
||||
debug ^= 1;
|
||||
set_logging(debug ? LOG_DEBUG : LOG_NOTICE);
|
||||
}
|
||||
|
||||
static void shut_down(int signo)
|
||||
{
|
||||
(void)signo;
|
||||
running = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Started by Finit as soon as possible when base filesystem is up,
|
||||
* modules have been probed, or insmodded from /etc/finit.conf, so by
|
||||
@@ -198,10 +223,13 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
if (!debug) {
|
||||
openlog("keventd", LOG_CONS | LOG_PID, LOG_DAEMON);
|
||||
setlogmask(LOG_UPTO(LOG_NOTICE));
|
||||
openlog("keventd", LOG_PID, LOG_DAEMON);
|
||||
set_logging(LOG_NOTICE);
|
||||
logon = 1;
|
||||
}
|
||||
|
||||
signal(SIGUSR1, toggle_debug);
|
||||
signal(SIGTERM, shut_down);
|
||||
init();
|
||||
|
||||
pfd.events = POLLIN;
|
||||
@@ -216,11 +244,18 @@ int main(int argc, char *argv[])
|
||||
panic("bind failed");
|
||||
|
||||
logit(LOG_DEBUG, "Waiting for events ...");
|
||||
while (-1 != poll(&pfd, 1, -1)) {
|
||||
while (running) {
|
||||
char *path = NULL;
|
||||
int ac = 0;
|
||||
int i, len;
|
||||
|
||||
if (-1 == poll(&pfd, 1, -1)) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
len = recv(pfd.fd, buf, sizeof(buf), MSG_DONTWAIT);
|
||||
if (len == -1) {
|
||||
switch (errno) {
|
||||
@@ -235,6 +270,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
buf[len] = 0;
|
||||
logit(LOG_DEBUG, "%s", buf);
|
||||
|
||||
/* skip libusb events, focus on kernel events/changes */
|
||||
if (strncmp(buf, "change@", 7))
|
||||
|
||||
@@ -40,6 +40,8 @@ static int loglevel = LOG_INFO;
|
||||
|
||||
void log_init(void)
|
||||
{
|
||||
ttinit();
|
||||
|
||||
if (debug)
|
||||
loglevel = LOG_DEBUG;
|
||||
else
|
||||
@@ -59,18 +61,29 @@ void log_exit(void)
|
||||
enable_progress(1);
|
||||
}
|
||||
|
||||
static void log_open(void)
|
||||
static int log_open(void)
|
||||
{
|
||||
int opts = LOG_PID;
|
||||
int opts;
|
||||
|
||||
closelog();
|
||||
if (up)
|
||||
return 1;
|
||||
if (access("/dev/log", W_OK))
|
||||
return 0;
|
||||
|
||||
opts = LOG_CONS | LOG_PID;
|
||||
if (debug)
|
||||
opts |= LOG_PERROR; /* LOG_CONS | */
|
||||
opts |= LOG_PERROR;
|
||||
|
||||
openlog("finit", opts, LOG_DAEMON);
|
||||
setlogmask(LOG_UPTO(loglevel));
|
||||
|
||||
up = 1;
|
||||
return up = 1;
|
||||
}
|
||||
|
||||
static void log_close(void)
|
||||
{
|
||||
closelog();
|
||||
up = 0;
|
||||
}
|
||||
|
||||
/* Toggle debug mode */
|
||||
@@ -78,12 +91,8 @@ void log_debug(void)
|
||||
{
|
||||
debug = !debug;
|
||||
|
||||
if (debug) {
|
||||
loglevel = LOG_DEBUG;
|
||||
} else {
|
||||
loglevel = LOG_NOTICE;
|
||||
ttinit();
|
||||
}
|
||||
log_close();
|
||||
log_init();
|
||||
log_open();
|
||||
|
||||
logit(LOG_NOTICE, "Debug mode %s", debug ? "enabled" : "disabled");
|
||||
@@ -95,15 +104,12 @@ void log_debug(void)
|
||||
*/
|
||||
void logit(int prio, const char *fmt, ...)
|
||||
{
|
||||
FILE *fp;
|
||||
va_list ap;
|
||||
FILE *fp;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
if (up || fexist("/dev/log")) {
|
||||
if (!up)
|
||||
log_open();
|
||||
|
||||
if (up || log_open()) {
|
||||
vsyslog(prio, fmt, ap);
|
||||
goto done;
|
||||
}
|
||||
@@ -111,9 +117,9 @@ void logit(int prio, const char *fmt, ...)
|
||||
if (LOG_PRI(prio) > loglevel)
|
||||
goto done;
|
||||
|
||||
fp = fopen("/dev/kmsg", "w");
|
||||
if (!fp) {
|
||||
if (in_container() || !(fp = fopen("/dev/kmsg", "w"))) {
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fputs("\n", stderr);
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -125,6 +131,7 @@ void logit(int prio, const char *fmt, ...)
|
||||
va_end(ap);
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fputs("\n", stderr);
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
@@ -40,17 +40,17 @@
|
||||
* The default log level is LOG_NOTICE. To toggle LOG_DEBUG messages,
|
||||
* use `initctl debug` or add `debug` to the kernel cmdline.
|
||||
*/
|
||||
#define _d(fmt, args...) logit(LOG_DEBUG, "%s():" fmt "\n", __func__, ##args)
|
||||
#define _w(fmt, args...) logit(LOG_WARNING, "%s():" fmt "\n", __func__, ##args)
|
||||
#define _e(fmt, args...) logit(LOG_ERR, "%s():" fmt "\n", __func__, ##args)
|
||||
#define _pe(fmt, args...) logit(LOG_ERR, "%s():" fmt ": %s\n", __func__, ##args, strerror(errno))
|
||||
#define _d(fmt, args...) logit(LOG_DEBUG, "%s():" fmt, __func__, ##args)
|
||||
#define _w(fmt, args...) logit(LOG_WARNING, "%s():" fmt, __func__, ##args)
|
||||
#define _e(fmt, args...) logit(LOG_ERR, "%s():" fmt, __func__, ##args)
|
||||
#define _pe(fmt, args...) logit(LOG_ERR, "%s():" fmt ": %s", __func__, ##args, strerror(errno))
|
||||
|
||||
void log_init (void);
|
||||
void log_exit (void);
|
||||
|
||||
void log_debug (void);
|
||||
|
||||
void logit (int prio, const char *fmt, ...);
|
||||
void flog (char *file, const char *fmt, ...);
|
||||
void logit (int prio, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
void flog (char *file, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
|
||||
#endif /* FINIT_LOG_H_ */
|
||||
|
||||
+19
-2
@@ -21,10 +21,13 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <mntent.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
/*
|
||||
* SysV init on Debian/Ubuntu skips these protected mount points
|
||||
*
|
||||
@@ -86,13 +89,27 @@ static struct mntent *iterator(char *fstab, FILE **fp)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int unmount(const char *target)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = umount(target);
|
||||
if (rc && errno != EBUSY) {
|
||||
print(2, "Failed unmounting %s, error %d: %s", target, errno, strerror(errno));
|
||||
return rc;
|
||||
}
|
||||
print(0, "Unmounting %s", target);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void unmount_tmpfs(void)
|
||||
{
|
||||
struct mntent *mnt;
|
||||
FILE *fp = NULL;
|
||||
|
||||
while ((mnt = iterator("/proc/mounts", &fp))) {
|
||||
if (!strcmp("tmpfs", mnt->mnt_fsname) && !umount(mnt->mnt_dir))
|
||||
if (!strcmp("tmpfs", mnt->mnt_fsname) && !unmount(mnt->mnt_dir))
|
||||
iterator_end(&fp); /* Restart iteration */
|
||||
}
|
||||
}
|
||||
@@ -103,7 +120,7 @@ void unmount_regular(void)
|
||||
FILE *fp = NULL;
|
||||
|
||||
while ((mnt = iterator("/proc/mounts", &fp))) {
|
||||
if (!umount(mnt->mnt_dir))
|
||||
if (!unmount(mnt->mnt_dir))
|
||||
iterator_end(&fp); /* Restart iteration */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,10 +69,11 @@ int pid_alive(pid_t pid)
|
||||
*/
|
||||
char *pid_get_name(pid_t pid, char *name, size_t len)
|
||||
{
|
||||
static char line[64];
|
||||
char *pname = NULL;
|
||||
char path[32];
|
||||
int ret = 1;
|
||||
FILE *fp;
|
||||
char *pname, path[32];
|
||||
static char line[64];
|
||||
|
||||
snprintf(path, sizeof(path), "/proc/%d/status", pid);
|
||||
fp = fopen(path, "r");
|
||||
@@ -113,8 +114,8 @@ char *pid_file(svc_t *svc)
|
||||
pid_t pid_file_read(const char *fn)
|
||||
{
|
||||
pid_t pid = 0;
|
||||
FILE *fp;
|
||||
char buf[42];
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen(fn, "r");
|
||||
if (!fp)
|
||||
@@ -157,6 +158,11 @@ int pid_file_set(svc_t *svc, char *file, int not)
|
||||
file++;
|
||||
}
|
||||
|
||||
if (svc_is_forking(svc) && !not) {
|
||||
logit(LOG_WARNING, "Service %s is forking, adjusting to pid:!%s", svc->name, file);
|
||||
not = 1;
|
||||
}
|
||||
|
||||
pid_runpath(file, &svc->pidfile[not], sizeof(svc->pidfile) - not);
|
||||
if (not)
|
||||
svc->pidfile[0] = '!';
|
||||
@@ -199,8 +205,8 @@ int pid_file_parse(svc_t *svc, char *arg)
|
||||
|
||||
/* 'pid:' implies argument following*/
|
||||
if (!strncmp(arg, "pid:", 4)) {
|
||||
int len, not = 0;
|
||||
char path[MAX_ARG_LEN];
|
||||
int len, not = 0;
|
||||
|
||||
arg += 4;
|
||||
if ((arg[0] == '!' && arg[1] == '/') || arg[0] == '/')
|
||||
|
||||
+4
-10
@@ -98,11 +98,6 @@ static void do_kill(int signo, char *msg)
|
||||
do_sleep(5);
|
||||
}
|
||||
|
||||
static void sig(int signo)
|
||||
{
|
||||
(void)signo; /* NOP */
|
||||
}
|
||||
|
||||
static int usage(int rc)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [OPTIONS]\n\n"
|
||||
@@ -164,10 +159,9 @@ int reboot_main(int argc, char *argv[])
|
||||
/* Check for any overrides */
|
||||
transform(NULL);
|
||||
|
||||
/* Catch and ignore SIGTERM on halt/poweroff */
|
||||
signal(SIGTERM, sig);
|
||||
|
||||
if (force) {
|
||||
sync();
|
||||
|
||||
switch (cmd) {
|
||||
case CMD_REBOOT:
|
||||
c = reboot(RB_AUTOBOOT);
|
||||
@@ -182,9 +176,9 @@ int reboot_main(int argc, char *argv[])
|
||||
break;
|
||||
|
||||
case CMD_SUSPEND:
|
||||
c = reboot(RB_SW_SUSPEND);
|
||||
c = suspend();
|
||||
if (c && errno == EINVAL)
|
||||
errx(1, "Kernel does not support suspend.");
|
||||
errx(1, "Kernel does not support suspend to RAM.");
|
||||
break;
|
||||
|
||||
case CMD_UNKNOWN:
|
||||
|
||||
+31
-1
@@ -34,9 +34,24 @@
|
||||
# include <lite/lite.h>
|
||||
#endif
|
||||
|
||||
#include "client.h"
|
||||
#include "initctl.h"
|
||||
|
||||
|
||||
static int is_builtin(char *arg)
|
||||
{
|
||||
svc_t *svc;
|
||||
|
||||
svc = client_svc_find(arg);
|
||||
if (!svc)
|
||||
return 0;
|
||||
|
||||
if (svc->file[0])
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int calc_width(char *arr[], size_t len)
|
||||
{
|
||||
int width = 0;
|
||||
@@ -292,6 +307,8 @@ int serv_touch(char *arg)
|
||||
if (!fexist(fn)) {
|
||||
if (!strstr(arg, "finit.conf"))
|
||||
errx(1, "%s not available.", arg);
|
||||
if (is_builtin(arg))
|
||||
errx(1, "%s is a built-in service.", arg);
|
||||
|
||||
strlcpy(path, FINIT_CONF, sizeof(path));
|
||||
fn = path;
|
||||
@@ -311,6 +328,9 @@ int serv_show(char *arg)
|
||||
|
||||
fn = conf(path, sizeof(path), arg, 0);
|
||||
if (!fexist(fn)) {
|
||||
if (is_builtin(arg))
|
||||
errx(1, "%s is a built-in service.", arg);
|
||||
|
||||
warnx("Cannot find %s", arg);
|
||||
return 1;
|
||||
}
|
||||
@@ -345,6 +365,9 @@ static int do_edit(char *arg, int creat)
|
||||
|
||||
fn = conf(path, sizeof(path), arg, creat);
|
||||
if (!fexist(fn)) {
|
||||
if (is_builtin(arg))
|
||||
errx(1, "%s is a built-in service.", arg);
|
||||
|
||||
if (!creat) {
|
||||
warnx("Cannot find %s, use -c flag, create command, or select one of:", arg);
|
||||
return serv_list(NULL);
|
||||
@@ -371,6 +394,7 @@ int serv_edit(char *arg)
|
||||
if (!arg || !arg[0]) {
|
||||
if (!yorn("Do you want to edit %s (y/N)? ", FINIT_CONF))
|
||||
return 0;
|
||||
arg = "";
|
||||
}
|
||||
|
||||
return do_edit(arg, icreate);
|
||||
@@ -385,6 +409,9 @@ int serv_creat(char *arg)
|
||||
if (!arg || !arg[0])
|
||||
errx(1, "missing argument to create");
|
||||
|
||||
if (is_builtin(arg))
|
||||
errx(1, "%s is a built-in service.", arg);
|
||||
|
||||
/* Input from a pipe or a proper TTY? */
|
||||
if (isatty(STDIN_FILENO))
|
||||
return do_edit(arg, 1);
|
||||
@@ -420,8 +447,11 @@ int serv_delete(char *arg)
|
||||
}
|
||||
|
||||
fn = conf(buf, sizeof(buf), arg, 0);
|
||||
if (!fn)
|
||||
if (!fn) {
|
||||
if (is_builtin(arg))
|
||||
errx(1, "%s is a built-in service.", arg);
|
||||
errx(1, FINIT_RCSD " missing on system.");
|
||||
}
|
||||
|
||||
if (!fexist(fn))
|
||||
warnx("cannot find %s", fn);
|
||||
|
||||
+116
-30
@@ -558,7 +558,7 @@ static int service_start(svc_t *svc)
|
||||
|
||||
for (i = 0; i < we.we_wordc; i++) {
|
||||
if (strlen(we.we_wordv[i]) >= sizeof(svc->args[i])) {
|
||||
logit(LOG_ERR, "%s: expanded arg. '%s' too long", we.we_wordv[i]);
|
||||
logit(LOG_ERR, "%s: expanded arg. '%s' too long", svc->cmd, we.we_wordv[i]);
|
||||
rc = WRDE_NOSPACE;
|
||||
goto nomem;
|
||||
}
|
||||
@@ -571,6 +571,7 @@ static int service_start(svc_t *svc)
|
||||
} else {
|
||||
i = 0;
|
||||
args[i++] = svc->cmd;
|
||||
args[i++] = svc->cmd;
|
||||
args[i++] = "start";
|
||||
}
|
||||
args[i] = NULL;
|
||||
@@ -628,10 +629,13 @@ static int service_start(svc_t *svc)
|
||||
switch (svc->type) {
|
||||
case SVC_TYPE_RUN:
|
||||
svc->status = complete(svc->cmd, pid);
|
||||
if (WIFEXITED(svc->status) && !WEXITSTATUS(svc->status))
|
||||
if (WIFEXITED(svc->status) && !WEXITSTATUS(svc->status)) {
|
||||
svc->started = 1;
|
||||
result = 0;
|
||||
else
|
||||
} else {
|
||||
svc->started = 0;
|
||||
result = 1;
|
||||
}
|
||||
svc->start_time = svc->pid = 0;
|
||||
svc->once++;
|
||||
svc_set_state(svc, SVC_STOPPING_STATE);
|
||||
@@ -701,7 +705,7 @@ static void service_cleanup(svc_t *svc)
|
||||
utmp_set_dead(svc->pid); /* Set DEAD_PROCESS UTMP entry */
|
||||
|
||||
svc->oldpid = svc->pid;
|
||||
svc->start_time = svc->pid = 0;
|
||||
svc->starting = svc->start_time = svc->pid = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -743,7 +747,13 @@ static int service_stop(svc_t *svc)
|
||||
*/
|
||||
svc_started(svc);
|
||||
|
||||
svc_set_state(svc, SVC_STOPPING_STATE);
|
||||
/*
|
||||
* Verify there's still something there before we send the reaper.
|
||||
*/
|
||||
if (svc->pid > 1 && !pid_alive(svc->pid)) {
|
||||
svc->pid = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!svc->desc[0])
|
||||
do_progress = 0;
|
||||
@@ -755,12 +765,17 @@ static int service_stop(svc_t *svc)
|
||||
if (svc->pid > 1) {
|
||||
/* Kill all children in the same proess group, e.g. logit */
|
||||
rc = kill(-svc->pid, svc->sighalt);
|
||||
_d("kill(-%d, %d) => rc %d", svc->pid, svc->sighalt, rc);
|
||||
_d("kill(-%d, %d) => rc %d, errno %d", svc->pid, svc->sighalt, rc, errno);
|
||||
/* PID lost or forking process never really started */
|
||||
if (rc == -1 && ESRCH == errno)
|
||||
service_cleanup(svc);
|
||||
} else
|
||||
if (rc == -1 && (errno == ESRCH || errno == ENOENT)) {
|
||||
service_cleanup(svc);
|
||||
svc_set_state(svc, SVC_HALTED_STATE);
|
||||
} else
|
||||
svc_set_state(svc, SVC_STOPPING_STATE);
|
||||
} else {
|
||||
service_cleanup(svc);
|
||||
svc_set_state(svc, SVC_HALTED_STATE);
|
||||
}
|
||||
} else {
|
||||
char *args[] = { svc->cmd, "stop", NULL };
|
||||
pid_t pid;
|
||||
@@ -778,7 +793,7 @@ static int service_stop(svc_t *svc)
|
||||
rc = 1;
|
||||
break;
|
||||
default:
|
||||
rc = WEXITSTATUS(complete(svc->cmd, pid));
|
||||
svc_set_state(svc, SVC_STOPPING_STATE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -829,7 +844,7 @@ static int service_restart(svc_t *svc)
|
||||
logit(LOG_CONSOLE | LOG_NOTICE, "Restarting %s[%d], sending SIGHUP ...",
|
||||
svc_ident(svc, NULL, 0), svc->pid);
|
||||
rc = kill(svc->pid, SIGHUP);
|
||||
if (rc == -1 && errno == ESRCH) {
|
||||
if (rc == -1 && (errno == ESRCH || errno == ENOENT)) {
|
||||
/* nobody home, reset internal state machine */
|
||||
lost = svc->pid;
|
||||
} else {
|
||||
@@ -880,7 +895,7 @@ void service_runlevel(int newlevel)
|
||||
sm_set_runlevel(&sm, newlevel);
|
||||
sm_step(&sm);
|
||||
|
||||
if (!rescue && runlevel <= 1)
|
||||
if (!rescue && (runlevel <= 1 || runlevel == 6))
|
||||
networking(0);
|
||||
}
|
||||
|
||||
@@ -916,7 +931,7 @@ static void parse_env(svc_t *svc, char *env)
|
||||
return;
|
||||
|
||||
if (strlen(env) >= sizeof(svc->env)) {
|
||||
_e("%s: env file is too long (>%d chars)", svc->cmd, sizeof(svc->env));
|
||||
_e("%s: env file is too long (>%zu chars)", svc->cmd, sizeof(svc->env));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -940,7 +955,7 @@ static void parse_cgroup(svc_t *svc, char *cgroup)
|
||||
}
|
||||
|
||||
if (strlen(ptr) >= sizeof(svc->cgroup)) {
|
||||
_e("%s: cgroup settings too long (>%d chars)", svc->cmd, sizeof(svc->cgroup));
|
||||
_e("%s: cgroup settings too long (>%zu chars)", svc->cmd, sizeof(svc->cgroup));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -976,7 +991,7 @@ static void parse_killdelay(svc_t *svc, char *delay)
|
||||
static void parse_script(char *type, char *script, char *buf, size_t len)
|
||||
{
|
||||
if (access(script, X_OK))
|
||||
logit(LOG_WARNING, "%s: %s:%s is missing or not executable, skipping.", type, script);
|
||||
logit(LOG_WARNING, "%s:%s is missing or not executable, skipping.", type, script);
|
||||
else
|
||||
strlcpy(buf, script, len);
|
||||
}
|
||||
@@ -1147,7 +1162,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
char *dev = NULL;
|
||||
int respawn = 0;
|
||||
int levels = 0;
|
||||
int manual = 0;
|
||||
int forking = 0, manual = 0;
|
||||
int restart_max = SVC_RESPAWN_MAX;
|
||||
int restart_tmo = 0;
|
||||
unsigned oncrash_action = SVC_ONCRASH_IGNORE;
|
||||
@@ -1206,6 +1221,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
pid = cmd;
|
||||
else if (!strncasecmp(cmd, "name:", 5))
|
||||
name = cmd;
|
||||
else if (!strncasecmp(cmd, "type:forking", 10))
|
||||
forking = 1;
|
||||
else if (!strncasecmp(cmd, "manual:yes", 10))
|
||||
manual = 1;
|
||||
else if (!strncasecmp(cmd, "restart:", 8))
|
||||
@@ -1317,10 +1334,6 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
svc_unblock(svc);
|
||||
}
|
||||
|
||||
/* Decode any optional pid:/optional/path/to/file.pid */
|
||||
if (pid && svc_is_daemon(svc) && pid_file_parse(svc, pid))
|
||||
_e("Invalid 'pid' argument to service: %s", pid);
|
||||
|
||||
if (username) {
|
||||
char *ptr = strchr(username, ':');
|
||||
|
||||
@@ -1398,8 +1411,26 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
parse_env(svc, env);
|
||||
if (file)
|
||||
strlcpy(svc->file, file, sizeof(svc->file));
|
||||
if (respawn)
|
||||
svc->respawn = 1;
|
||||
svc->respawn = respawn;
|
||||
svc->forking = forking;
|
||||
|
||||
/* Decode any (optional) pid:/optional/path/to/file.pid */
|
||||
if (svc_is_daemon(svc) || svc_is_sysv(svc)) {
|
||||
char tmp[sizeof(svc->name) + 6]; /* pid:! + svc->name */
|
||||
|
||||
/* no pid: set, figure out a default to track this svc */
|
||||
if (!pid && forking) {
|
||||
snprintf(tmp, sizeof(tmp), "pid:!%s", svc->name);
|
||||
pid = tmp;
|
||||
logit(LOG_INFO, "%s: forking but no pid:!file set, guessing -> %s", svc->name, tmp);
|
||||
}
|
||||
|
||||
if (pid && pid_file_parse(svc, pid))
|
||||
logit(LOG_WARNING, "%s: service has invalid 'pid:' config: %s", svc->name, pid);
|
||||
|
||||
if (svc->pidfile[0] == '!')
|
||||
svc->forking = 1;
|
||||
}
|
||||
|
||||
/* Set configured limits */
|
||||
memcpy(svc->rlimit, rlimit, sizeof(svc->rlimit));
|
||||
@@ -1478,8 +1509,10 @@ void service_monitor(pid_t lost, int status)
|
||||
}
|
||||
|
||||
/* Forking sysv/services declare themselves with pid:!/path/to/pid.file */
|
||||
if (svc_is_starting(svc) && svc_is_forking(svc))
|
||||
if (svc_is_starting(svc) && svc_is_forking(svc)) {
|
||||
svc->pid = 0; /* Expect no more activity from this one */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Terminate any children in the same proess group, e.g. logit */
|
||||
kill(-svc->pid, SIGKILL);
|
||||
@@ -1548,6 +1581,33 @@ static void service_kill_script(svc_t *svc)
|
||||
kill(-svc->pid, SIGKILL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Shared env vars for both pre: and post: scripts
|
||||
*/
|
||||
static void set_pre_post_envs(svc_t *svc, const char *type)
|
||||
{
|
||||
char buf[25 + 256] = "/etc/default:/etc/conf.d";
|
||||
const char *fn = svc_getenv(svc);
|
||||
const char *exist = "0";
|
||||
|
||||
setenv("SERVICE_TYPE", svc_typestr(svc), 1);
|
||||
setenv("SERVICE_IDENT", svc_ident(svc, NULL, 0), 1);
|
||||
setenv("SERVICE_SCRIPT_TYPE", type, 1);
|
||||
|
||||
if (fn) {
|
||||
setenv("SERVICE_ENV_FILE", fn, 1);
|
||||
if (!access(fn, R_OK))
|
||||
exist = "1";
|
||||
}
|
||||
setenv("SERVICE_ENV_FILE_EXIST", exist, 1);
|
||||
|
||||
#ifdef FINIT_SYSCONFIG
|
||||
strlcat(buf, ":", sizeof(buf));
|
||||
strlcat(buf, FINIT_SYSCONFIG, sizeof(buf));
|
||||
#endif
|
||||
setenv("SERVICE_CONF_DIR", buf, 1);
|
||||
}
|
||||
|
||||
static void service_pre_script(svc_t *svc)
|
||||
{
|
||||
svc->pid = service_fork(svc);
|
||||
@@ -1564,7 +1624,7 @@ static void service_pre_script(svc_t *svc)
|
||||
NULL
|
||||
};
|
||||
|
||||
setenv("SERVICE_IDENT", svc_ident(svc, NULL, 0), 1);
|
||||
set_pre_post_envs(svc, "pre");
|
||||
execvp(_PATH_BSHELL, argv);
|
||||
_exit(EX_OSERR);
|
||||
}
|
||||
@@ -1593,7 +1653,7 @@ static void service_post_script(svc_t *svc)
|
||||
rc = WEXITSTATUS(svc->status);
|
||||
sig = WTERMSIG(svc->status);
|
||||
|
||||
setenv("SERVICE_IDENT", svc_ident(svc, NULL, 0), 1);
|
||||
set_pre_post_envs(svc, "post");
|
||||
|
||||
if (WIFEXITED(svc->status)) {
|
||||
char val[4];
|
||||
@@ -1621,7 +1681,7 @@ static void service_retry(svc_t *svc)
|
||||
|
||||
service_timeout_cancel(svc);
|
||||
if (svc->respawn) {
|
||||
_d("%s crashed, respawning ...", svc->cmd);
|
||||
_d("%s crashed/exited, respawning ...", svc->cmd);
|
||||
svc_unblock(svc);
|
||||
service_step(svc);
|
||||
return;
|
||||
@@ -1677,6 +1737,27 @@ static void svc_set_state(svc_t *svc, svc_state_t new)
|
||||
service_timeout_cancel(svc);
|
||||
service_timeout_after(svc, svc->killdelay, service_kill);
|
||||
}
|
||||
|
||||
if (svc_is_runtask(svc)) {
|
||||
char success[MAX_COND_LEN], failure[MAX_COND_LEN];
|
||||
|
||||
snprintf(success, sizeof(success), "%s/%s/success", svc_typestr(svc), svc->name);
|
||||
snprintf(failure, sizeof(failure), "%s/%s/failure", svc_typestr(svc), svc->name);
|
||||
|
||||
/* create success/failure condition when entering SVC_DONE_STATE. */
|
||||
if (*state == SVC_DONE_STATE) {
|
||||
if (svc->started)
|
||||
cond_set_oneshot(success);
|
||||
else
|
||||
cond_set_oneshot(failure);
|
||||
}
|
||||
|
||||
/* clear all conditions when entering SVC_HALTED_STATE. */
|
||||
if (*state == SVC_HALTED_STATE) {
|
||||
cond_clear(success);
|
||||
cond_clear(failure);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1719,14 +1800,15 @@ restart:
|
||||
|
||||
case SVC_STOPPING_STATE:
|
||||
if (!svc->pid) {
|
||||
char cond[MAX_COND_LEN];
|
||||
char condstr[MAX_COND_LEN];
|
||||
|
||||
_d("%s: stopped, cleaning up timers and conditions ...", svc->cmd);
|
||||
service_timeout_cancel(svc);
|
||||
cond_clear(mkcond(svc, cond, sizeof(cond)));
|
||||
cond_clear(mkcond(svc, condstr, sizeof(condstr)));
|
||||
|
||||
switch (svc->type) {
|
||||
case SVC_TYPE_SERVICE:
|
||||
case SVC_TYPE_SYSV:
|
||||
case SVC_TYPE_TTY:
|
||||
if (svc_has_post(svc)) {
|
||||
svc_set_state(svc, SVC_CLEANUP_STATE);
|
||||
@@ -1737,7 +1819,6 @@ restart:
|
||||
|
||||
case SVC_TYPE_TASK:
|
||||
case SVC_TYPE_RUN:
|
||||
case SVC_TYPE_SYSV:
|
||||
svc_set_state(svc, SVC_DONE_STATE);
|
||||
break;
|
||||
|
||||
@@ -1790,6 +1871,9 @@ restart:
|
||||
|
||||
if (!svc->pid) {
|
||||
if (svc_is_daemon(svc) || svc_is_tty(svc)) {
|
||||
if (svc_is_forking(svc))
|
||||
break;
|
||||
|
||||
svc_restarting(svc);
|
||||
svc_set_state(svc, SVC_HALTED_STATE);
|
||||
|
||||
@@ -1797,7 +1881,8 @@ restart:
|
||||
* Restart directly after the first crash,
|
||||
* then retry after 2 sec
|
||||
*/
|
||||
_d("delayed restart of %s", svc->cmd);
|
||||
if (!svc->respawn)
|
||||
_d("delayed restart of %s", svc->cmd);
|
||||
service_timeout_after(svc, 1, service_retry);
|
||||
break;
|
||||
}
|
||||
@@ -1813,6 +1898,7 @@ restart:
|
||||
break;
|
||||
}
|
||||
}
|
||||
service_timeout_cancel(svc);
|
||||
|
||||
cond = cond_get_agg(svc->cond);
|
||||
switch (cond) {
|
||||
|
||||
@@ -71,6 +71,7 @@
|
||||
|
||||
#include <dirent.h>
|
||||
#include <string.h> /* strerror() */
|
||||
#include <sched.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/wait.h>
|
||||
#ifdef _LIBITE_LITE
|
||||
@@ -172,7 +173,7 @@ void unmount_regular(void);
|
||||
*
|
||||
* https://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons/
|
||||
*/
|
||||
void do_kill(int signo)
|
||||
void do_iterate_proc(int (*cb)(int, void *), void *data)
|
||||
{
|
||||
DIR *dirp;
|
||||
|
||||
@@ -191,6 +192,8 @@ void do_kill(int signo)
|
||||
pid = atoi(d->d_name);
|
||||
if (!pid)
|
||||
continue;
|
||||
if (pid == 1)
|
||||
continue;
|
||||
|
||||
snprintf(file, sizeof(file), "/proc/%s/cmdline", d->d_name);
|
||||
fp = fopen(file, "r");
|
||||
@@ -203,7 +206,11 @@ void do_kill(int signo)
|
||||
else if (file[0] == '@')
|
||||
_d("Skipping %s ...", &file[1]);
|
||||
else
|
||||
kill(pid, signo);
|
||||
if (cb(pid, data)) {
|
||||
_d("PID %d is still alive (%s)", pid, file);
|
||||
fclose(fp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
@@ -211,8 +218,61 @@ void do_kill(int signo)
|
||||
}
|
||||
}
|
||||
|
||||
static int kill_cb(int pid, void *data)
|
||||
{
|
||||
int signo = *(int *)data;
|
||||
|
||||
kill(pid, signo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int status_cb(int pid, void *data)
|
||||
{
|
||||
int *has_proc = (int *)data;
|
||||
|
||||
*has_proc = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* return value:
|
||||
* 1 - at least one process remaining
|
||||
* 0 - no processes remaining
|
||||
*/
|
||||
static int do_wait(int secs)
|
||||
{
|
||||
const int delay = 250000;
|
||||
int iterations = secs * 1000 * 1000 / delay;
|
||||
int has_proc;
|
||||
|
||||
do {
|
||||
do_usleep(delay);
|
||||
while (waitpid(-1, NULL, WNOHANG) > 0)
|
||||
;
|
||||
has_proc = 0;
|
||||
iterations--;
|
||||
do_iterate_proc(status_cb, &has_proc);
|
||||
}
|
||||
while (has_proc && iterations > 0);
|
||||
|
||||
return has_proc;
|
||||
}
|
||||
|
||||
void do_shutdown(shutop_t op)
|
||||
{
|
||||
struct sched_param sched_param = { .sched_priority = 99 };
|
||||
int in_cont = in_container();
|
||||
int signo = SIGTERM;
|
||||
|
||||
if (!in_cont) {
|
||||
/*
|
||||
* On a PREEMPT-RT system, Finit must run as the highest prioritized
|
||||
* RT process to ensure it completes the shutdown sequence.
|
||||
*/
|
||||
sched_setscheduler(1, SCHED_RR, &sched_param);
|
||||
}
|
||||
|
||||
if (sdown)
|
||||
run_interactive(sdown, "Calling shutdown hook: %s", sdown);
|
||||
|
||||
@@ -223,9 +283,11 @@ void do_shutdown(shutop_t op)
|
||||
* Tell remaining non-monitored processes to exit, give them
|
||||
* time to exit gracefully, 2 sec was customary, we go for 1.
|
||||
*/
|
||||
do_kill(SIGTERM);
|
||||
do_sleep(1);
|
||||
do_kill(SIGKILL);
|
||||
do_iterate_proc(kill_cb, &signo);
|
||||
if (do_wait(1)) {
|
||||
signo = SIGKILL;
|
||||
do_iterate_proc(kill_cb, &signo);
|
||||
}
|
||||
|
||||
/* Exit plugins and API gracefully */
|
||||
plugin_exit();
|
||||
@@ -235,6 +297,12 @@ void do_shutdown(shutop_t op)
|
||||
while (waitpid(-1, NULL, WNOHANG) > 0)
|
||||
;
|
||||
|
||||
if (in_cont) {
|
||||
if (osheading)
|
||||
logit(LOG_CONSOLE | LOG_NOTICE, "%s, shutting down container.", osheading);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
/* Close all local non-console descriptors */
|
||||
for (int fd = 3; fd < 128; fd++)
|
||||
close(fd);
|
||||
@@ -255,16 +323,22 @@ void do_shutdown(shutop_t op)
|
||||
|
||||
/* Unmount any tmpfs before unmounting swap ... */
|
||||
unmount_tmpfs();
|
||||
run("swapoff -e -a");
|
||||
if (whichp("swapoff"))
|
||||
run_interactive("swapoff -a", "Disabling system swap");
|
||||
|
||||
/* ... unmount remaining regular file systems. */
|
||||
unmount_regular();
|
||||
|
||||
/* We sit on / so we must remount it ro, try all the things! */
|
||||
/*
|
||||
* We sit on / so we must remount it ro, try all the things!
|
||||
* See the following links for details:
|
||||
* - https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=339023
|
||||
* - https://bugs.launchpad.net/ubuntu/+source/util-linux/+bug/29187
|
||||
*/
|
||||
sync();
|
||||
run("mount -n -o remount,ro -t dummytype dummydev /");
|
||||
run("mount -n -o remount,ro dummydev /");
|
||||
run("mount -n -o remount,ro /");
|
||||
run("mount -n -o remount,ro -t dummytype dummydev /", NULL);
|
||||
run("mount -n -o remount,ro dummydev /", NULL);
|
||||
run("mount -n -o remount,ro /", "mount");
|
||||
|
||||
/* Call mdadm to mark any RAID array(s) as clean before halting. */
|
||||
mdadm_wait();
|
||||
|
||||
@@ -256,7 +256,7 @@ svc_t *svc_named_iterator(svc_t **iter, int first, char *cmd)
|
||||
for (svc = svc_iterator(iter, first); svc; svc = svc_iterator(iter, 0)) {
|
||||
char *name = svc->name;
|
||||
|
||||
if (!strncmp(name, cmd, strlen(name)))
|
||||
if (string_compare(name, cmd))
|
||||
return svc;
|
||||
}
|
||||
|
||||
@@ -473,23 +473,23 @@ svc_t *svc_find_by_pidfile(char *fn)
|
||||
pid_t pid;
|
||||
|
||||
pid = pid_file_read(fn);
|
||||
if (pid <= 0) {
|
||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||
int v = 0;
|
||||
|
||||
if (svc->pidfile[0] == '!')
|
||||
v = 1;
|
||||
if (strcmp(&svc->pidfile[v], fn))
|
||||
continue;
|
||||
|
||||
if (pid > 1) {
|
||||
svc = svc_find_by_pid(pid);
|
||||
if (svc)
|
||||
return svc;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* No PID in file, or a sysv service. So it has probably forked
|
||||
* off a chiled that we don't know about. See if we can match
|
||||
* the PID file to a service instead.
|
||||
*/
|
||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||
if (svc->pid != pid)
|
||||
int v = 0;
|
||||
|
||||
if (svc->pidfile[0] == '!')
|
||||
v = 1;
|
||||
if (strcmp(&svc->pidfile[v], fn))
|
||||
continue;
|
||||
|
||||
return svc;
|
||||
@@ -650,7 +650,7 @@ static char *tokstr(char *str, size_t len)
|
||||
/*
|
||||
* Used by api.c (to start/stop/restart) and initctl.c (for input validation)
|
||||
*/
|
||||
int svc_parse_jobstr(char *str, size_t len, int (*found)(svc_t *), int (not_found)(char *, char *))
|
||||
int svc_parse_jobstr(char *str, size_t len, void *user_data, int (*found)(svc_t *, void *), int (not_found)(char *, char *, void *))
|
||||
{
|
||||
char *input, *token;
|
||||
int result = 0;
|
||||
@@ -686,11 +686,11 @@ int svc_parse_jobstr(char *str, size_t len, int (*found)(svc_t *), int (not_foun
|
||||
if (!ptr) {
|
||||
svc = svc_job_iterator(&iter, 1, job);
|
||||
if (!svc && not_found)
|
||||
result += not_found(NULL, token);
|
||||
result += not_found(NULL, token, user_data);
|
||||
|
||||
while (svc) {
|
||||
if (found)
|
||||
result += found(svc);
|
||||
result += found(svc, user_data);
|
||||
svc = svc_job_iterator(&iter, 0, job);
|
||||
}
|
||||
} else {
|
||||
@@ -699,19 +699,19 @@ int svc_parse_jobstr(char *str, size_t len, int (*found)(svc_t *), int (not_foun
|
||||
|
||||
svc = svc_find_by_jobid(job, id);
|
||||
if (!svc && not_found)
|
||||
result += not_found(token, id);
|
||||
result += not_found(token, id, user_data);
|
||||
else if (found)
|
||||
result += found(svc);
|
||||
result += found(svc, user_data);
|
||||
}
|
||||
} else {
|
||||
if (!ptr) {
|
||||
svc = svc_named_iterator(&iter, 1, token);
|
||||
if (!svc && not_found)
|
||||
result += not_found(token, id);
|
||||
result += not_found(token, id, user_data);
|
||||
|
||||
while (svc) {
|
||||
if (found)
|
||||
result += found(svc);
|
||||
result += found(svc, user_data);
|
||||
svc = svc_named_iterator(&iter, 0, token);
|
||||
}
|
||||
} else {
|
||||
@@ -720,9 +720,9 @@ int svc_parse_jobstr(char *str, size_t len, int (*found)(svc_t *), int (not_foun
|
||||
|
||||
svc = svc_find_by_nameid(token, id);
|
||||
if (!svc && not_found)
|
||||
result += not_found(token, id);
|
||||
result += not_found(token, id, user_data);
|
||||
else if (found)
|
||||
result += found(svc);
|
||||
result += found(svc, user_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -127,6 +127,7 @@ typedef struct svc {
|
||||
int starting; /* ... waiting for pidfile to be re-asserted */
|
||||
int runlevels;
|
||||
int sighup; /* This service supports SIGHUP :) */
|
||||
int forking; /* This is a service/sysv daemon that forks, wait for it ... */
|
||||
svc_block_t block; /* Reason that this service is currently stopped */
|
||||
char cond[MAX_COND_LEN];
|
||||
|
||||
@@ -222,13 +223,13 @@ void svc_prune_bootstrap (void);
|
||||
void svc_enable (svc_t *svc);
|
||||
int svc_enabled (svc_t *svc);
|
||||
|
||||
int svc_parse_jobstr (char *str, size_t len, int (*found)(svc_t *), int (not_found)(char *, char *));
|
||||
int svc_parse_jobstr (char *str, size_t len, void *user_data, int (*found)(svc_t *, void *), int (not_found)(char *, char *, void *));
|
||||
|
||||
static inline int svc_is_daemon (svc_t *svc) { return svc && SVC_TYPE_SERVICE == svc->type; }
|
||||
static inline int svc_is_sysv (svc_t *svc) { return svc && SVC_TYPE_SYSV == svc->type; }
|
||||
static inline int svc_is_tty (svc_t *svc) { return svc && SVC_TYPE_TTY == svc->type; }
|
||||
static inline int svc_is_runtask (svc_t *svc) { return svc && (SVC_TYPE_RUNTASK & svc->type);}
|
||||
static inline int svc_is_forking (svc_t *svc) { return (svc_is_daemon(svc) || svc_is_sysv(svc)) && svc->pidfile[0] == '!'; }
|
||||
static inline int svc_is_forking (svc_t *svc) { return svc && svc->forking; }
|
||||
|
||||
static inline int svc_in_runlevel (svc_t *svc, int runlevel) { return svc && ISSET(svc->runlevels, runlevel); }
|
||||
static inline int svc_nohup (svc_t *svc) { return svc && (0 == svc->sighup || 0 != svc->args_dirty); }
|
||||
@@ -278,6 +279,31 @@ static inline int svc_has_cond(svc_t *svc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline const char *svc_typestr(svc_t *svc)
|
||||
{
|
||||
switch (svc->type) {
|
||||
case SVC_TYPE_FREE:
|
||||
return "free";
|
||||
|
||||
case SVC_TYPE_SERVICE:
|
||||
return "service";
|
||||
|
||||
case SVC_TYPE_TASK:
|
||||
return "task";
|
||||
|
||||
case SVC_TYPE_RUN:
|
||||
return "run";
|
||||
|
||||
case SVC_TYPE_TTY:
|
||||
return "tty";
|
||||
|
||||
case SVC_TYPE_SYSV:
|
||||
return "sysv";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
static inline char *svc_status(svc_t *svc)
|
||||
{
|
||||
if (!svc)
|
||||
@@ -307,7 +333,10 @@ static inline char *svc_status(svc_t *svc)
|
||||
return "unknown";
|
||||
|
||||
case SVC_DONE_STATE:
|
||||
return "done";
|
||||
if (svc->started)
|
||||
return "done";
|
||||
else
|
||||
return "failed";
|
||||
|
||||
case SVC_STOPPING_STATE:
|
||||
switch (svc->type) {
|
||||
|
||||
+74
-4
@@ -224,7 +224,7 @@ int fngetint(char *path, int *val)
|
||||
{
|
||||
char buf[64];
|
||||
|
||||
if (fnread(buf, sizeof(buf), path) <= 0)
|
||||
if (fnread(buf, sizeof(buf), "%s", path) <= 0)
|
||||
return -1;
|
||||
|
||||
errno = 0;
|
||||
@@ -235,6 +235,40 @@ int fngetint(char *path, int *val)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a replacement for the non-working reboot(RB_SW_SUSPEND). It
|
||||
* checks for suspend to RAM support, assuming `mem_sleep` has a sane
|
||||
* default, e.g. 'deep' or 's2idle'. The latter should be possible to
|
||||
* select from finit.conf, but for now we go with the kernel default.
|
||||
* For more information on kernel sleep states, see:
|
||||
* https://www.kernel.org/doc/html/latest/admin-guide/pm/sleep-states.html
|
||||
*/
|
||||
int suspend(void)
|
||||
{
|
||||
char buf[80];
|
||||
char *ptr;
|
||||
|
||||
if (fnread(buf, sizeof(buf), "/sys/power/state") <= 0) {
|
||||
opnotsup:
|
||||
errno = EINVAL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
chomp(buf);
|
||||
|
||||
ptr = strtok(buf, " ");
|
||||
while (ptr) {
|
||||
if (!strcmp(ptr, "mem"))
|
||||
break;
|
||||
|
||||
ptr = strtok(NULL, " ");
|
||||
}
|
||||
if (!ptr)
|
||||
goto opnotsup;
|
||||
|
||||
return fnwrite("mem", "/sys/power/state");
|
||||
}
|
||||
|
||||
int strtobytes(char *arg)
|
||||
{
|
||||
int mod = 0, bytes;
|
||||
@@ -264,17 +298,39 @@ int strtobytes(char *arg)
|
||||
return bytes;
|
||||
}
|
||||
|
||||
char *sig2str(int sig)
|
||||
char *sig2str(int signo)
|
||||
{
|
||||
static char signame[8];
|
||||
|
||||
if (sig < 1 || sig >= (int)NELEMS(signames))
|
||||
if (signo < 1 || signo >= (int)NELEMS(signames))
|
||||
return "";
|
||||
|
||||
snprintf(signame, sizeof(signame), "/%s", signames[sig]);
|
||||
snprintf(signame, sizeof(signame), "/%s", signames[signo]);
|
||||
return signame;
|
||||
}
|
||||
|
||||
/**
|
||||
* str2sig - Translate signal name to the corresponding signal number.
|
||||
* @sig: The name of the signal
|
||||
*
|
||||
* A signal can be a complete signal name such as "SIGHUP", or
|
||||
* it can be the shortest unique name, such as "HUP" (no SIG prefix).
|
||||
*/
|
||||
int str2sig(char *sig)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!strncasecmp(sig, "SIG", 3))
|
||||
sig += 3;
|
||||
|
||||
for (i = 1; i < NELEMS(signames); ++i) {
|
||||
if (strcasecmp(sig, signames[i]) == 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *code2str(int code)
|
||||
{
|
||||
static char codename[20];
|
||||
@@ -297,6 +353,20 @@ void do_sleep(unsigned int sec)
|
||||
;
|
||||
}
|
||||
|
||||
void do_usleep(unsigned int usec)
|
||||
{
|
||||
struct timespec deadline;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &deadline);
|
||||
|
||||
deadline.tv_nsec += usec * 1000;
|
||||
deadline.tv_sec += deadline.tv_nsec / 1000000000;
|
||||
deadline.tv_nsec = deadline.tv_nsec % 1000000000;
|
||||
|
||||
while (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &deadline, NULL) != 0 && errno == EINTR)
|
||||
;
|
||||
}
|
||||
|
||||
/* Seconds since boot, from sysinfo() */
|
||||
long jiffies(void)
|
||||
{
|
||||
|
||||
+8
-4
@@ -54,16 +54,20 @@ extern char *prognm;
|
||||
|
||||
char *progname (char *arg0);
|
||||
|
||||
char *str (char *fmt, ...);
|
||||
int fnread (char *buf, size_t len, char *fmt, ...);
|
||||
int fnwrite (char *value, char *fmt, ...);
|
||||
char *str (char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
||||
int fnread (char *buf, size_t len, char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
|
||||
int fnwrite (char *value, char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
int fngetint (char *path, int *val);
|
||||
|
||||
int suspend (void);
|
||||
|
||||
int strtobytes (char *arg);
|
||||
char *sig2str (int sig);
|
||||
int str2sig (char *sig);
|
||||
char *code2str (int code);
|
||||
|
||||
void do_sleep (unsigned int sec);
|
||||
void do_usleep (unsigned int usec);
|
||||
long jiffies (void);
|
||||
char *uptime (long secs, char *buf, size_t len);
|
||||
char *memsz (uint64_t sz, char *buf, size_t len);
|
||||
@@ -83,7 +87,7 @@ int ttcooked (void);
|
||||
#define ttcooked() 0
|
||||
#endif
|
||||
|
||||
static inline void dbg(char *fmt, ...)
|
||||
static __attribute__ ((format (printf, 1, 2))) inline void dbg(char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
|
||||
+25
-4
@@ -1,12 +1,29 @@
|
||||
EXTRA_DIST = tenv/lib.sh tenv/exec.sh tenv/start.sh
|
||||
EXTRA_DIST += tenv/root.mk tenv/busybox-x86_64.md5
|
||||
EXTRA_DIST += tenv/chrootsetup.sh
|
||||
SUBDIRS = common tenv
|
||||
|
||||
EXTRA_DIST = skel/bin/busybox-x86_64.md5 skel/sbin/service.sh skel/bin/slay \
|
||||
skel/cdrom/.empty skel/dev/shm/.empty skel/dev/pts/.empty \
|
||||
skel/etc/inittab skel/etc/hostname skel/etc/fstab \
|
||||
skel/etc/init.d/rcS skel/etc/init.d/rcK skel/tmp/.empty \
|
||||
skel/etc/init.d/S01-service.sh skel/home/.empty \
|
||||
skel/proc/.empty skel/root/.empty skel/run/.empty \
|
||||
skel/sbin/chrootsetup.sh skel/srv/.empty skel/sys/.empty \
|
||||
skel/usr/bin/.empty skel/usr/lib/.empty skel/usr/sbin/.empty \
|
||||
skel/usr/games/.empty skel/usr/src/.empty \
|
||||
skel/usr/share/.empty skel/usr/include/.empty \
|
||||
skel/usr/local/games/.empty skel/usr/local/sbin/.empty \
|
||||
skel/usr/local/share/.empty skel/usr/local/src/.empty \
|
||||
skel/usr/local/lib/.empty skel/usr/local/bin/.empty \
|
||||
skel/usr/local/etc/.empty skel/var/.empty
|
||||
|
||||
EXTRA_DIST += setup-root.sh
|
||||
EXTRA_DIST += common/service.conf common/service.sh
|
||||
EXTRA_DIST += add-remove-dynamic-service.sh
|
||||
EXTRA_DIST += add-remove-dynamic-service-sub-config.sh
|
||||
EXTRA_DIST += start-stop-service.sh
|
||||
EXTRA_DIST += start-stop-service-sub-config.sh
|
||||
EXTRA_DIST += start-kill-service.sh
|
||||
EXTRA_DIST += start-stop-sysv.sh
|
||||
EXTRA_DIST += start-stop-serv.sh
|
||||
EXTRA_DIST += signal-service.sh
|
||||
|
||||
AM_TESTS_ENVIRONMENT = TENV_ROOT='$(abs_builddir)/tenv-root/';
|
||||
AM_TESTS_ENVIRONMENT += export TENV_ROOT;
|
||||
@@ -26,6 +43,10 @@ TESTS += add-remove-dynamic-service.sh
|
||||
TESTS += add-remove-dynamic-service-sub-config.sh
|
||||
TESTS += start-stop-service.sh
|
||||
TESTS += start-stop-service-sub-config.sh
|
||||
TESTS += start-kill-service.sh
|
||||
TESTS += start-stop-sysv.sh
|
||||
TESTS += start-stop-serv.sh
|
||||
TESTS += signal-service.sh
|
||||
|
||||
clean-local:
|
||||
-rm -rf $(builddir)/tenv-root/
|
||||
|
||||
+14
-3
@@ -1,5 +1,5 @@
|
||||
Tests
|
||||
=====
|
||||
Finit Test Suite
|
||||
================
|
||||
|
||||
Finit comes with a set of tests and a small framework for running them.
|
||||
Contributors are encouraged to write new tests when implementing features, or
|
||||
@@ -10,10 +10,16 @@ be able to be launched as PID 1. Since it's also running with it's own root
|
||||
directory it will be able to function properly without having any super user
|
||||
privileges in the host environment.
|
||||
|
||||
|
||||
Running tests
|
||||
-------------
|
||||
|
||||
To run the test suite, first [build](../doc/build.md) Finit - then simply run:
|
||||
To run the test suite, first [build](../doc/build.md) Finit, e.g:
|
||||
|
||||
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var
|
||||
make -j9 clean all
|
||||
|
||||
Then run (parallel does not work atm):
|
||||
|
||||
make check
|
||||
|
||||
@@ -24,3 +30,8 @@ test suite, which is handy when developing new tests or debugging existing
|
||||
test. To execute an individual test, simply invoke the script containing it:
|
||||
|
||||
./test/name-of-the-test.sh
|
||||
|
||||
Another way to run a single (or more) test(s) is to define the `TESTS`
|
||||
environment variable:
|
||||
|
||||
TESTS="start-kill-service" make check
|
||||
|
||||
@@ -7,20 +7,18 @@ TEST_DIR=$(dirname "$0")
|
||||
# shellcheck source=/dev/null
|
||||
. "$TEST_DIR/tenv/lib.sh"
|
||||
|
||||
test_teardown() {
|
||||
say "Test done $(date)"
|
||||
say "Running test teardown."
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Running test teardown."
|
||||
|
||||
texec rm -f "$FINIT_RCSD/service.conf"
|
||||
texec rm -f /test_assets/service.sh
|
||||
texec rm -f "$FINIT_RCSD/service.conf"
|
||||
}
|
||||
|
||||
say "Test start $(date)"
|
||||
|
||||
cp "$TEST_DIR"/common/service.sh "$TENV_ROOT"/test_assets/
|
||||
|
||||
say "Add a dynamic service in $FINIT_RCSD/service.conf"
|
||||
texec sh -c "echo 'service [2345] kill:20 log /test_assets/service.sh' > $FINIT_RCSD/service.conf"
|
||||
texec sh -c "echo 'service [2345] kill:20 log service.sh -- Dyn serv' > $FINIT_RCSD/service.conf"
|
||||
|
||||
say 'Reload Finit'
|
||||
texec sh -c "initctl reload"
|
||||
|
||||
@@ -7,20 +7,18 @@ TEST_DIR=$(dirname "$0")
|
||||
# shellcheck source=/dev/null
|
||||
. "$TEST_DIR/tenv/lib.sh"
|
||||
|
||||
test_teardown() {
|
||||
say "Test done $(date)"
|
||||
say "Running test teardown."
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Running test teardown."
|
||||
|
||||
texec rm -f "$FINIT_CONF"
|
||||
texec rm -f /test_assets/service.sh
|
||||
texec rm -f "$FINIT_CONF"
|
||||
}
|
||||
|
||||
say "Test start $(date)"
|
||||
|
||||
cp "$TEST_DIR"/common/service.sh "$TENV_ROOT"/test_assets/
|
||||
|
||||
say "Add a dynamic service in $FINIT_CONF"
|
||||
texec sh -c "echo 'service [2345] kill:20 log /test_assets/service.sh' > $FINIT_CONF"
|
||||
texec sh -c "echo 'service [2345] kill:20 log service.sh -- Dyn service' > $FINIT_CONF"
|
||||
|
||||
say 'Reload Finit'
|
||||
texec sh -c "initctl reload"
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
/Makefile
|
||||
/Makefile.in
|
||||
|
||||
/.deps/
|
||||
/serv
|
||||
@@ -0,0 +1,2 @@
|
||||
noinst_PROGRAMS = serv
|
||||
serv_SOURCES = serv.c
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Basic UNIX daemon
|
||||
*
|
||||
* Options to run in foreground and to create a PID file. When running
|
||||
* in foregrund it does not create a PID file by default.
|
||||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <paths.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define PROGNM "serv"
|
||||
|
||||
static void sig(int signo)
|
||||
{
|
||||
warnx("We got signal %d ...", signo);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void pidfile(char *pidfn)
|
||||
{
|
||||
char fn[80];
|
||||
pid_t pid;
|
||||
FILE *fp;
|
||||
|
||||
if (!pidfn) {
|
||||
snprintf(fn, sizeof(fn), "%s%s.pid", _PATH_VARRUN, PROGNM);
|
||||
pidfn = fn;
|
||||
}
|
||||
pid = getpid();
|
||||
warnx("Creating PID file %s with %d", pidfn, pid);
|
||||
|
||||
fp = fopen(pidfn, "w");
|
||||
if (!fp)
|
||||
exit(1);
|
||||
fprintf(fp, "%d\n", pid);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
static int usage(int rc)
|
||||
{
|
||||
FILE *fp = rc ? stderr : stdout;
|
||||
|
||||
fprintf(fp,
|
||||
"%s [-nhp] [-P FILE]\n"
|
||||
"\n"
|
||||
" -n Run in foreground\n"
|
||||
" -h Show help text (this)\n"
|
||||
" -p Create PID file despite running in foreground\n"
|
||||
" -P FILE Create PID file using FILE\n"
|
||||
"\n"
|
||||
"By default this program daemonizes itself to the background, and,\n"
|
||||
"when it's done setting up its signal handler(s), creates a PID file\n"
|
||||
"to let the rest of the system know it's done. When the program runs\n"
|
||||
"in the foreground it does not create a PID file by default.\n",
|
||||
PROGNM);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int do_background = 1;
|
||||
int do_pidfile = 1;
|
||||
char *pidfn = NULL;
|
||||
int c;
|
||||
|
||||
while ((c = getopt(argc, argv, "hnpP:")) != EOF) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
return usage(0);
|
||||
case 'n':
|
||||
do_background = 0;
|
||||
do_pidfile--;
|
||||
break;
|
||||
case 'p':
|
||||
do_pidfile++;
|
||||
break;
|
||||
case 'P':
|
||||
pidfn = optarg;
|
||||
break;
|
||||
default:
|
||||
return usage(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Daemonize, fork to background etc. */
|
||||
if (do_background) {
|
||||
if (daemon(0, 1))
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Signal handlers first *then* PID file */
|
||||
signal(SIGTERM, sig);
|
||||
|
||||
/* Tell world where we are, but not if bg w/o pid file */
|
||||
if (do_pidfile == 1)
|
||||
pidfile(pidfn);
|
||||
|
||||
warnx("Entering while(1) loop");
|
||||
while (1)
|
||||
sleep(1);
|
||||
|
||||
warnx("Leaving ...");
|
||||
return 0;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
service [2345] kill:20 log /test_assets/service.sh
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
while true; do
|
||||
sleep 5
|
||||
done
|
||||
@@ -4,5 +4,14 @@ set -eu
|
||||
|
||||
# shellcheck disable=SC2154
|
||||
make -C "$top_builddir" DESTDIR="$TENV_ROOT" install
|
||||
|
||||
mkdir -p "$TENV_ROOT/sbin/"
|
||||
cp "$top_builddir/test/common/serv" "$TENV_ROOT/sbin/"
|
||||
|
||||
# shellcheck disable=SC2154
|
||||
FINITBIN="$(pwd)/$top_builddir/src/finit" DEST="$TENV_ROOT" make -f "$srcdir/tenv/root.mk"
|
||||
|
||||
# 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 "$TENV_ROOT" -name $plugin -delete
|
||||
done
|
||||
|
||||
Executable
+34
@@ -0,0 +1,34 @@
|
||||
#!/bin/sh
|
||||
# Verifies initctl can send arbitrary signals (USR1 in this case) to finit managed services
|
||||
|
||||
set -eu
|
||||
|
||||
TEST_DIR=$(dirname "$0")
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
. "$TEST_DIR/tenv/lib.sh"
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Running test teardown."
|
||||
|
||||
texec rm -f "$FINIT_CONF"
|
||||
}
|
||||
|
||||
say "Test start $(date)"
|
||||
|
||||
say 'Ensure file system is cleared'
|
||||
texec rm -f /tmp/usr1.log
|
||||
|
||||
say "Add service stanza in $FINIT_CONF"
|
||||
texec sh -c "echo 'service [2345] kill:20 log service.sh -- Test service' > $FINIT_CONF"
|
||||
|
||||
say 'Reload Finit'
|
||||
texec sh -c "initctl reload"
|
||||
|
||||
say 'Send SIGUSR1 to service...'
|
||||
texec sh -c "initctl signal service.sh SIGUSR1"
|
||||
|
||||
# shellcheck disable=SC2016
|
||||
retry 'assert "service.sh received SIGUSR" "$(texec cat /tmp/usr1.log)" = "USR1"' 10 1
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
#!/bin/sh
|
||||
|
||||
nm=$1
|
||||
|
||||
# shellcheck disable=SC2046
|
||||
getpid()
|
||||
{
|
||||
initctl status "$1" |awk '/PID :/{ print $3; }'
|
||||
}
|
||||
|
||||
pid=$(getpid "$nm")
|
||||
if [ -f oldpid ]; then
|
||||
oldpid=$(cat oldpid)
|
||||
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
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$pid" -le 1 ]; then
|
||||
sleep 3
|
||||
pid=$(getpid "$nm")
|
||||
if [ "$pid" -le 1 ]; then
|
||||
echo "Got a bad PID: $pid, aborting ..."
|
||||
ps
|
||||
sleep 1
|
||||
initctl status "$nm"
|
||||
ps
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "$pid" > oldpid
|
||||
|
||||
#echo "PID $pid, kill -9 ..."
|
||||
kill -9 "$pid"
|
||||
@@ -0,0 +1 @@
|
||||
test
|
||||
Executable
+51
@@ -0,0 +1,51 @@
|
||||
#!/bin/sh
|
||||
# SysV style start script for service.sh
|
||||
|
||||
DAEMON="/sbin/service.sh"
|
||||
PIDFILE="/var/run/service.pid"
|
||||
|
||||
start()
|
||||
{
|
||||
printf 'Starting %s: ' "$DAEMON"
|
||||
start-stop-daemon -S -b -q -p "$PIDFILE" -x "$DAEMON"
|
||||
|
||||
status=$?
|
||||
if [ "$status" -eq 0 ]; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "FAIL"
|
||||
fi
|
||||
|
||||
return "$status"
|
||||
}
|
||||
|
||||
stop()
|
||||
{
|
||||
printf 'Stopping %s: ' "$DAEMON"
|
||||
start-stop-daemon -K -q -p "$PIDFILE"
|
||||
|
||||
status=$?
|
||||
if [ "$status" -eq 0 ]; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "FAIL"
|
||||
fi
|
||||
|
||||
return "$status"
|
||||
}
|
||||
|
||||
restart()
|
||||
{
|
||||
stop
|
||||
sleep 1
|
||||
start
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start|stop|restart)
|
||||
"$1"
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart}, got $0 $1"
|
||||
exit 1
|
||||
esac
|
||||
Executable
+4
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "Shutting down ..."
|
||||
exit 0
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "Starting up ..."
|
||||
poweroff -d 2
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# /etc/inittab
|
||||
#
|
||||
# Copyright (C) 2001 Erik Andersen <andersen@codepoet.org>
|
||||
#
|
||||
# Note: BusyBox init doesn't support runlevels. The runlevels field is
|
||||
# completely ignored by BusyBox init. If you want runlevels, use
|
||||
# sysvinit.
|
||||
#
|
||||
# Format for each entry: <id>:<runlevels>:<action>:<process>
|
||||
#
|
||||
# id == tty to run on, or empty for /dev/console
|
||||
# runlevels == ignored
|
||||
# action == one of sysinit, respawn, askfirst, wait, and once
|
||||
# process == program to run
|
||||
|
||||
# Startup the system
|
||||
#::sysinit:/bin/mount -t proc proc /proc
|
||||
#::sysinit:/bin/mount -o remount,rw /
|
||||
#::sysinit:/bin/mkdir -p /dev/pts /dev/shm
|
||||
#::sysinit:/bin/mount -a
|
||||
#::sysinit:/bin/mkdir -p /run/lock/subsys
|
||||
#::sysinit:/sbin/swapon -a
|
||||
null::sysinit:/bin/ln -sf /proc/self/fd /dev/fd
|
||||
null::sysinit:/bin/ln -sf /proc/self/fd/0 /dev/stdin
|
||||
null::sysinit:/bin/ln -sf /proc/self/fd/1 /dev/stdout
|
||||
null::sysinit:/bin/ln -sf /proc/self/fd/2 /dev/stderr
|
||||
::sysinit:/bin/hostname -F /etc/hostname
|
||||
# now run any rc scripts
|
||||
::sysinit:/etc/init.d/rcS
|
||||
|
||||
# Put a getty on the serial port
|
||||
#ttyS0::respawn:/sbin/getty -L ttyS0 115200 vt100 # GENERIC_SERIAL
|
||||
|
||||
# Stuff to do for the 3-finger salute
|
||||
#::ctrlaltdel:/sbin/reboot
|
||||
|
||||
# Stuff to do before rebooting
|
||||
::shutdown:/etc/init.d/rcK
|
||||
#::shutdown:/sbin/swapoff -a
|
||||
#::shutdown:/bin/umount -a -r
|
||||
@@ -12,7 +12,7 @@
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
@@ -23,22 +23,25 @@
|
||||
# THE SOFTWARE.
|
||||
|
||||
set -eu
|
||||
export PATH=$PATH:/usr/bin:/usr/sbin
|
||||
|
||||
# It would have been nice to mount /dev as devtmpfs, but unfortunately
|
||||
# that's not possible if you're not privileged. For now tmpfs will
|
||||
# have to do.
|
||||
mount -n -t tmpfs none /dev
|
||||
# Silence BusyBox init
|
||||
touch /dev/null
|
||||
|
||||
mount -t proc none /proc
|
||||
mount -t sysfs none /sys
|
||||
|
||||
if [ "$(ls -A /tmp)" ]; then
|
||||
mkdir -p /tmp.shadow
|
||||
mount --bind /tmp /tmp.shadow
|
||||
mount -t tmpfs none /tmp
|
||||
cp -a /tmp.shadow/* /tmp/
|
||||
mkdir -p /tmp.shadow
|
||||
mount --bind /tmp /tmp.shadow
|
||||
mount -t tmpfs none /tmp
|
||||
cp -a /tmp.shadow/* /tmp/
|
||||
else
|
||||
mount -t tmpfs none /tmp
|
||||
mount -t tmpfs none /tmp
|
||||
fi
|
||||
|
||||
mkdir -p "$FINIT_RCSD"
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
|
||||
cleanup()
|
||||
{
|
||||
echo "Got signal, stopping ..."
|
||||
rm -f /run/service.pid
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Hook SIGUSR1 and dump trace to file system
|
||||
# shellcheck disable=SC2172
|
||||
trap 'echo USR1 > /tmp/usr1.log' USR1
|
||||
trap cleanup INT
|
||||
trap cleanup TERM
|
||||
trap cleanup QUIT
|
||||
trap cleanup EXIT
|
||||
|
||||
echo $$ > /run/service.pid
|
||||
|
||||
# sleep may exit on known signal, so
|
||||
# we cannot use 'set -e'
|
||||
while true; do
|
||||
sleep 1
|
||||
done
|
||||
Executable
+43
@@ -0,0 +1,43 @@
|
||||
#!/bin/sh
|
||||
# Verifies Finit restarts crashing services and registers their new PID
|
||||
# from their (default) PID file.
|
||||
|
||||
set -eu
|
||||
|
||||
TEST_DIR=$(dirname "$0")
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
. "$TEST_DIR/tenv/lib.sh"
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Running test teardown."
|
||||
|
||||
texec rm -f "$FINIT_CONF"
|
||||
}
|
||||
|
||||
say "Test start $(date)"
|
||||
rm -f "$TENV_ROOT"/oldpid
|
||||
|
||||
say "Add service stanza in $FINIT_CONF"
|
||||
texec sh -c "echo 'service [2345] respawn log service.sh -- Test service' > $FINIT_CONF"
|
||||
|
||||
say 'Reload Finit'
|
||||
texec sh -c "initctl reload"
|
||||
#texec sh -c "initctl status"
|
||||
|
||||
retry 'assert_num_children 1 service.sh'
|
||||
texec sh -c "initctl status service.sh"
|
||||
|
||||
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
|
||||
texec sh -c "slay service.sh"
|
||||
done
|
||||
|
||||
retry 'assert_new_pid service.sh /run/service.pid'
|
||||
retry 'assert_num_children 1 service.sh'
|
||||
Executable
+66
@@ -0,0 +1,66 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
TEST_DIR=$(dirname "$0")
|
||||
|
||||
test_setup()
|
||||
{
|
||||
say "Test start $(date)"
|
||||
}
|
||||
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Running test teardown."
|
||||
|
||||
texec rm -f "$FINIT_CONF"
|
||||
}
|
||||
|
||||
test_one()
|
||||
{
|
||||
pidfn=$1
|
||||
service=$2
|
||||
|
||||
say "Add service stanza '$service' to $FINIT_CONF ..."
|
||||
texec sh -c "echo '$service' > $FINIT_CONF"
|
||||
|
||||
say 'Reload Finit'
|
||||
#texec sh -c "initctl debug"
|
||||
texec sh -c "initctl reload"
|
||||
#texec sh -c "initctl status"
|
||||
#texec sh -c "ps"
|
||||
|
||||
#texec sh -c "initctl status"
|
||||
#texec sh -c "ps"
|
||||
#texec sh -c "initctl status serv"
|
||||
|
||||
retry 'assert_num_children 1 serv'
|
||||
retry "assert_pidfile $pidfn" 1
|
||||
|
||||
say 'Stop the service'
|
||||
texec sh -c "initctl stop serv"
|
||||
|
||||
retry 'assert_num_children 0 serv'
|
||||
|
||||
say 'Start the service again'
|
||||
texec sh -c "initctl start serv"
|
||||
|
||||
retry 'assert_num_children 1 serv'
|
||||
|
||||
say "Done, drop service from $FINIT_CONF ..."
|
||||
texec sh -c "rm $FINIT_CONF"
|
||||
texec sh -c "initctl reload"
|
||||
}
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
. "$TEST_DIR/tenv/lib.sh"
|
||||
|
||||
test_one "/run/serv.pid" "service pid:!/run/serv.pid serv -- Forking service, type 1"
|
||||
test_one "/run/serv.pid" "service type:forking serv -- Forking service, type 2"
|
||||
# This one could never be started by and monitored by Finit: it forks to
|
||||
# background and does not create a PID file. Essentially it's lost to
|
||||
# Finit, and any other sane process monitor.
|
||||
#test_one "/run/serv.pid" "service pid:/run/serv.pid serv -p -- Forking service w/o PID file"
|
||||
test_one "/run/serv.pid" "service pid:/run/serv.pid serv -n -- Foreground service w/o PID file"
|
||||
test_one "/run/serv.pid" "service serv -n -p -- Foreground service w/ PID file"
|
||||
test_one "/run/servy.pid" "service pid:/run/servy.pid serv -n -p -P /run/servy.pid -- Foreground service w/ custom PID file"
|
||||
@@ -7,24 +7,25 @@ TEST_DIR=$(dirname "$0")
|
||||
# shellcheck source=/dev/null
|
||||
. "$TEST_DIR/tenv/lib.sh"
|
||||
|
||||
test_teardown() {
|
||||
say "Test done $(date)"
|
||||
say "Running test teardown."
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Running test teardown."
|
||||
|
||||
texec rm -f "$FINIT_RCSD/service.conf"
|
||||
texec rm -f /test_assets/service.sh
|
||||
texec rm -f "$FINIT_RCSD/service.conf"
|
||||
}
|
||||
|
||||
say "Test start $(date)"
|
||||
|
||||
cp "$TEST_DIR"/common/service.sh "$TENV_ROOT"/test_assets/
|
||||
|
||||
say "Add service stanza in $FINIT_RCSD/service.conf"
|
||||
texec sh -c "echo 'service [2345] kill:20 log /test_assets/service.sh' > $FINIT_RCSD/service.conf"
|
||||
texec sh -c "echo 'service [2345] kill:20 log service.sh -- Subserv' > $FINIT_RCSD/service.conf"
|
||||
|
||||
say 'Reload Finit'
|
||||
texec sh -c "initctl reload"
|
||||
|
||||
sleep 2
|
||||
texec sh -c "ps"
|
||||
|
||||
retry 'assert_num_children 1 service.sh'
|
||||
|
||||
say 'Stop the service'
|
||||
|
||||
@@ -7,20 +7,18 @@ TEST_DIR=$(dirname "$0")
|
||||
# shellcheck source=/dev/null
|
||||
. "$TEST_DIR/tenv/lib.sh"
|
||||
|
||||
test_teardown() {
|
||||
say "Test done $(date)"
|
||||
say "Running test teardown."
|
||||
test_teardown()
|
||||
{
|
||||
say "Test done $(date)"
|
||||
say "Running test teardown."
|
||||
|
||||
texec rm -f "$FINIT_CONF"
|
||||
texec rm -f /test_assets/service.sh
|
||||
texec rm -f "$FINIT_CONF"
|
||||
}
|
||||
|
||||
say "Test start $(date)"
|
||||
|
||||
cp "$TEST_DIR"/common/service.sh "$TENV_ROOT"/test_assets/
|
||||
|
||||
say "Add service stanza in $FINIT_CONF"
|
||||
texec sh -c "echo 'service [2345] kill:20 log /test_assets/service.sh' > $FINIT_CONF"
|
||||
texec sh -c "echo 'service [2345] kill:20 log service.sh -- Test service' > $FINIT_CONF"
|
||||
|
||||
say 'Reload Finit'
|
||||
texec sh -c "initctl reload"
|
||||
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
TEST_DIR=$(dirname "$0")
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
. "$TEST_DIR/tenv/lib.sh"
|
||||
|
||||
test_teardown() {
|
||||
say "Test done $(date)"
|
||||
say "Running test teardown."
|
||||
|
||||
texec rm -f "$FINIT_CONF"
|
||||
}
|
||||
|
||||
say "Test start $(date)"
|
||||
|
||||
say "Add sysv stanza in $FINIT_CONF"
|
||||
texec sh -c "echo 'sysv [2345] pid:!/run/service.pid name:service.sh /etc/init.d/S01-service.sh -- SysV test service' > $FINIT_CONF"
|
||||
|
||||
say 'Reload Finit'
|
||||
texec sh -c "initctl reload"
|
||||
|
||||
retry 'assert_num_children 1 service.sh'
|
||||
|
||||
say 'Stop the sysv service'
|
||||
texec sh -c "initctl stop service.sh"
|
||||
|
||||
retry 'assert_num_children 0 service.sh'
|
||||
|
||||
say 'Start the sysv service again'
|
||||
texec sh -c "initctl start service.sh"
|
||||
|
||||
retry 'assert_num_children 1 service.sh'
|
||||
|
||||
return 0
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user