mirror of
https://github.com/troglobit/finit.git
synced 2026-10-13 10:14:47 +00:00
Compare commits
122
Commits
4.2
..
bisect-cache
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58e31dbd22 | ||
|
|
85058b54a8 | ||
|
|
f16df142d7 | ||
|
|
f9f52a46a6 | ||
|
|
ef1bfb869f | ||
|
|
5002c74876 | ||
|
|
a0bc23c48f | ||
|
|
350cf6e578 | ||
|
|
b96a8d8766 | ||
|
|
a419828dea | ||
|
|
702b22d4a3 | ||
|
|
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:
|
build:
|
||||||
# Verify we can build on latest Ubuntu with both gcc and clang
|
# Verify we can build on latest Ubuntu with both gcc and clang
|
||||||
name: ${{ matrix.compiler }}
|
name: ${{ matrix.compiler }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-18.04
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
compiler: [gcc, clang]
|
compiler: [gcc, clang]
|
||||||
@@ -60,7 +60,9 @@ jobs:
|
|||||||
/tmp/sbin/initctl -h
|
/tmp/sbin/initctl -h
|
||||||
- name: Run Unit Tests
|
- name: Run Unit Tests
|
||||||
run: |
|
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
|
- name: Upload Test Results
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -45,3 +45,6 @@ GTAGS
|
|||||||
/.autoconf
|
/.autoconf
|
||||||
/.automake
|
/.automake
|
||||||
/.built
|
/.built
|
||||||
|
|
||||||
|
# VS Code user settings
|
||||||
|
.vscode
|
||||||
|
|||||||
@@ -4,6 +4,31 @@ Change Log
|
|||||||
All relevant changes are documented in this file.
|
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!
|
||||||
|
|
||||||
|
### 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
|
||||||
|
|
||||||
|
### 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
|
||||||
|
|
||||||
|
|
||||||
[4.2][] - 2022-01-16
|
[4.2][] - 2022-01-16
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
@@ -1039,6 +1064,7 @@ Major bug fix release.
|
|||||||
* Initial release
|
* Initial release
|
||||||
|
|
||||||
[UNRELEASED]: https://github.com/troglobit/finit/compare/4.2...HEAD
|
[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.2]: https://github.com/troglobit/finit/compare/4.1...4.2
|
||||||
[4.1]: https://github.com/troglobit/finit/compare/4.0...4.1
|
[4.1]: https://github.com/troglobit/finit/compare/4.0...4.1
|
||||||
[4.0]: https://github.com/troglobit/finit/compare/3.1...4.0
|
[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">
|
<img align="right" src="img/finit3.png" alt="Finit: Fast Init">
|
||||||
|
|
||||||
* [Introduction](#introduction)
|
* [Introduction](#introduction)
|
||||||
@@ -598,7 +598,7 @@ and proposed extensions.
|
|||||||
[Joachim Wiberg]: https://troglobit.com
|
[Joachim Wiberg]: https://troglobit.com
|
||||||
[License]: https://en.wikipedia.org/wiki/MIT_License
|
[License]: https://en.wikipedia.org/wiki/MIT_License
|
||||||
[License Badge]: https://img.shields.io/badge/License-MIT-teal.svg
|
[License Badge]: https://img.shields.io/badge/License-MIT-teal.svg
|
||||||
[GitHub]: https://travis-ci.org/troglobit/finit
|
[GitHub]: https://github.com/troglobit/finit/actions/workflows/build.yml/
|
||||||
[GitHub Status]: https://travis-ci.org/troglobit/finit.svg?branch=master
|
[GitHub Status]: https://github.com/troglobit/finit/actions/workflows/build.yml/badge.svg
|
||||||
[Coverity Scan]: https://scan.coverity.com/projects/3545
|
[Coverity Scan]: https://scan.coverity.com/projects/3545
|
||||||
[Coverity Status]: https://scan.coverity.com/projects/3545/badge.svg
|
[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-dev, https://github.com/troglobit/finit/issues, finit, https://troglobit.com/finit.html)
|
||||||
AC_CONFIG_AUX_DIR(aux)
|
AC_CONFIG_AUX_DIR(aux)
|
||||||
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
|
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
|
||||||
AM_SILENT_RULES([yes])
|
AM_SILENT_RULES([yes])
|
||||||
@@ -14,8 +14,8 @@ AC_CONFIG_FILES([Makefile
|
|||||||
man/Makefile
|
man/Makefile
|
||||||
plugins/Makefile
|
plugins/Makefile
|
||||||
src/Makefile
|
src/Makefile
|
||||||
test/test.env
|
test/test.env test/Makefile
|
||||||
test/Makefile])
|
test/tenv/Makefile test/common/Makefile])
|
||||||
|
|
||||||
# Older versions of autoconf (<2.58) do not have AC_CONFIG_MACRO_DIR()
|
# Older versions of autoconf (<2.58) do not have AC_CONFIG_MACRO_DIR()
|
||||||
#m4_include([m4/plugin.m4])
|
#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([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([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([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([resolvconf], [no], [Setup necessary files for resolvconf])
|
||||||
AC_PLUGIN([x11-common], [no], [Console setup (for X)])
|
AC_PLUGIN([x11-common], [no], [Console setup (for X)])
|
||||||
AC_PLUGIN([netlink], [yes], [Basic netlink plugin for IFUP/IFDN and GW events. Can be replaced with externally built plugin that links with libnl or similar.])
|
AC_PLUGIN([netlink], [yes], [Basic netlink plugin for IFUP/IFDN and GW events. Can be replaced with externally built plugin that links with libnl or similar.])
|
||||||
AC_PLUGIN([hotplug], [yes], [Setup and start udev or mdev hotplug daemon])
|
AC_PLUGIN([hotplug], [yes], [Setup and start udev or mdev hotplug daemon])
|
||||||
AC_PLUGIN([rtc], [yes], [Save and restore RTC using hwclock])
|
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])
|
AC_PLUGIN([urandom], [yes], [Setup and save random seed at boot/shutdown])
|
||||||
|
|
||||||
# Check for extra arguments or packages
|
# 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 */
|
||||||
+45
-1
@@ -1,7 +1,49 @@
|
|||||||
Finit Services
|
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
|
||||||
|
|
||||||
|
service pid:!/run/serv.pid serv -- Forking service
|
||||||
|
|
||||||
|
### 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
|
State Machine
|
||||||
-------------
|
-------------
|
||||||
@@ -11,6 +53,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`
|
not shown in the diagram for brevity. Services start in the `HALTED`
|
||||||
state.
|
state.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
The current state depends on the two following conditions:
|
The current state depends on the two following conditions:
|
||||||
|
|
||||||
* `E`: Service enabled. In order for `E` to be satisfied, the service
|
* `E`: Service enabled. In order for `E` to be satisfied, the service
|
||||||
|
|||||||
+11
-3
@@ -11,7 +11,7 @@
|
|||||||
.Nd Control tool for Finit
|
.Nd Control tool for Finit
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm /sbin/initctl
|
.Nm /sbin/initctl
|
||||||
.Op Fl bcfhlpqtv
|
.Op Fl bcfhlpqtvV
|
||||||
.Op COMMAND
|
.Op COMMAND
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
.Nm
|
.Nm
|
||||||
@@ -41,16 +41,20 @@ Silent, only return status of command.
|
|||||||
Skip table headings.
|
Skip table headings.
|
||||||
.It Fl v, -verbose
|
.It Fl v, -verbose
|
||||||
Verbose output, where applicable.
|
Verbose output, where applicable.
|
||||||
|
.It Fl V, -version
|
||||||
|
Show program version.
|
||||||
.El
|
.El
|
||||||
.Sh COMMANDS
|
.Sh COMMANDS
|
||||||
.Bl -tag -width Ds
|
.Bl -tag -width Ds
|
||||||
.It Nm Ar debug
|
.It Nm Ar debug
|
||||||
Toggle finit (daemon) debug to
|
Toggle
|
||||||
|
.Nm finit
|
||||||
|
(daemon) debug to
|
||||||
.Pa /dev/console
|
.Pa /dev/console
|
||||||
.It Nm Ar help
|
.It Nm Ar help
|
||||||
Show built-in help text
|
Show built-in help text
|
||||||
.It Nm Ar version
|
.It Nm Ar version
|
||||||
Show Finit (daemon) version
|
Show program version
|
||||||
.It Nm Ar ls | list
|
.It Nm Ar ls | list
|
||||||
List all
|
List all
|
||||||
.Cm *.conf
|
.Cm *.conf
|
||||||
@@ -136,6 +140,10 @@ Start service by name, with optional ID, e.g.,
|
|||||||
Stop/Pause a running service by name
|
Stop/Pause a running service by name
|
||||||
.It Nm Ar reload Cm NAME[:ID]
|
.It Nm Ar reload Cm NAME[:ID]
|
||||||
Reload service by name (SIGHUP or restart)
|
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]
|
.It Nm Ar restart Cm NAME[:ID]
|
||||||
Restart (stop/start) service by name
|
Restart (stop/start) service by name
|
||||||
.It Nm Ar status Cm NAME[:ID]
|
.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_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||||
AM_CPPFLAGS = -I$(top_srcdir)/src -U_FORTIFY_SOURCE
|
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 += -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
|
if STATIC
|
||||||
noinst_LTLIBRARIES = libplug.la
|
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
|
if BUILD_ALSA_UTILS_PLUGIN
|
||||||
libplug_la_SOURCES += alsa-utils.c
|
libplug_la_SOURCES += alsa-utils.c
|
||||||
@@ -25,6 +25,10 @@ if BUILD_MODULES_LOAD_PLUGIN
|
|||||||
libplug_la_SOURCES += modules-load.c
|
libplug_la_SOURCES += modules-load.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if BUILD_MODPROBE_PLUGIN
|
||||||
|
libplug_la_SOURCES += modprobe.c
|
||||||
|
endif
|
||||||
|
|
||||||
if BUILD_NETLINK_PLUGIN
|
if BUILD_NETLINK_PLUGIN
|
||||||
libplug_la_SOURCES += netlink.c
|
libplug_la_SOURCES += netlink.c
|
||||||
endif
|
endif
|
||||||
@@ -37,6 +41,10 @@ if BUILD_RTC_PLUGIN
|
|||||||
libplug_la_SOURCES += rtc.c
|
libplug_la_SOURCES += rtc.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if BUILD_TTY_PLUGIN
|
||||||
|
libplug_la_SOURCES += tty.c
|
||||||
|
endif
|
||||||
|
|
||||||
if BUILD_URANDOM_PLUGIN
|
if BUILD_URANDOM_PLUGIN
|
||||||
libplug_la_SOURCES += urandom.c
|
libplug_la_SOURCES += urandom.c
|
||||||
endif
|
endif
|
||||||
@@ -46,7 +54,7 @@ libplug_la_SOURCES += x11-common.c
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
else
|
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
|
if BUILD_ALSA_UTILS_PLUGIN
|
||||||
pkglib_LTLIBRARIES += alsa-utils.la
|
pkglib_LTLIBRARIES += alsa-utils.la
|
||||||
@@ -64,6 +72,10 @@ if BUILD_MODULES_LOAD_PLUGIN
|
|||||||
pkglib_LTLIBRARIES += modules-load.la
|
pkglib_LTLIBRARIES += modules-load.la
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if BUILD_MODPROBE_PLUGIN
|
||||||
|
pkglib_LTLIBRARIES += modprobe.la
|
||||||
|
endif
|
||||||
|
|
||||||
if BUILD_NETLINK_PLUGIN
|
if BUILD_NETLINK_PLUGIN
|
||||||
pkglib_LTLIBRARIES += netlink.la
|
pkglib_LTLIBRARIES += netlink.la
|
||||||
endif
|
endif
|
||||||
@@ -76,6 +88,10 @@ if BUILD_RTC_PLUGIN
|
|||||||
pkglib_LTLIBRARIES += rtc.la
|
pkglib_LTLIBRARIES += rtc.la
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if BUILD_TTY_PLUGIN
|
||||||
|
pkglib_LTLIBRARIES += tty.la
|
||||||
|
endif
|
||||||
|
|
||||||
if BUILD_URANDOM_PLUGIN
|
if BUILD_URANDOM_PLUGIN
|
||||||
pkglib_LTLIBRARIES += urandom.la
|
pkglib_LTLIBRARIES += urandom.la
|
||||||
endif
|
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);
|
_pe("Failed creating %s -> %s symlink", target, linkpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,11 +131,11 @@ static void setup(void *arg)
|
|||||||
_d("System with new /run tmpfs ...");
|
_d("System with new /run tmpfs ...");
|
||||||
if (!fisdir("/run/lock"))
|
if (!fisdir("/run/lock"))
|
||||||
makedir("/run/lock", 1777);
|
makedir("/run/lock", 1777);
|
||||||
ln("/run/lock", "/var/lock", 0);
|
ln("/run/lock", "/var/lock");
|
||||||
ln("/dev/shm", "/run/shm", 0);
|
ln("/dev/shm", "/run/shm");
|
||||||
|
|
||||||
/* compat only, should really be set up by OS/dist */
|
/* compat only, should really be set up by OS/dist */
|
||||||
ln("/run", "/var/run", 1);
|
ln("../run", "/var/run");
|
||||||
} else {
|
} else {
|
||||||
makedir("/var/lock", 1777);
|
makedir("/var/lock", 1777);
|
||||||
makedir("/var/run", 0755);
|
makedir("/var/run", 0755);
|
||||||
@@ -189,7 +189,7 @@ static void setup(void *arg)
|
|||||||
makedir("/var/run/sshd", 01755); /* OpenSSH */
|
makedir("/var/run/sshd", 01755); /* OpenSSH */
|
||||||
|
|
||||||
if (!fexist("/etc/mtab"))
|
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 */
|
/* Void Linux has a uuidd that runs as uuid:uuid and needs /run/uuid */
|
||||||
mksubsys("/var/run/uuidd", 0755, "uuidd", "uuidd");
|
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", 0711, "root", "root");
|
||||||
mksubsys("/var/run/sudo/ts", 0700, "root", "root");
|
mksubsys("/var/run/sudo/ts", 0700, "root", "root");
|
||||||
if (whichp("restorecon"))
|
if (whichp("restorecon"))
|
||||||
run("restorecon /var/run/sudo /var/run/sudo/ts");
|
run("restorecon /var/run/sudo /var/run/sudo/ts", "restorecon");
|
||||||
|
|
||||||
umask(prev);
|
umask(prev);
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-4
@@ -34,9 +34,7 @@
|
|||||||
|
|
||||||
static void setup(void *arg)
|
static void setup(void *arg)
|
||||||
{
|
{
|
||||||
size_t i;
|
|
||||||
glob_t gl;
|
glob_t gl;
|
||||||
char buf[160];
|
|
||||||
|
|
||||||
if (rescue) {
|
if (rescue) {
|
||||||
_d("Skipping %s plugin in rescue mode.", __FILE__);
|
_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("/mnt/sysctl.d/*.conf", GLOB_APPEND, NULL, &gl);
|
||||||
glob("/etc/sysctl.conf", GLOB_APPEND, NULL, &gl);
|
glob("/etc/sysctl.conf", GLOB_APPEND, NULL, &gl);
|
||||||
if (gl.gl_pathc > 0) {
|
if (gl.gl_pathc > 0) {
|
||||||
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < gl.gl_pathc; i++) {
|
for (i = 0; i < gl.gl_pathc; i++) {
|
||||||
snprintf(buf, sizeof(buf), "/sbin/sysctl -e -p %s >/dev/null", gl.gl_pathv[i]);
|
char cmd[160];
|
||||||
run(buf);
|
|
||||||
|
snprintf(cmd, sizeof(cmd), "/sbin/sysctl -e -p %s >/dev/null", gl.gl_pathv[i]);
|
||||||
|
run(cmd, "sysctl");
|
||||||
}
|
}
|
||||||
globfree(&gl);
|
globfree(&gl);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,19 +160,23 @@ static void sys_init(void *arg)
|
|||||||
char sysdir[MAX_ARG_LEN];
|
char sysdir[MAX_ARG_LEN];
|
||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
|
_d("Calling mkpath() on sys conds");
|
||||||
if (mkpath(pid_runpath(_PATH_CONDSYS, sysdir, sizeof(sysdir)), 0755) && errno != EEXIST) {
|
if (mkpath(pid_runpath(_PATH_CONDSYS, sysdir, sizeof(sysdir)), 0755) && errno != EEXIST) {
|
||||||
_pe("Failed creating %s condition directory, %s", COND_SYS, _PATH_CONDSYS);
|
_pe("Failed creating %s condition directory, %s", COND_SYS, _PATH_CONDSYS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_d("Calling realpth() on condsys");
|
||||||
path = realpath(_PATH_CONDSYS, NULL);
|
path = realpath(_PATH_CONDSYS, NULL);
|
||||||
if (!path) {
|
if (!path) {
|
||||||
_pe("Cannot figure out real path to %s, aborting", _PATH_CONDSYS);
|
_pe("Cannot figure out real path to %s, aborting", _PATH_CONDSYS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_d("Calling iwatch_add()");
|
||||||
if (iwatch_add(&iw_sys, path, IN_ONLYDIR))
|
if (iwatch_add(&iw_sys, path, IN_ONLYDIR))
|
||||||
iwatch_exit(&iw_sys);
|
iwatch_exit(&iw_sys);
|
||||||
|
_d("Done.");
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
|
|||||||
@@ -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) {
|
if ((fd = open("/var/run/console/console.lock", O_CREAT|O_WRONLY|O_TRUNC, 0644)) >= 0) {
|
||||||
write(fd, username, strlen(username));
|
write(fd, username, strlen(username));
|
||||||
close(fd);
|
close(fd);
|
||||||
run("pam_console_apply");
|
run("pam_console_apply", "pam-console");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ static void setup(void *arg)
|
|||||||
makedir("/tmp/.ICE-unix", 01777);
|
makedir("/tmp/.ICE-unix", 01777);
|
||||||
|
|
||||||
if (whichp("restorecon"))
|
if (whichp("restorecon"))
|
||||||
run("restorecon /tmp/.ICE-unix /tmp/.X11-unix");
|
run("restorecon /tmp/.ICE-unix /tmp/.X11-unix", "restorecon");
|
||||||
|
|
||||||
umask(prev);
|
umask(prev);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,12 +51,12 @@
|
|||||||
extern svc_t *wdog;
|
extern svc_t *wdog;
|
||||||
static uev_t api_watcher;
|
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)
|
if (!svc)
|
||||||
return 1;
|
return 1;
|
||||||
@@ -67,7 +67,7 @@ static int stop(svc_t *svc)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int start(svc_t *svc)
|
static int start(svc_t *svc, void *user_data)
|
||||||
{
|
{
|
||||||
if (!svc)
|
if (!svc)
|
||||||
return 1;
|
return 1;
|
||||||
@@ -83,7 +83,7 @@ static int start(svc_t *svc)
|
|||||||
* responsibility of initctl to do. Otherwise we'd block PID 1,
|
* responsibility of initctl to do. Otherwise we'd block PID 1,
|
||||||
* or introduce some nasty race conditions.
|
* or introduce some nasty race conditions.
|
||||||
*/
|
*/
|
||||||
static int restart(svc_t *svc)
|
static int restart(svc_t *svc, void *user_data)
|
||||||
{
|
{
|
||||||
if (!svc)
|
if (!svc)
|
||||||
return 1;
|
return 1;
|
||||||
@@ -95,7 +95,7 @@ static int restart(svc_t *svc)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int reload(svc_t *svc)
|
static int reload(svc_t *svc, void *user_data)
|
||||||
{
|
{
|
||||||
if (!svc)
|
if (!svc)
|
||||||
return 1;
|
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_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_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 char query_buf[368];
|
||||||
static int missing(char *job, char *id)
|
static int missing(char *job, char *id, void *user_data)
|
||||||
{
|
{
|
||||||
char buf[20];
|
char buf[20];
|
||||||
|
|
||||||
@@ -133,7 +153,7 @@ static int missing(char *job, char *id)
|
|||||||
static int do_query(char *buf, size_t len)
|
static int do_query(char *buf, size_t len)
|
||||||
{
|
{
|
||||||
query_buf[0] = 0;
|
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);
|
memcpy(buf, query_buf, len);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -407,7 +427,7 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
|
|
||||||
if (wdog->protect) {
|
if (wdog->protect) {
|
||||||
logit(LOG_NOTICE, "Stopping and deleting built-in watchdog.");
|
logit(LOG_NOTICE, "Stopping and deleting built-in watchdog.");
|
||||||
stop(wdog);
|
stop(wdog, NULL);
|
||||||
svc_del(wdog);
|
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)));
|
send_svc(sd, do_find_byc(rq.data, sizeof(rq.data)));
|
||||||
goto leave;
|
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:
|
default:
|
||||||
_d("Unsupported cmd: %d", rq.cmd);
|
_d("Unsupported cmd: %d", rq.cmd);
|
||||||
break;
|
break;
|
||||||
|
|||||||
+26
-8
@@ -466,8 +466,10 @@ void cgroup_init(uev_ctx_t *ctx)
|
|||||||
if (mount("none", FINIT_CGPATH, "cgroup2", opts, NULL)) {
|
if (mount("none", FINIT_CGPATH, "cgroup2", opts, NULL)) {
|
||||||
if (errno == ENOENT)
|
if (errno == ENOENT)
|
||||||
logit(LOG_NOTICE, "Kernel does not support cgroups v2, disabling.");
|
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
|
else
|
||||||
_pe("Failed mounting cgroup v2, disabling.");
|
_pe("Failed mounting cgroup v2");
|
||||||
avail = 0;
|
avail = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -477,6 +479,7 @@ void cgroup_init(uev_ctx_t *ctx)
|
|||||||
fp = fopen(FINIT_CGPATH "/cgroup.controllers", "r");
|
fp = fopen(FINIT_CGPATH "/cgroup.controllers", "r");
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
_pe("Failed opening %s", FINIT_CGPATH "/cgroup.controllers");
|
_pe("Failed opening %s", FINIT_CGPATH "/cgroup.controllers");
|
||||||
|
abort:
|
||||||
umount(FINIT_CGPATH);
|
umount(FINIT_CGPATH);
|
||||||
avail = 0;
|
avail = 0;
|
||||||
return;
|
return;
|
||||||
@@ -494,9 +497,26 @@ void cgroup_init(uev_ctx_t *ctx)
|
|||||||
|
|
||||||
fclose(fp);
|
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 */
|
/* 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");
|
_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 */
|
/* Default (protected) groups, PID 1, services, and user/login processes */
|
||||||
cgroup_add("init", "cpu.weight:100", 1);
|
cgroup_add("init", "cpu.weight:100", 1);
|
||||||
@@ -505,14 +525,12 @@ void cgroup_init(uev_ctx_t *ctx)
|
|||||||
cgroup_config();
|
cgroup_config();
|
||||||
|
|
||||||
/* Move ourselves to init (best effort, otherwise run in 'root' group */
|
/* Move ourselves to init (best effort, otherwise run in 'root' group */
|
||||||
if (fnwrite("1", FINIT_CGPATH "/init/cgroup.procs"))
|
if (fnwrite("1", FINIT_CGPATH "/init/cgroup.procs")) {
|
||||||
_pe("Failed moving PID 1 to cgroup ", FINIT_CGPATH "/init");
|
_pe("Failed moving PID 1 to cgroup ", FINIT_CGPATH "/init");
|
||||||
|
uev_io_stop(&cgw);
|
||||||
/* prepare cgroup.events watcher */
|
iwatch_exit(&iw_cgroup);
|
||||||
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");
|
|
||||||
close(fd);
|
close(fd);
|
||||||
|
goto abort;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-3
@@ -86,11 +86,13 @@ int client_send(struct init_request *rq, ssize_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pfd.fd = sd;
|
pfd.fd = sd;
|
||||||
pfd.events = POLLIN;
|
pfd.events = POLLIN | POLLERR | POLLHUP;
|
||||||
if ((rc = poll(&pfd, 1, 2000)) <= 0) {
|
if ((rc = poll(&pfd, 1, 2000)) <= 0) {
|
||||||
if (rc)
|
if (rc) {
|
||||||
|
if (errno == EINTR) /* shutdown/reboot */
|
||||||
|
goto exit;
|
||||||
warn("poll(), errno %d", errno);
|
warn("poll(), errno %d", errno);
|
||||||
else
|
} else
|
||||||
warnx("Timed out waiting for reply from Finit.");
|
warnx("Timed out waiting for reply from Finit.");
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-15
@@ -211,22 +211,18 @@ void conf_parse_cmdline(int argc, char *argv[])
|
|||||||
|
|
||||||
static int kmod_exists(char *mod)
|
static int kmod_exists(char *mod)
|
||||||
{
|
{
|
||||||
|
char buf[256];
|
||||||
int found = 0;
|
int found = 0;
|
||||||
FILE *fp;
|
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");
|
fp = fopen("/proc/modules", "r");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
while (!found && (fgets(buf, sizeof(buf), fp))) {
|
while (!found && fgets(buf, sizeof(buf), fp)) {
|
||||||
if (!strncmp(buf, mod, len))
|
char *kmod = strtok(buf, " \t");
|
||||||
|
|
||||||
|
if (kmod && !strcmp(kmod, mod))
|
||||||
found = 1;
|
found = 1;
|
||||||
}
|
}
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
@@ -234,22 +230,26 @@ static int kmod_exists(char *mod)
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kmod_load(char *line)
|
static void kmod_load(char *mod)
|
||||||
{
|
{
|
||||||
char *mod;
|
char module[64] = { 0 };
|
||||||
char cmd[CMD_SIZE];
|
char cmd[CMD_SIZE];
|
||||||
|
|
||||||
if (runlevel != 0)
|
if (runlevel != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mod = strip_line(line);
|
/* Strip args for progress below and kmod_exists() */
|
||||||
if (kmod_exists(mod))
|
strlcpy(module, mod, sizeof(module));
|
||||||
|
if (!strtok(module, " \t"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (kmod_exists(module))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
strcpy(cmd, "modprobe ");
|
strcpy(cmd, "modprobe ");
|
||||||
strlcat(cmd, mod, sizeof(cmd));
|
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 */
|
/* Convert optional "[!123456789S]" string into a bitmask */
|
||||||
@@ -502,7 +502,7 @@ static void parse_static(char *line, int is_rcsd)
|
|||||||
|
|
||||||
/* Kernel module to load */
|
/* Kernel module to load */
|
||||||
if (BOOTSTRAP && MATCH_CMD(line, "module ", x)) {
|
if (BOOTSTRAP && MATCH_CMD(line, "module ", x)) {
|
||||||
kmod_load(x);
|
kmod_load(strip_line(x));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+56
-18
@@ -28,6 +28,7 @@
|
|||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <sysexits.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
@@ -70,16 +71,42 @@ int complete(char *cmd, int pid)
|
|||||||
return status;
|
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)
|
||||||
{
|
{
|
||||||
int status, result, i = 0;
|
int status, result, i = 0;
|
||||||
char *args[NUM_ARGS + 1], *arg, *backup;
|
char *args[NUM_ARGS + 1], *arg;
|
||||||
|
char *backup = NULL;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
|
if (!log) {
|
||||||
/* We must create a copy that is possible to modify. */
|
/* We must create a copy that is possible to modify. */
|
||||||
backup = arg = strdup(cmd);
|
backup = arg = strdup(cmd);
|
||||||
if (!arg)
|
if (!arg)
|
||||||
return 1; /* Failed allocating a string to be modified. */
|
return 1;
|
||||||
|
|
||||||
/* Split command line into tokens of an argv[] array. */
|
/* Split command line into tokens of an argv[] array. */
|
||||||
args[i++] = strsep(&arg, "\t ");
|
args[i++] = strsep(&arg, "\t ");
|
||||||
@@ -107,29 +134,38 @@ int run(char *cmd)
|
|||||||
errno = EOVERFLOW;
|
errno = EOVERFLOW;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if (0 == pid) {
|
if (0 == pid) {
|
||||||
FILE *fp;
|
int rc = EX_OSERR;
|
||||||
|
|
||||||
setsid();
|
setsid();
|
||||||
|
sig_unblock();
|
||||||
|
if (!log) {
|
||||||
|
do_redirect();
|
||||||
|
execvp(args[0], args);
|
||||||
|
} else {
|
||||||
|
char *pfx = *log ? ": " : "";
|
||||||
|
FILE *pp;
|
||||||
|
|
||||||
/* Always redirect stdio for run() */
|
pp = popen(cmd, "r");
|
||||||
fp = fopen("/dev/null", "w");
|
if (pp) {
|
||||||
if (fp) {
|
char buf[256];
|
||||||
int fd = fileno(fp);
|
|
||||||
|
|
||||||
dup2(fd, STDIN_FILENO);
|
while (fgets(buf, sizeof(buf), pp)) {
|
||||||
dup2(fd, STDOUT_FILENO);
|
chomp(buf);
|
||||||
dup2(fd, STDERR_FILENO);
|
logit(LOG_NOTICE, "%s%s%s", log, pfx, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
sig_unblock();
|
rc = pclose(pp);
|
||||||
execvp(args[0], args);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_exit(1); /* Only if execv() fails. */
|
_exit(rc);
|
||||||
} else if (-1 == pid) {
|
} else if (-1 == pid) {
|
||||||
_pe("%s", args[0]);
|
_pe("%s", args[0]);
|
||||||
|
if (backup)
|
||||||
free(backup);
|
free(backup);
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
@@ -137,21 +173,23 @@ int run(char *cmd)
|
|||||||
|
|
||||||
status = complete(args[0], pid);
|
status = complete(args[0], pid);
|
||||||
if (-1 == status) {
|
if (-1 == status) {
|
||||||
|
if (backup)
|
||||||
free(backup);
|
free(backup);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = WEXITSTATUS(status);
|
result = WEXITSTATUS(status);
|
||||||
if (WIFEXITED(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)) {
|
} 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)
|
if (!result)
|
||||||
result = 1; /* Must alert callee that the command did complete successfully.
|
result = 1; /* Must alert callee that the command did complete successfully.
|
||||||
* This is necessary since not all programs trap signals and
|
* This is necessary since not all programs trap signals and
|
||||||
* change their return code accordingly. --Jocke */
|
* change their return code accordingly. --Jocke */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (backup)
|
||||||
free(backup);
|
free(backup);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -186,7 +224,7 @@ int run_interactive(char *cmd, char *fmt, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Run cmd ... */
|
/* Run cmd ... */
|
||||||
status = run(cmd);
|
status = run(cmd, "");
|
||||||
|
|
||||||
/* Restore stderr/stdout */
|
/* Restore stderr/stdout */
|
||||||
if (fp && !debug) {
|
if (fp && !debug) {
|
||||||
@@ -222,7 +260,6 @@ int run_interactive(char *cmd, char *fmt, ...)
|
|||||||
|
|
||||||
int exec_runtask(char *cmd, char *args[])
|
int exec_runtask(char *cmd, char *args[])
|
||||||
{
|
{
|
||||||
size_t i;
|
|
||||||
char buf[1024] = "";
|
char buf[1024] = "";
|
||||||
char *argv[4] = {
|
char *argv[4] = {
|
||||||
"sh",
|
"sh",
|
||||||
@@ -230,6 +267,7 @@ int exec_runtask(char *cmd, char *args[])
|
|||||||
buf,
|
buf,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
size_t i;
|
||||||
|
|
||||||
strlcat(buf, cmd, sizeof(buf));
|
strlcat(buf, cmd, sizeof(buf));
|
||||||
for (i = 1; args[i]; i++) {
|
for (i = 1; args[i]; i++) {
|
||||||
|
|||||||
+2
-1
@@ -333,7 +333,8 @@ static void fs_mount_all(void)
|
|||||||
_d("Calling extra mount hook, after mount -a ...");
|
_d("Calling extra mount hook, after mount -a ...");
|
||||||
plugin_run_hooks(HOOK_MOUNT_POST);
|
plugin_run_hooks(HOOK_MOUNT_POST);
|
||||||
|
|
||||||
run("swapon -ea");
|
if (whichp("swapon"))
|
||||||
|
run("swapon -ea", "swapon");
|
||||||
|
|
||||||
_d("Finalize, ensure common file systems are available ...");
|
_d("Finalize, ensure common file systems are available ...");
|
||||||
fs_finalize();
|
fs_finalize();
|
||||||
|
|||||||
@@ -95,6 +95,7 @@
|
|||||||
#define INIT_CMD_SVC_QUERY 130
|
#define INIT_CMD_SVC_QUERY 130
|
||||||
#define INIT_CMD_SVC_FIND 131
|
#define INIT_CMD_SVC_FIND 131
|
||||||
#define INIT_CMD_SVC_FIND_BYC 132
|
#define INIT_CMD_SVC_FIND_BYC 132
|
||||||
|
#define INIT_CMD_SIGNAL 133
|
||||||
#define INIT_CMD_NACK 254
|
#define INIT_CMD_NACK 254
|
||||||
#define INIT_CMD_ACK 255
|
#define INIT_CMD_ACK 255
|
||||||
|
|
||||||
|
|||||||
+68
-9
@@ -30,6 +30,7 @@
|
|||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <sysexits.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#ifdef _LIBITE_LITE
|
#ifdef _LIBITE_LITE
|
||||||
# include <libite/lite.h>
|
# include <libite/lite.h>
|
||||||
@@ -40,6 +41,7 @@
|
|||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "private.h"
|
#include "private.h"
|
||||||
|
#include "sig.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "utmp-api.h"
|
#include "utmp-api.h"
|
||||||
|
|
||||||
@@ -57,7 +59,7 @@ static pstyle_t progress_style = PROGRESS_DEFAULT;
|
|||||||
#define STATUS_CLASS { \
|
#define STATUS_CLASS { \
|
||||||
CHOOSE(" OK ", " OK ", "\e[1;32m"), /* Green */ \
|
CHOOSE(" OK ", " OK ", "\e[1;32m"), /* Green */ \
|
||||||
CHOOSE("FAIL", "FAIL", "\e[1;31m"), /* Red */ \
|
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 */ \
|
CHOOSE(" \\/ ", " ⋯ ", "\e[1;33m"), /* Yellow */ \
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -493,27 +495,46 @@ void networking(int updown)
|
|||||||
|
|
||||||
/* Debian/Ubuntu/Busybox/RH/Suse */
|
/* Debian/Ubuntu/Busybox/RH/Suse */
|
||||||
if (!whichp("ifup"))
|
if (!whichp("ifup"))
|
||||||
goto done;
|
goto fallback;
|
||||||
|
|
||||||
if (fexist("/etc/network/interfaces")) {
|
if (fexist("/etc/network/interfaces")) {
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
|
if (!updown) {
|
||||||
|
run_interactive("ifdown -a", "Stopping networking");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
if (updown)
|
int rc = EX_OSERR;
|
||||||
run("ifup -a");
|
FILE *pp;
|
||||||
else
|
|
||||||
run("ifdown -a");
|
setsid();
|
||||||
_exit(0);
|
sig_unblock();
|
||||||
|
|
||||||
|
pp = popen("ifup -a 2>&1", "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);
|
cgroup_service("network", pid, NULL);
|
||||||
|
print(pid > 0 ? 0 : 1, "Bringing up network interfaces ...");
|
||||||
|
|
||||||
print(pid > 0 ? 0 : 1, "%s networking", updown ? "Starting" : "Stopping");
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
fallback:
|
||||||
/* Fall back to bring up at least loopback */
|
/* Fall back to bring up at least loopback */
|
||||||
ifconfig("lo", "127.0.0.1", "255.0.0.0", updown);
|
ifconfig("lo", "127.0.0.1", "255.0.0.0", updown);
|
||||||
|
done:
|
||||||
|
|
||||||
/* Hooks that rely on loopback, or basic networking being up. */
|
/* Hooks that rely on loopback, or basic networking being up. */
|
||||||
if (updown) {
|
if (updown) {
|
||||||
@@ -522,6 +543,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
|
#ifndef HAVE_GETFSENT
|
||||||
static lfile_t *fstab = NULL;
|
static lfile_t *fstab = NULL;
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -93,9 +93,10 @@ int mksubsys (const char *dir, mode_t mode, char *user, char *group);
|
|||||||
|
|
||||||
void set_hostname (char **hostname);
|
void set_hostname (char **hostname);
|
||||||
void networking (int updown);
|
void networking (int updown);
|
||||||
|
int in_container (void);
|
||||||
|
|
||||||
int complete (char *cmd, int pid);
|
int complete (char *cmd, int pid);
|
||||||
int run (char *cmd);
|
int run (char *cmd, char *log);
|
||||||
int run_interactive (char *cmd, char *fmt, ...);
|
int run_interactive (char *cmd, char *fmt, ...);
|
||||||
int exec_runtask (char *cmd, char *args[]);
|
int exec_runtask (char *cmd, char *args[]);
|
||||||
pid_t run_getty (char *tty, char *cmd, char *args[], int noclear, int nowait, struct rlimit rlimit[]);
|
pid_t run_getty (char *tty, char *cmd, char *args[], int noclear, int nowait, struct rlimit rlimit[]);
|
||||||
|
|||||||
+125
-45
@@ -52,6 +52,7 @@ struct cmd {
|
|||||||
struct cmd *ctx;
|
struct cmd *ctx;
|
||||||
int (*cb)(char *arg);
|
int (*cb)(char *arg);
|
||||||
int *cond;
|
int *cond;
|
||||||
|
int (*cb_multiarg)(int argc, char **argv);
|
||||||
};
|
};
|
||||||
|
|
||||||
int icreate = 0;
|
int icreate = 0;
|
||||||
@@ -160,8 +161,11 @@ static int do_log(char *svc)
|
|||||||
if (!svc || !svc[0])
|
if (!svc || !svc[0])
|
||||||
svc = "finit";
|
svc = "finit";
|
||||||
|
|
||||||
if (!fexist(logfile))
|
if (!fexist(logfile)) {
|
||||||
logfile = "/var/log/messages";
|
logfile = "/var/log/messages";
|
||||||
|
if (!fexist(logfile))
|
||||||
|
return 0; /* bail out, maybe in container */
|
||||||
|
}
|
||||||
|
|
||||||
return systemf("cat %s | grep %s | tail -10", logfile, svc);
|
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);
|
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)
|
static int dump_one_cond(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftwbuf)
|
||||||
{
|
{
|
||||||
const char *cond, *asserted;
|
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) {
|
if (strncmp("pid/", cond, 4) == 0) {
|
||||||
svc_t *svc;
|
svc_t *svc;
|
||||||
|
|
||||||
svc= client_svc_find_by_cond(cond);
|
svc = client_svc_find_by_cond(cond);
|
||||||
if (!svc) {
|
if (!svc) {
|
||||||
nm = "unknown";
|
nm = "unknown";
|
||||||
pid = 0;
|
pid = 0;
|
||||||
@@ -722,7 +781,7 @@ static int show_status(char *arg)
|
|||||||
|
|
||||||
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
|
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
|
||||||
svc_ident(svc, ident, sizeof(ident));
|
svc_ident(svc, ident, sizeof(ident));
|
||||||
if (string_match(ident, arg))
|
if (string_compare(ident, arg))
|
||||||
num++;
|
num++;
|
||||||
if (string_case_compare(ident, arg))
|
if (string_case_compare(ident, arg))
|
||||||
exact++;
|
exact++;
|
||||||
@@ -735,8 +794,15 @@ static int show_status(char *arg)
|
|||||||
if (!svc)
|
if (!svc)
|
||||||
return 255;
|
return 255;
|
||||||
|
|
||||||
if (quiet)
|
if (quiet) {
|
||||||
|
if (svc_is_runtask(svc))
|
||||||
|
if (svc->started)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
return svc->state != SVC_RUNNING_STATE;
|
return svc->state != SVC_RUNNING_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
pidfn = svc->pidfile;
|
pidfn = svc->pidfile;
|
||||||
if (pidfn[0] == '!')
|
if (pidfn[0] == '!')
|
||||||
@@ -765,6 +831,8 @@ static int show_status(char *arg)
|
|||||||
char *group;
|
char *group;
|
||||||
|
|
||||||
group = pid_cgroup(svc->pid, grbuf, sizeof(grbuf));
|
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);
|
snprintf(path, sizeof(path), "%s/%s", FINIT_CGPATH, group);
|
||||||
cg = cg_conf(path);
|
cg = cg_conf(path);
|
||||||
|
|
||||||
@@ -774,6 +842,7 @@ static int show_status(char *arg)
|
|||||||
cg->cg_mem.min, cg->cg_mem.max);
|
cg->cg_mem.min, cg->cg_mem.max);
|
||||||
show_cgroup_tree(group, " ");
|
show_cgroup_tree(group, " ");
|
||||||
}
|
}
|
||||||
|
no_cgroup:
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
return do_log(svc->cmd);
|
return do_log(svc->cmd);
|
||||||
@@ -797,7 +866,7 @@ static int show_status(char *arg)
|
|||||||
char *lvls;
|
char *lvls;
|
||||||
|
|
||||||
svc_ident(svc, ident, sizeof(ident));
|
svc_ident(svc, ident, sizeof(ident));
|
||||||
if (num && !string_match(ident, arg))
|
if (num && !string_compare(ident, arg))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
printf("%-*d ", pw, svc->pid);
|
printf("%-*d ", pw, svc->pid);
|
||||||
@@ -891,12 +960,13 @@ static int usage(int rc)
|
|||||||
" -q, --quiet Silent, only return status of command\n"
|
" -q, --quiet Silent, only return status of command\n"
|
||||||
" -t, --no-heading Skip table headings\n"
|
" -t, --no-heading Skip table headings\n"
|
||||||
" -v, --verbose Verbose output\n"
|
" -v, --verbose Verbose output\n"
|
||||||
|
" -V, --version Show program version\n"
|
||||||
" -h, --help This help text\n"
|
" -h, --help This help text\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Commands:\n"
|
"Commands:\n"
|
||||||
" debug Toggle Finit (daemon) debug\n"
|
" debug Toggle Finit (daemon) debug\n"
|
||||||
" help This help text\n"
|
" help This help text\n"
|
||||||
" version Show Finit version\n"
|
" version Show program version\n"
|
||||||
"\n", prognm);
|
"\n", prognm);
|
||||||
|
|
||||||
if (has_rcsd)
|
if (has_rcsd)
|
||||||
@@ -938,6 +1008,7 @@ static int usage(int rc)
|
|||||||
" stop <NAME>[:ID] Stop/Pause a running service by name\n"
|
" stop <NAME>[:ID] Stop/Pause a running service by name\n"
|
||||||
" reload <NAME>[:ID] Reload service by name (SIGHUP or restart)\n"
|
" reload <NAME>[:ID] Reload service by name (SIGHUP or restart)\n"
|
||||||
" restart <NAME>[:ID] Restart (stop/start) service by name\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"
|
" ident [NAME] Show matching identities for NAME, or all\n"
|
||||||
" status <NAME>[:ID] Show service status, by name\n"
|
" status <NAME>[:ID] Show service status, by name\n"
|
||||||
" status Show status of services, default command\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]))
|
if (!cmd_cond(&command[i]))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!string_match(command[i].cmd, argv[0]))
|
if (!string_compare(command[i].cmd, argv[0]))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (command[i].ctx)
|
if (command[i].ctx)
|
||||||
return cmd_parse(argc - 1, &argv[1], 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) {
|
if (command[i].cb) {
|
||||||
int rc = 0;
|
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 */
|
return command[0].cb(NULL); /* default cmd */
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct option long_options[] = {
|
struct option long_options[] = {
|
||||||
@@ -1031,55 +1106,57 @@ int main(int argc, char *argv[])
|
|||||||
{ "quiet", 0, NULL, 'q' },
|
{ "quiet", 0, NULL, 'q' },
|
||||||
{ "no-heading", 0, NULL, 't' },
|
{ "no-heading", 0, NULL, 't' },
|
||||||
{ "verbose", 0, NULL, 'v' },
|
{ "verbose", 0, NULL, 'v' },
|
||||||
|
{ "version", 0, NULL, 'V' },
|
||||||
{ NULL, 0, NULL, 0 }
|
{ NULL, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
struct cmd cond[] = {
|
struct cmd cond[] = {
|
||||||
{ "status", NULL, do_cond_show, NULL }, /* default cmd */
|
{ "status", NULL, do_cond_show, NULL, NULL }, /* default cmd */
|
||||||
{ "dump", NULL, do_cond_dump, NULL },
|
{ "dump", NULL, do_cond_dump, NULL, NULL },
|
||||||
{ "set", NULL, do_cond_set, NULL },
|
{ "set", NULL, do_cond_set, NULL, NULL },
|
||||||
{ "clr", NULL, do_cond_clr, NULL },
|
{ "clr", NULL, do_cond_clr, NULL, NULL },
|
||||||
{ "clear", NULL, do_cond_clr, NULL },
|
{ "clear", NULL, do_cond_clr, NULL, NULL },
|
||||||
{ NULL, NULL, NULL, NULL }
|
{ NULL, NULL, NULL, NULL, NULL }
|
||||||
};
|
};
|
||||||
struct cmd command[] = {
|
struct cmd command[] = {
|
||||||
{ "status", NULL, show_status, NULL }, /* default cmd */
|
{ "status", NULL, show_status, NULL, NULL }, /* default cmd */
|
||||||
{ "ident", NULL, show_ident, NULL },
|
{ "ident", NULL, show_ident, NULL, NULL },
|
||||||
|
|
||||||
{ "debug", NULL, toggle_debug, NULL },
|
{ "debug", NULL, toggle_debug, NULL, NULL },
|
||||||
{ "devel", NULL, do_devel, NULL },
|
{ "devel", NULL, do_devel, NULL, NULL },
|
||||||
{ "help", NULL, do_help, NULL },
|
{ "help", NULL, do_help, NULL, NULL },
|
||||||
{ "version", NULL, show_version, NULL },
|
{ "version", NULL, show_version, NULL, NULL },
|
||||||
|
|
||||||
{ "list", NULL, serv_list, NULL },
|
{ "list", NULL, serv_list, NULL, NULL },
|
||||||
{ "ls", NULL, serv_list, NULL },
|
{ "ls", NULL, serv_list, NULL, NULL },
|
||||||
{ "enable", NULL, serv_enable, NULL },
|
{ "enable", NULL, serv_enable, NULL, NULL },
|
||||||
{ "disable", NULL, serv_disable, NULL },
|
{ "disable", NULL, serv_disable, NULL, NULL },
|
||||||
{ "touch", NULL, serv_touch, NULL },
|
{ "touch", NULL, serv_touch, NULL, NULL },
|
||||||
{ "show", NULL, serv_show, NULL },
|
{ "show", NULL, serv_show, NULL, NULL },
|
||||||
{ "edit", NULL, serv_edit, NULL },
|
{ "edit", NULL, serv_edit, NULL, NULL },
|
||||||
{ "create", NULL, serv_creat, NULL },
|
{ "create", NULL, serv_creat, NULL, NULL },
|
||||||
{ "delete", NULL, serv_delete, NULL },
|
{ "delete", NULL, serv_delete, NULL, NULL },
|
||||||
{ "reload", NULL, do_reload, NULL },
|
{ "reload", NULL, do_reload, NULL, NULL },
|
||||||
|
|
||||||
{ "cond", cond, NULL, NULL },
|
{ "cond", cond, NULL, NULL, NULL },
|
||||||
|
|
||||||
{ "log", NULL, do_log, NULL },
|
{ "log", NULL, do_log, NULL, NULL },
|
||||||
{ "start", NULL, do_start, NULL },
|
{ "start", NULL, do_start, NULL, NULL },
|
||||||
{ "stop", NULL, do_stop, NULL },
|
{ "stop", NULL, do_stop, NULL, NULL },
|
||||||
{ "restart", NULL, do_restart, NULL },
|
{ "restart", NULL, do_restart, NULL, NULL },
|
||||||
|
{ "signal", NULL, NULL, NULL, do_signal },
|
||||||
|
|
||||||
{ "cgroup", NULL, show_cgroup, &cgrp },
|
{ "cgroup", NULL, show_cgroup, &cgrp, NULL },
|
||||||
{ "ps", NULL, show_cgps, &cgrp },
|
{ "ps", NULL, show_cgps, &cgrp, NULL },
|
||||||
{ "top", NULL, show_cgtop, &cgrp },
|
{ "top", NULL, show_cgtop, &cgrp, NULL },
|
||||||
|
|
||||||
{ "runlevel", NULL, do_runlevel, NULL },
|
{ "runlevel", NULL, do_runlevel, NULL, NULL },
|
||||||
{ "reboot", NULL, do_reboot, NULL },
|
{ "reboot", NULL, do_reboot, NULL, NULL },
|
||||||
{ "halt", NULL, do_halt, NULL },
|
{ "halt", NULL, do_halt, NULL, NULL },
|
||||||
{ "poweroff", NULL, do_poweroff, NULL },
|
{ "poweroff", NULL, do_poweroff, NULL, NULL },
|
||||||
{ "suspend", NULL, do_suspend, NULL },
|
{ "suspend", NULL, do_suspend, NULL, NULL },
|
||||||
|
|
||||||
{ "utmp", NULL, do_utmp, &utmp },
|
{ "utmp", NULL, do_utmp, &utmp, NULL },
|
||||||
{ NULL, NULL, NULL, NULL }
|
{ NULL, NULL, NULL, NULL, NULL }
|
||||||
};
|
};
|
||||||
int interactive = 1, c;
|
int interactive = 1, c;
|
||||||
|
|
||||||
@@ -1090,7 +1167,7 @@ int main(int argc, char *argv[])
|
|||||||
cgrp = cgroup_avail();
|
cgrp = cgroup_avail();
|
||||||
utmp = has_utmp();
|
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) {
|
switch(c) {
|
||||||
case '1':
|
case '1':
|
||||||
ionce = 1;
|
ionce = 1;
|
||||||
@@ -1131,6 +1208,9 @@ int main(int argc, char *argv[])
|
|||||||
case 'v':
|
case 'v':
|
||||||
verbose = 1;
|
verbose = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'V':
|
||||||
|
return show_version(NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "iwatch.h"
|
#include "iwatch.h"
|
||||||
@@ -39,6 +40,9 @@ static int initialized = 0;
|
|||||||
|
|
||||||
int iwatch_init(struct iwatch *iw)
|
int iwatch_init(struct iwatch *iw)
|
||||||
{
|
{
|
||||||
|
socklen_t len;
|
||||||
|
int sz;
|
||||||
|
|
||||||
if (!iw) {
|
if (!iw) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -51,6 +55,16 @@ int iwatch_init(struct iwatch *iw)
|
|||||||
_pe("Failed creating inotify descriptor");
|
_pe("Failed creating inotify descriptor");
|
||||||
return -1;
|
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))
|
||||||
|
setsockopt(iw->fd, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz));
|
||||||
|
|
||||||
initialized = 1;
|
initialized = 1;
|
||||||
|
|
||||||
return iw->fd;
|
return iw->fd;
|
||||||
|
|||||||
@@ -59,18 +59,24 @@ void log_exit(void)
|
|||||||
enable_progress(1);
|
enable_progress(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void log_open(void)
|
static int log_open(void)
|
||||||
{
|
{
|
||||||
int opts = LOG_PID;
|
int opts;
|
||||||
|
|
||||||
|
if (up)
|
||||||
|
return 1;
|
||||||
|
if (access("/dev/log", W_OK))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
opts = LOG_CONS | LOG_PID;
|
||||||
|
if (debug)
|
||||||
|
opts |= LOG_PERROR;
|
||||||
|
|
||||||
closelog();
|
closelog();
|
||||||
|
|
||||||
if (debug)
|
|
||||||
opts |= LOG_PERROR; /* LOG_CONS | */
|
|
||||||
openlog("finit", opts, LOG_DAEMON);
|
openlog("finit", opts, LOG_DAEMON);
|
||||||
setlogmask(LOG_UPTO(loglevel));
|
setlogmask(LOG_UPTO(loglevel));
|
||||||
|
|
||||||
up = 1;
|
return up = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Toggle debug mode */
|
/* Toggle debug mode */
|
||||||
@@ -95,15 +101,12 @@ void log_debug(void)
|
|||||||
*/
|
*/
|
||||||
void logit(int prio, const char *fmt, ...)
|
void logit(int prio, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
|
|
||||||
if (up || fexist("/dev/log")) {
|
if (up || log_open()) {
|
||||||
if (!up)
|
|
||||||
log_open();
|
|
||||||
|
|
||||||
vsyslog(prio, fmt, ap);
|
vsyslog(prio, fmt, ap);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@@ -111,9 +114,9 @@ void logit(int prio, const char *fmt, ...)
|
|||||||
if (LOG_PRI(prio) > loglevel)
|
if (LOG_PRI(prio) > loglevel)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
fp = fopen("/dev/kmsg", "w");
|
if (in_container() || !(fp = fopen("/dev/kmsg", "w"))) {
|
||||||
if (!fp) {
|
|
||||||
vfprintf(stderr, fmt, ap);
|
vfprintf(stderr, fmt, ap);
|
||||||
|
fputs("\n", stderr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,6 +128,7 @@ void logit(int prio, const char *fmt, ...)
|
|||||||
va_end(ap);
|
va_end(ap);
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
vfprintf(stderr, fmt, ap);
|
vfprintf(stderr, fmt, ap);
|
||||||
|
fputs("\n", stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
|||||||
@@ -40,10 +40,10 @@
|
|||||||
* The default log level is LOG_NOTICE. To toggle LOG_DEBUG messages,
|
* The default log level is LOG_NOTICE. To toggle LOG_DEBUG messages,
|
||||||
* use `initctl debug` or add `debug` to the kernel cmdline.
|
* use `initctl debug` or add `debug` to the kernel cmdline.
|
||||||
*/
|
*/
|
||||||
#define _d(fmt, args...) logit(LOG_DEBUG, "%s():" fmt "\n", __func__, ##args)
|
#define _d(fmt, args...) logit(LOG_DEBUG, "%s():" fmt, __func__, ##args)
|
||||||
#define _w(fmt, args...) logit(LOG_WARNING, "%s():" fmt "\n", __func__, ##args)
|
#define _w(fmt, args...) logit(LOG_WARNING, "%s():" fmt, __func__, ##args)
|
||||||
#define _e(fmt, args...) logit(LOG_ERR, "%s():" fmt "\n", __func__, ##args)
|
#define _e(fmt, args...) logit(LOG_ERR, "%s():" fmt, __func__, ##args)
|
||||||
#define _pe(fmt, args...) logit(LOG_ERR, "%s():" fmt ": %s\n", __func__, ##args, strerror(errno))
|
#define _pe(fmt, args...) logit(LOG_ERR, "%s():" fmt ": %n", __func__, ##args, strerror(errno))
|
||||||
|
|
||||||
void log_init (void);
|
void log_init (void);
|
||||||
void log_exit (void);
|
void log_exit (void);
|
||||||
|
|||||||
@@ -98,11 +98,6 @@ static void do_kill(int signo, char *msg)
|
|||||||
do_sleep(5);
|
do_sleep(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sig(int signo)
|
|
||||||
{
|
|
||||||
(void)signo; /* NOP */
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usage(int rc)
|
static int usage(int rc)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Usage: %s [OPTIONS]\n\n"
|
fprintf(stderr, "Usage: %s [OPTIONS]\n\n"
|
||||||
@@ -164,9 +159,6 @@ int reboot_main(int argc, char *argv[])
|
|||||||
/* Check for any overrides */
|
/* Check for any overrides */
|
||||||
transform(NULL);
|
transform(NULL);
|
||||||
|
|
||||||
/* Catch and ignore SIGTERM on halt/poweroff */
|
|
||||||
signal(SIGTERM, sig);
|
|
||||||
|
|
||||||
if (force) {
|
if (force) {
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case CMD_REBOOT:
|
case CMD_REBOOT:
|
||||||
|
|||||||
+75
-17
@@ -571,6 +571,7 @@ static int service_start(svc_t *svc)
|
|||||||
} else {
|
} else {
|
||||||
i = 0;
|
i = 0;
|
||||||
args[i++] = svc->cmd;
|
args[i++] = svc->cmd;
|
||||||
|
args[i++] = svc->cmd;
|
||||||
args[i++] = "start";
|
args[i++] = "start";
|
||||||
}
|
}
|
||||||
args[i] = NULL;
|
args[i] = NULL;
|
||||||
@@ -628,10 +629,13 @@ static int service_start(svc_t *svc)
|
|||||||
switch (svc->type) {
|
switch (svc->type) {
|
||||||
case SVC_TYPE_RUN:
|
case SVC_TYPE_RUN:
|
||||||
svc->status = complete(svc->cmd, pid);
|
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;
|
result = 0;
|
||||||
else
|
} else {
|
||||||
|
svc->started = 0;
|
||||||
result = 1;
|
result = 1;
|
||||||
|
}
|
||||||
svc->start_time = svc->pid = 0;
|
svc->start_time = svc->pid = 0;
|
||||||
svc->once++;
|
svc->once++;
|
||||||
svc_set_state(svc, SVC_STOPPING_STATE);
|
svc_set_state(svc, SVC_STOPPING_STATE);
|
||||||
@@ -701,7 +705,7 @@ static void service_cleanup(svc_t *svc)
|
|||||||
utmp_set_dead(svc->pid); /* Set DEAD_PROCESS UTMP entry */
|
utmp_set_dead(svc->pid); /* Set DEAD_PROCESS UTMP entry */
|
||||||
|
|
||||||
svc->oldpid = svc->pid;
|
svc->oldpid = svc->pid;
|
||||||
svc->start_time = svc->pid = 0;
|
svc->starting = svc->start_time = svc->pid = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -743,8 +747,6 @@ static int service_stop(svc_t *svc)
|
|||||||
*/
|
*/
|
||||||
svc_started(svc);
|
svc_started(svc);
|
||||||
|
|
||||||
svc_set_state(svc, SVC_STOPPING_STATE);
|
|
||||||
|
|
||||||
if (!svc->desc[0])
|
if (!svc->desc[0])
|
||||||
do_progress = 0;
|
do_progress = 0;
|
||||||
|
|
||||||
@@ -755,12 +757,17 @@ static int service_stop(svc_t *svc)
|
|||||||
if (svc->pid > 1) {
|
if (svc->pid > 1) {
|
||||||
/* Kill all children in the same proess group, e.g. logit */
|
/* Kill all children in the same proess group, e.g. logit */
|
||||||
rc = kill(-svc->pid, svc->sighalt);
|
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 */
|
/* PID lost or forking process never really started */
|
||||||
if (rc == -1 && ESRCH == errno)
|
if (rc == -1 && (errno == ESRCH || errno == ENOENT)) {
|
||||||
service_cleanup(svc);
|
service_cleanup(svc);
|
||||||
|
svc_set_state(svc, SVC_HALTED_STATE);
|
||||||
} else
|
} else
|
||||||
|
svc_set_state(svc, SVC_STOPPING_STATE);
|
||||||
|
} else {
|
||||||
service_cleanup(svc);
|
service_cleanup(svc);
|
||||||
|
svc_set_state(svc, SVC_HALTED_STATE);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
char *args[] = { svc->cmd, "stop", NULL };
|
char *args[] = { svc->cmd, "stop", NULL };
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
@@ -778,7 +785,7 @@ static int service_stop(svc_t *svc)
|
|||||||
rc = 1;
|
rc = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
rc = WEXITSTATUS(complete(svc->cmd, pid));
|
svc_set_state(svc, SVC_STOPPING_STATE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -829,7 +836,7 @@ static int service_restart(svc_t *svc)
|
|||||||
logit(LOG_CONSOLE | LOG_NOTICE, "Restarting %s[%d], sending SIGHUP ...",
|
logit(LOG_CONSOLE | LOG_NOTICE, "Restarting %s[%d], sending SIGHUP ...",
|
||||||
svc_ident(svc, NULL, 0), svc->pid);
|
svc_ident(svc, NULL, 0), svc->pid);
|
||||||
rc = kill(svc->pid, SIGHUP);
|
rc = kill(svc->pid, SIGHUP);
|
||||||
if (rc == -1 && errno == ESRCH) {
|
if (rc == -1 && (errno == ESRCH || errno == ENOENT)) {
|
||||||
/* nobody home, reset internal state machine */
|
/* nobody home, reset internal state machine */
|
||||||
lost = svc->pid;
|
lost = svc->pid;
|
||||||
} else {
|
} else {
|
||||||
@@ -880,7 +887,7 @@ void service_runlevel(int newlevel)
|
|||||||
sm_set_runlevel(&sm, newlevel);
|
sm_set_runlevel(&sm, newlevel);
|
||||||
sm_step(&sm);
|
sm_step(&sm);
|
||||||
|
|
||||||
if (!rescue && runlevel <= 1)
|
if (!rescue && (runlevel <= 1 || runlevel == 6))
|
||||||
networking(0);
|
networking(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1318,7 +1325,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Decode any optional pid:/optional/path/to/file.pid */
|
/* Decode any optional pid:/optional/path/to/file.pid */
|
||||||
if (pid && svc_is_daemon(svc) && pid_file_parse(svc, pid))
|
if (pid && (svc_is_daemon(svc) || svc_is_sysv(svc)) && pid_file_parse(svc, pid))
|
||||||
_e("Invalid 'pid' argument to service: %s", pid);
|
_e("Invalid 'pid' argument to service: %s", pid);
|
||||||
|
|
||||||
if (username) {
|
if (username) {
|
||||||
@@ -1548,6 +1555,34 @@ static void service_kill_script(svc_t *svc)
|
|||||||
kill(-svc->pid, SIGKILL);
|
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", fn, 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)
|
static void service_pre_script(svc_t *svc)
|
||||||
{
|
{
|
||||||
svc->pid = service_fork(svc);
|
svc->pid = service_fork(svc);
|
||||||
@@ -1564,7 +1599,7 @@ static void service_pre_script(svc_t *svc)
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
setenv("SERVICE_IDENT", svc_ident(svc, NULL, 0), 1);
|
set_pre_post_envs(svc, "pre");
|
||||||
execvp(_PATH_BSHELL, argv);
|
execvp(_PATH_BSHELL, argv);
|
||||||
_exit(EX_OSERR);
|
_exit(EX_OSERR);
|
||||||
}
|
}
|
||||||
@@ -1593,7 +1628,7 @@ static void service_post_script(svc_t *svc)
|
|||||||
rc = WEXITSTATUS(svc->status);
|
rc = WEXITSTATUS(svc->status);
|
||||||
sig = WTERMSIG(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)) {
|
if (WIFEXITED(svc->status)) {
|
||||||
char val[4];
|
char val[4];
|
||||||
@@ -1621,7 +1656,7 @@ static void service_retry(svc_t *svc)
|
|||||||
|
|
||||||
service_timeout_cancel(svc);
|
service_timeout_cancel(svc);
|
||||||
if (svc->respawn) {
|
if (svc->respawn) {
|
||||||
_d("%s crashed, respawning ...", svc->cmd);
|
_d("%s crashed/exited, respawning ...", svc->cmd);
|
||||||
svc_unblock(svc);
|
svc_unblock(svc);
|
||||||
service_step(svc);
|
service_step(svc);
|
||||||
return;
|
return;
|
||||||
@@ -1677,6 +1712,27 @@ static void svc_set_state(svc_t *svc, svc_state_t new)
|
|||||||
service_timeout_cancel(svc);
|
service_timeout_cancel(svc);
|
||||||
service_timeout_after(svc, svc->killdelay, service_kill);
|
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 +1775,15 @@ restart:
|
|||||||
|
|
||||||
case SVC_STOPPING_STATE:
|
case SVC_STOPPING_STATE:
|
||||||
if (!svc->pid) {
|
if (!svc->pid) {
|
||||||
char cond[MAX_COND_LEN];
|
char condstr[MAX_COND_LEN];
|
||||||
|
|
||||||
_d("%s: stopped, cleaning up timers and conditions ...", svc->cmd);
|
_d("%s: stopped, cleaning up timers and conditions ...", svc->cmd);
|
||||||
service_timeout_cancel(svc);
|
service_timeout_cancel(svc);
|
||||||
cond_clear(mkcond(svc, cond, sizeof(cond)));
|
cond_clear(mkcond(svc, condstr, sizeof(condstr)));
|
||||||
|
|
||||||
switch (svc->type) {
|
switch (svc->type) {
|
||||||
case SVC_TYPE_SERVICE:
|
case SVC_TYPE_SERVICE:
|
||||||
|
case SVC_TYPE_SYSV:
|
||||||
case SVC_TYPE_TTY:
|
case SVC_TYPE_TTY:
|
||||||
if (svc_has_post(svc)) {
|
if (svc_has_post(svc)) {
|
||||||
svc_set_state(svc, SVC_CLEANUP_STATE);
|
svc_set_state(svc, SVC_CLEANUP_STATE);
|
||||||
@@ -1737,7 +1794,6 @@ restart:
|
|||||||
|
|
||||||
case SVC_TYPE_TASK:
|
case SVC_TYPE_TASK:
|
||||||
case SVC_TYPE_RUN:
|
case SVC_TYPE_RUN:
|
||||||
case SVC_TYPE_SYSV:
|
|
||||||
svc_set_state(svc, SVC_DONE_STATE);
|
svc_set_state(svc, SVC_DONE_STATE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1797,6 +1853,7 @@ restart:
|
|||||||
* Restart directly after the first crash,
|
* Restart directly after the first crash,
|
||||||
* then retry after 2 sec
|
* then retry after 2 sec
|
||||||
*/
|
*/
|
||||||
|
if (!svc->respawn)
|
||||||
_d("delayed restart of %s", svc->cmd);
|
_d("delayed restart of %s", svc->cmd);
|
||||||
service_timeout_after(svc, 1, service_retry);
|
service_timeout_after(svc, 1, service_retry);
|
||||||
break;
|
break;
|
||||||
@@ -1813,6 +1870,7 @@ restart:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
service_timeout_cancel(svc);
|
||||||
|
|
||||||
cond = cond_get_agg(svc->cond);
|
cond = cond_get_agg(svc->cond);
|
||||||
switch (cond) {
|
switch (cond) {
|
||||||
|
|||||||
@@ -71,6 +71,7 @@
|
|||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <string.h> /* strerror() */
|
#include <string.h> /* strerror() */
|
||||||
|
#include <sched.h>
|
||||||
#include <sys/reboot.h>
|
#include <sys/reboot.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#ifdef _LIBITE_LITE
|
#ifdef _LIBITE_LITE
|
||||||
@@ -172,7 +173,7 @@ void unmount_regular(void);
|
|||||||
*
|
*
|
||||||
* https://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons/
|
* 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;
|
DIR *dirp;
|
||||||
|
|
||||||
@@ -191,6 +192,8 @@ void do_kill(int signo)
|
|||||||
pid = atoi(d->d_name);
|
pid = atoi(d->d_name);
|
||||||
if (!pid)
|
if (!pid)
|
||||||
continue;
|
continue;
|
||||||
|
if (pid == 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
snprintf(file, sizeof(file), "/proc/%s/cmdline", d->d_name);
|
snprintf(file, sizeof(file), "/proc/%s/cmdline", d->d_name);
|
||||||
fp = fopen(file, "r");
|
fp = fopen(file, "r");
|
||||||
@@ -203,7 +206,10 @@ void do_kill(int signo)
|
|||||||
else if (file[0] == '@')
|
else if (file[0] == '@')
|
||||||
_d("Skipping %s ...", &file[1]);
|
_d("Skipping %s ...", &file[1]);
|
||||||
else
|
else
|
||||||
kill(pid, signo);
|
if (cb(pid, data)) {
|
||||||
|
print(0, "PID %d is still alive (%s)", pid, file);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
@@ -211,8 +217,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)
|
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)
|
if (sdown)
|
||||||
run_interactive(sdown, "Calling shutdown hook: %s", sdown);
|
run_interactive(sdown, "Calling shutdown hook: %s", sdown);
|
||||||
|
|
||||||
@@ -223,9 +282,11 @@ void do_shutdown(shutop_t op)
|
|||||||
* Tell remaining non-monitored processes to exit, give them
|
* Tell remaining non-monitored processes to exit, give them
|
||||||
* time to exit gracefully, 2 sec was customary, we go for 1.
|
* time to exit gracefully, 2 sec was customary, we go for 1.
|
||||||
*/
|
*/
|
||||||
do_kill(SIGTERM);
|
do_iterate_proc(kill_cb, &signo);
|
||||||
do_sleep(1);
|
if (do_wait(1)) {
|
||||||
do_kill(SIGKILL);
|
signo = SIGKILL;
|
||||||
|
do_iterate_proc(kill_cb, &signo);
|
||||||
|
}
|
||||||
|
|
||||||
/* Exit plugins and API gracefully */
|
/* Exit plugins and API gracefully */
|
||||||
plugin_exit();
|
plugin_exit();
|
||||||
@@ -235,6 +296,12 @@ void do_shutdown(shutop_t op)
|
|||||||
while (waitpid(-1, NULL, WNOHANG) > 0)
|
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 */
|
/* Close all local non-console descriptors */
|
||||||
for (int fd = 3; fd < 128; fd++)
|
for (int fd = 3; fd < 128; fd++)
|
||||||
close(fd);
|
close(fd);
|
||||||
@@ -255,16 +322,14 @@ void do_shutdown(shutop_t op)
|
|||||||
|
|
||||||
/* Unmount any tmpfs before unmounting swap ... */
|
/* Unmount any tmpfs before unmounting swap ... */
|
||||||
unmount_tmpfs();
|
unmount_tmpfs();
|
||||||
run("swapoff -e -a");
|
if (whichp("swapoff"))
|
||||||
|
run("swapoff -e -a", "swapoff");
|
||||||
|
|
||||||
/* ... unmount remaining regular file systems. */
|
/* ... unmount remaining regular file systems. */
|
||||||
unmount_regular();
|
unmount_regular();
|
||||||
|
|
||||||
/* We sit on / so we must remount it ro, try all the things! */
|
/* We sit on / so we must remount it read-only */
|
||||||
sync();
|
run("mount -n -o remount,ro -t none rootfs /", "mount");
|
||||||
run("mount -n -o remount,ro -t dummytype dummydev /");
|
|
||||||
run("mount -n -o remount,ro dummydev /");
|
|
||||||
run("mount -n -o remount,ro /");
|
|
||||||
|
|
||||||
/* Call mdadm to mark any RAID array(s) as clean before halting. */
|
/* Call mdadm to mark any RAID array(s) as clean before halting. */
|
||||||
mdadm_wait();
|
mdadm_wait();
|
||||||
|
|||||||
@@ -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)) {
|
for (svc = svc_iterator(iter, first); svc; svc = svc_iterator(iter, 0)) {
|
||||||
char *name = svc->name;
|
char *name = svc->name;
|
||||||
|
|
||||||
if (!strncmp(name, cmd, strlen(name)))
|
if (string_compare(name, cmd))
|
||||||
return svc;
|
return svc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -473,7 +473,17 @@ svc_t *svc_find_by_pidfile(char *fn)
|
|||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
pid = pid_file_read(fn);
|
pid = pid_file_read(fn);
|
||||||
if (pid <= 0) {
|
if (pid > 1) {
|
||||||
|
svc = svc_find_by_pid(pid);
|
||||||
|
if (svc)
|
||||||
|
return svc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
int v = 0;
|
int v = 0;
|
||||||
|
|
||||||
@@ -485,16 +495,6 @@ svc_t *svc_find_by_pidfile(char *fn)
|
|||||||
return svc;
|
return svc;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
|
||||||
if (svc->pid != pid)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
return svc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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)
|
* 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;
|
char *input, *token;
|
||||||
int result = 0;
|
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) {
|
if (!ptr) {
|
||||||
svc = svc_job_iterator(&iter, 1, job);
|
svc = svc_job_iterator(&iter, 1, job);
|
||||||
if (!svc && not_found)
|
if (!svc && not_found)
|
||||||
result += not_found(NULL, token);
|
result += not_found(NULL, token, user_data);
|
||||||
|
|
||||||
while (svc) {
|
while (svc) {
|
||||||
if (found)
|
if (found)
|
||||||
result += found(svc);
|
result += found(svc, user_data);
|
||||||
svc = svc_job_iterator(&iter, 0, job);
|
svc = svc_job_iterator(&iter, 0, job);
|
||||||
}
|
}
|
||||||
} else {
|
} 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);
|
svc = svc_find_by_jobid(job, id);
|
||||||
if (!svc && not_found)
|
if (!svc && not_found)
|
||||||
result += not_found(token, id);
|
result += not_found(token, id, user_data);
|
||||||
else if (found)
|
else if (found)
|
||||||
result += found(svc);
|
result += found(svc, user_data);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!ptr) {
|
if (!ptr) {
|
||||||
svc = svc_named_iterator(&iter, 1, token);
|
svc = svc_named_iterator(&iter, 1, token);
|
||||||
if (!svc && not_found)
|
if (!svc && not_found)
|
||||||
result += not_found(token, id);
|
result += not_found(token, id, user_data);
|
||||||
|
|
||||||
while (svc) {
|
while (svc) {
|
||||||
if (found)
|
if (found)
|
||||||
result += found(svc);
|
result += found(svc, user_data);
|
||||||
svc = svc_named_iterator(&iter, 0, token);
|
svc = svc_named_iterator(&iter, 0, token);
|
||||||
}
|
}
|
||||||
} else {
|
} 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);
|
svc = svc_find_by_nameid(token, id);
|
||||||
if (!svc && not_found)
|
if (!svc && not_found)
|
||||||
result += not_found(token, id);
|
result += not_found(token, id, user_data);
|
||||||
else if (found)
|
else if (found)
|
||||||
result += found(svc);
|
result += found(svc, user_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ void svc_prune_bootstrap (void);
|
|||||||
void svc_enable (svc_t *svc);
|
void svc_enable (svc_t *svc);
|
||||||
int svc_enabled (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_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_sysv (svc_t *svc) { return svc && SVC_TYPE_SYSV == svc->type; }
|
||||||
@@ -278,6 +278,31 @@ static inline int svc_has_cond(svc_t *svc)
|
|||||||
return 0;
|
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)
|
static inline char *svc_status(svc_t *svc)
|
||||||
{
|
{
|
||||||
if (!svc)
|
if (!svc)
|
||||||
@@ -307,7 +332,10 @@ static inline char *svc_status(svc_t *svc)
|
|||||||
return "unknown";
|
return "unknown";
|
||||||
|
|
||||||
case SVC_DONE_STATE:
|
case SVC_DONE_STATE:
|
||||||
|
if (svc->started)
|
||||||
return "done";
|
return "done";
|
||||||
|
else
|
||||||
|
return "failed";
|
||||||
|
|
||||||
case SVC_STOPPING_STATE:
|
case SVC_STOPPING_STATE:
|
||||||
switch (svc->type) {
|
switch (svc->type) {
|
||||||
|
|||||||
+39
-3
@@ -264,17 +264,39 @@ int strtobytes(char *arg)
|
|||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *sig2str(int sig)
|
char *sig2str(int signo)
|
||||||
{
|
{
|
||||||
static char signame[8];
|
static char signame[8];
|
||||||
|
|
||||||
if (sig < 1 || sig >= (int)NELEMS(signames))
|
if (signo < 1 || signo >= (int)NELEMS(signames))
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
snprintf(signame, sizeof(signame), "/%s", signames[sig]);
|
snprintf(signame, sizeof(signame), "/%s", signames[signo]);
|
||||||
return signame;
|
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)
|
char *code2str(int code)
|
||||||
{
|
{
|
||||||
static char codename[20];
|
static char codename[20];
|
||||||
@@ -297,6 +319,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() */
|
/* Seconds since boot, from sysinfo() */
|
||||||
long jiffies(void)
|
long jiffies(void)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -61,9 +61,11 @@ int fngetint (char *path, int *val);
|
|||||||
|
|
||||||
int strtobytes (char *arg);
|
int strtobytes (char *arg);
|
||||||
char *sig2str (int sig);
|
char *sig2str (int sig);
|
||||||
|
int str2sig (char *sig);
|
||||||
char *code2str (int code);
|
char *code2str (int code);
|
||||||
|
|
||||||
void do_sleep (unsigned int sec);
|
void do_sleep (unsigned int sec);
|
||||||
|
void do_usleep (unsigned int usec);
|
||||||
long jiffies (void);
|
long jiffies (void);
|
||||||
char *uptime (long secs, char *buf, size_t len);
|
char *uptime (long secs, char *buf, size_t len);
|
||||||
char *memsz (uint64_t sz, char *buf, size_t len);
|
char *memsz (uint64_t sz, char *buf, size_t len);
|
||||||
|
|||||||
+11
-5
@@ -1,12 +1,14 @@
|
|||||||
EXTRA_DIST = tenv/lib.sh tenv/exec.sh tenv/start.sh
|
SUBDIRS = common tenv
|
||||||
EXTRA_DIST += tenv/root.mk tenv/busybox-x86_64.md5
|
|
||||||
EXTRA_DIST += tenv/chrootsetup.sh
|
EXTRA_DIST = setup-root.sh
|
||||||
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.sh
|
||||||
EXTRA_DIST += add-remove-dynamic-service-sub-config.sh
|
EXTRA_DIST += add-remove-dynamic-service-sub-config.sh
|
||||||
EXTRA_DIST += start-stop-service.sh
|
EXTRA_DIST += start-stop-service.sh
|
||||||
EXTRA_DIST += start-stop-service-sub-config.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 = TENV_ROOT='$(abs_builddir)/tenv-root/';
|
||||||
AM_TESTS_ENVIRONMENT += export TENV_ROOT;
|
AM_TESTS_ENVIRONMENT += export TENV_ROOT;
|
||||||
@@ -26,6 +28,10 @@ TESTS += add-remove-dynamic-service.sh
|
|||||||
TESTS += add-remove-dynamic-service-sub-config.sh
|
TESTS += add-remove-dynamic-service-sub-config.sh
|
||||||
TESTS += start-stop-service.sh
|
TESTS += start-stop-service.sh
|
||||||
TESTS += start-stop-service-sub-config.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:
|
clean-local:
|
||||||
-rm -rf $(builddir)/tenv-root/
|
-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.
|
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
|
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
|
directory it will be able to function properly without having any super user
|
||||||
privileges in the host environment.
|
privileges in the host environment.
|
||||||
|
|
||||||
|
|
||||||
Running tests
|
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
|
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. To execute an individual test, simply invoke the script containing it:
|
||||||
|
|
||||||
./test/name-of-the-test.sh
|
./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,7 +7,8 @@ TEST_DIR=$(dirname "$0")
|
|||||||
# shellcheck source=/dev/null
|
# shellcheck source=/dev/null
|
||||||
. "$TEST_DIR/tenv/lib.sh"
|
. "$TEST_DIR/tenv/lib.sh"
|
||||||
|
|
||||||
test_teardown() {
|
test_teardown()
|
||||||
|
{
|
||||||
say "Test done $(date)"
|
say "Test done $(date)"
|
||||||
say "Running test teardown."
|
say "Running test teardown."
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ say "Test start $(date)"
|
|||||||
cp "$TEST_DIR"/common/service.sh "$TENV_ROOT"/test_assets/
|
cp "$TEST_DIR"/common/service.sh "$TENV_ROOT"/test_assets/
|
||||||
|
|
||||||
say "Add a dynamic service in $FINIT_RCSD/service.conf"
|
say "Add a dynamic service in $FINIT_RCSD/service.conf"
|
||||||
texec sh -c "echo 'service [2345] kill:20 log /test_assets/service.sh' > $FINIT_RCSD/service.conf"
|
texec sh -c "echo 'service [2345] kill:20 log /test_assets/service.sh -- Dyn serv' > $FINIT_RCSD/service.conf"
|
||||||
|
|
||||||
say 'Reload Finit'
|
say 'Reload Finit'
|
||||||
texec sh -c "initctl reload"
|
texec sh -c "initctl reload"
|
||||||
|
|||||||
@@ -3,11 +3,13 @@
|
|||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
TEST_DIR=$(dirname "$0")
|
TEST_DIR=$(dirname "$0")
|
||||||
|
export DEBUG=1
|
||||||
|
|
||||||
# shellcheck source=/dev/null
|
# shellcheck source=/dev/null
|
||||||
. "$TEST_DIR/tenv/lib.sh"
|
. "$TEST_DIR/tenv/lib.sh"
|
||||||
|
|
||||||
test_teardown() {
|
test_teardown()
|
||||||
|
{
|
||||||
say "Test done $(date)"
|
say "Test done $(date)"
|
||||||
say "Running test teardown."
|
say "Running test teardown."
|
||||||
|
|
||||||
@@ -15,12 +17,17 @@ test_teardown() {
|
|||||||
texec rm -f /test_assets/service.sh
|
texec rm -f /test_assets/service.sh
|
||||||
}
|
}
|
||||||
|
|
||||||
|
say "Hi, this is /run et al"
|
||||||
|
texec sh -c "echo 'ROOT:/bin'; ls -l /bin/; echo 'ROOT:/sbin'; ls -l /sbin/; echo 'ROOT:/run'; ls -l /run/; echo 'ROOT:/run/finit/'; ls -l /run/finit/; echo 'ROOT:/dev'; ls -l /dev/; ps; ls -l /proc/1/fd/"
|
||||||
|
say "HUPing PID 1 ..."
|
||||||
|
texec sh -c "kill -HUP 1"
|
||||||
|
|
||||||
say "Test start $(date)"
|
say "Test start $(date)"
|
||||||
|
|
||||||
cp "$TEST_DIR"/common/service.sh "$TENV_ROOT"/test_assets/
|
cp "$TEST_DIR"/common/service.sh "$TENV_ROOT"/test_assets/
|
||||||
|
|
||||||
say "Add a dynamic service in $FINIT_CONF"
|
say "Add a dynamic service in $FINIT_CONF"
|
||||||
texec sh -c "echo 'service [2345] kill:20 log /test_assets/service.sh' > $FINIT_CONF"
|
texec sh -c "echo 'service [2345] kill:20 log /test_assets/service.sh -- Dyn service' > $FINIT_CONF"
|
||||||
|
|
||||||
say 'Reload Finit'
|
say 'Reload Finit'
|
||||||
texec sh -c "initctl reload"
|
texec sh -c "initctl reload"
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
/Makefile
|
||||||
|
/Makefile.in
|
||||||
|
|
||||||
|
/.deps/
|
||||||
|
/serv
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
EXTRA_DIST = service.conf service.sh S01-service.sh slay.sh
|
||||||
|
|
||||||
|
noinst_PROGRAMS = serv
|
||||||
|
serv_SOURCES = serv.c
|
||||||
Executable
+51
@@ -0,0 +1,51 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# SysV style start script for service.sh
|
||||||
|
|
||||||
|
DAEMON="/test_assets/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
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
+19
-2
@@ -1,7 +1,24 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
set -eu
|
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
|
while true; do
|
||||||
sleep 5
|
sleep 1
|
||||||
done
|
done
|
||||||
|
|||||||
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"
|
||||||
@@ -4,5 +4,21 @@ set -eu
|
|||||||
|
|
||||||
# shellcheck disable=SC2154
|
# shellcheck disable=SC2154
|
||||||
make -C "$top_builddir" DESTDIR="$TENV_ROOT" install
|
make -C "$top_builddir" DESTDIR="$TENV_ROOT" install
|
||||||
|
|
||||||
# shellcheck disable=SC2154
|
# shellcheck disable=SC2154
|
||||||
FINITBIN="$(pwd)/$top_builddir/src/finit" DEST="$TENV_ROOT" make -f "$srcdir/tenv/root.mk"
|
FINITBIN="$(pwd)/$top_builddir/src/finit" DEST="$TENV_ROOT" make -f "$srcdir/tenv/root.mk"
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
echo "$TENV_ROOT:"
|
||||||
|
ls -l "$TENV_ROOT"
|
||||||
|
echo "$TENV_ROOT:/bin"
|
||||||
|
ls -l "$TENV_ROOT"/bin
|
||||||
|
echo "$TENV_ROOT:/sbin"
|
||||||
|
ls -l "$TENV_ROOT"/sbin
|
||||||
|
echo "$TENV_ROOT:/var"
|
||||||
|
ls -l "$TENV_ROOT"/var/
|
||||||
|
|
||||||
|
|||||||
Executable
+37
@@ -0,0 +1,37 @@
|
|||||||
|
#!/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"
|
||||||
|
texec rm -f /test_assets/service.sh
|
||||||
|
}
|
||||||
|
|
||||||
|
say "Test start $(date)"
|
||||||
|
|
||||||
|
cp "$TEST_DIR"/common/service.sh "$TENV_ROOT"/test_assets/
|
||||||
|
|
||||||
|
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 /test_assets/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
|
||||||
|
# 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"
|
||||||
|
texec rm -f /test_assets/service.sh
|
||||||
|
}
|
||||||
|
|
||||||
|
say "Test start $(date)"
|
||||||
|
|
||||||
|
cp "$TEST_DIR"/common/slay.sh "$TENV_ROOT"/test_assets/
|
||||||
|
cp "$TEST_DIR"/common/service.sh "$TENV_ROOT"/test_assets/
|
||||||
|
rm -f "$TENV_ROOT"/oldpid
|
||||||
|
|
||||||
|
say "Add service stanza in $FINIT_CONF"
|
||||||
|
texec sh -c "echo 'service [2345] respawn log /test_assets/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 "/test_assets/slay.sh service.sh"
|
||||||
|
done
|
||||||
|
|
||||||
|
retry 'assert_new_pid service.sh /run/service.pid'
|
||||||
|
retry 'assert_num_children 1 service.sh'
|
||||||
Executable
+67
@@ -0,0 +1,67 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
TEST_DIR=$(dirname "$0")
|
||||||
|
|
||||||
|
test_setup()
|
||||||
|
{
|
||||||
|
say "Test start $(date)"
|
||||||
|
cp "$TENV_ROOT"/../common/serv "$TENV_ROOT"/test_assets/
|
||||||
|
}
|
||||||
|
|
||||||
|
test_teardown()
|
||||||
|
{
|
||||||
|
say "Test done $(date)"
|
||||||
|
say "Running test teardown."
|
||||||
|
|
||||||
|
texec rm -f "$FINIT_CONF"
|
||||||
|
texec rm -f /test_assets/serv
|
||||||
|
}
|
||||||
|
|
||||||
|
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 /test_assets/serv -- Forking service"
|
||||||
|
# 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 /test_assets/serv -p -- Forking service w/o PID file"
|
||||||
|
test_one "/run/serv.pid" "service pid:/run/serv.pid /test_assets/serv -n -- Foreground service w/o PID file"
|
||||||
|
test_one "/run/serv.pid" "service /test_assets/serv -n -p -- Foreground service w/ PID file"
|
||||||
|
test_one "/run/servy.pid" "service pid:/run/servy.pid /test_assets/serv -n -p -P /run/servy.pid -- Foreground service w/ custom PID file"
|
||||||
@@ -7,7 +7,8 @@ TEST_DIR=$(dirname "$0")
|
|||||||
# shellcheck source=/dev/null
|
# shellcheck source=/dev/null
|
||||||
. "$TEST_DIR/tenv/lib.sh"
|
. "$TEST_DIR/tenv/lib.sh"
|
||||||
|
|
||||||
test_teardown() {
|
test_teardown()
|
||||||
|
{
|
||||||
say "Test done $(date)"
|
say "Test done $(date)"
|
||||||
say "Running test teardown."
|
say "Running test teardown."
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ say "Test start $(date)"
|
|||||||
cp "$TEST_DIR"/common/service.sh "$TENV_ROOT"/test_assets/
|
cp "$TEST_DIR"/common/service.sh "$TENV_ROOT"/test_assets/
|
||||||
|
|
||||||
say "Add service stanza in $FINIT_RCSD/service.conf"
|
say "Add service stanza in $FINIT_RCSD/service.conf"
|
||||||
texec sh -c "echo 'service [2345] kill:20 log /test_assets/service.sh' > $FINIT_RCSD/service.conf"
|
texec sh -c "echo 'service [2345] kill:20 log /test_assets/service.sh -- Subserv' > $FINIT_RCSD/service.conf"
|
||||||
|
|
||||||
say 'Reload Finit'
|
say 'Reload Finit'
|
||||||
texec sh -c "initctl reload"
|
texec sh -c "initctl reload"
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ TEST_DIR=$(dirname "$0")
|
|||||||
# shellcheck source=/dev/null
|
# shellcheck source=/dev/null
|
||||||
. "$TEST_DIR/tenv/lib.sh"
|
. "$TEST_DIR/tenv/lib.sh"
|
||||||
|
|
||||||
test_teardown() {
|
test_teardown()
|
||||||
|
{
|
||||||
say "Test done $(date)"
|
say "Test done $(date)"
|
||||||
say "Running test teardown."
|
say "Running test teardown."
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ say "Test start $(date)"
|
|||||||
cp "$TEST_DIR"/common/service.sh "$TENV_ROOT"/test_assets/
|
cp "$TEST_DIR"/common/service.sh "$TENV_ROOT"/test_assets/
|
||||||
|
|
||||||
say "Add service stanza in $FINIT_CONF"
|
say "Add service stanza in $FINIT_CONF"
|
||||||
texec sh -c "echo 'service [2345] kill:20 log /test_assets/service.sh' > $FINIT_CONF"
|
texec sh -c "echo 'service [2345] kill:20 log /test_assets/service.sh -- Test service' > $FINIT_CONF"
|
||||||
|
|
||||||
say 'Reload Finit'
|
say 'Reload Finit'
|
||||||
texec sh -c "initctl reload"
|
texec sh -c "initctl reload"
|
||||||
|
|||||||
Executable
+42
@@ -0,0 +1,42 @@
|
|||||||
|
#!/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"
|
||||||
|
texec rm -f /test_assets/service.sh
|
||||||
|
}
|
||||||
|
|
||||||
|
say "Test start $(date)"
|
||||||
|
|
||||||
|
cp "$TEST_DIR"/common/service.sh "$TENV_ROOT"/test_assets/
|
||||||
|
cp "$TEST_DIR"/common/S01-service.sh "$TENV_ROOT"/test_assets/
|
||||||
|
chmod +x "$TENV_ROOT"/test_assets/*.sh
|
||||||
|
|
||||||
|
say "Add sysv stanza in $FINIT_CONF"
|
||||||
|
texec sh -c "echo 'sysv [2345] pid:!/run/service.pid name:service.sh /test_assets/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
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
/Makefile
|
||||||
|
/Makefile.in
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
EXTRA_DIST = lib.sh exec.sh start.sh root.mk busybox-x86_64.md5
|
||||||
|
EXTRA_DIST += chrootsetup.sh
|
||||||
+48
-18
@@ -21,21 +21,37 @@
|
|||||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
# THE SOFTWARE.
|
# THE SOFTWARE.
|
||||||
|
|
||||||
assert_num_children() {
|
assert_num_children()
|
||||||
|
{
|
||||||
assert "$1 services are running" "$(texec pgrep -P 1 "$2" | wc -l)" -eq "$1"
|
assert "$1 services are running" "$(texec pgrep -P 1 "$2" | wc -l)" -eq "$1"
|
||||||
}
|
}
|
||||||
|
|
||||||
texec() {
|
# shellcheck disable=SC2086
|
||||||
# shellcheck disable=SC2154
|
assert_new_pid()
|
||||||
|
{
|
||||||
|
assert "Finit has registered new PID" "$(texec initctl |grep $1 |awk '{print $1}')" -eq "$(texec cat $2)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
assert_pidfile()
|
||||||
|
{
|
||||||
|
assert "Process has PID file" "$(texec find $1 2>/dev/null)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# shellcheck disable=SC2154
|
||||||
|
texec()
|
||||||
|
{
|
||||||
"$TEST_DIR/tenv/exec.sh" "$finit_pid" "$@"
|
"$TEST_DIR/tenv/exec.sh" "$finit_pid" "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
pause() {
|
pause()
|
||||||
|
{
|
||||||
echo "Press any key to continue... "
|
echo "Press any key to continue... "
|
||||||
read -r REPLY
|
read -r REPLY
|
||||||
}
|
}
|
||||||
|
|
||||||
toggle_finit_debug() {
|
toggle_finit_debug()
|
||||||
|
{
|
||||||
say 'Toggle finit debug'
|
say 'Toggle finit debug'
|
||||||
texec initctl debug
|
texec initctl debug
|
||||||
sleep 0.5
|
sleep 0.5
|
||||||
@@ -45,23 +61,30 @@ color_reset='\e[0m'
|
|||||||
fg_red='\e[1;31m'
|
fg_red='\e[1;31m'
|
||||||
fg_green='\e[1;32m'
|
fg_green='\e[1;32m'
|
||||||
fg_yellow='\e[1;33m'
|
fg_yellow='\e[1;33m'
|
||||||
log() {
|
log()
|
||||||
printf "< %s > %b%b%b %s\n" "$0" "$1" "$2" "$color_reset" "$3"
|
{
|
||||||
|
test=$(basename "$0" ".sh")
|
||||||
|
printf "\e[2m[%s]\e[0m %b%b%b %s\n" "$test" "$1" "$2" "$color_reset" "$3"
|
||||||
}
|
}
|
||||||
|
|
||||||
assert() {
|
assert()
|
||||||
|
{
|
||||||
__assert_msg=$1
|
__assert_msg=$1
|
||||||
shift
|
shift
|
||||||
|
|
||||||
if [ ! "$@" ]; then
|
if [ ! "$@" ]; then
|
||||||
log "$fg_red" ✘ "$__assert_msg ($*)"
|
log "$fg_red" ✘ "$__assert_msg ($*)"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
log "$fg_green" ✔ "$__assert_msg"
|
log "$fg_green" ✔ "$__assert_msg"
|
||||||
}
|
}
|
||||||
|
|
||||||
retry() {
|
retry()
|
||||||
|
{
|
||||||
__retry_cmd=$1
|
__retry_cmd=$1
|
||||||
shift
|
shift
|
||||||
|
|
||||||
case "$#" in
|
case "$#" in
|
||||||
2)
|
2)
|
||||||
__retry_n=$1
|
__retry_n=$1
|
||||||
@@ -83,16 +106,20 @@ retry() {
|
|||||||
echo "$__retry_cmd_out" && \
|
echo "$__retry_cmd_out" && \
|
||||||
return 0
|
return 0
|
||||||
done
|
done
|
||||||
|
|
||||||
__retry_cmd_exit="$?"
|
__retry_cmd_exit="$?"
|
||||||
echo "$__retry_cmd_out"
|
echo "$__retry_cmd_out"
|
||||||
|
|
||||||
return "$__retry_cmd_exit"
|
return "$__retry_cmd_exit"
|
||||||
}
|
}
|
||||||
|
|
||||||
say() {
|
say()
|
||||||
|
{
|
||||||
log "$fg_yellow" • "$@"
|
log "$fg_yellow" • "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
teardown() {
|
teardown()
|
||||||
|
{
|
||||||
test_status="$?"
|
test_status="$?"
|
||||||
|
|
||||||
if type test_teardown > /dev/null 2>&1 ; then
|
if type test_teardown > /dev/null 2>&1 ; then
|
||||||
@@ -111,9 +138,6 @@ teardown() {
|
|||||||
|
|
||||||
wait
|
wait
|
||||||
|
|
||||||
if [ -d "$TENV_ROOT/var/lock" ]; then
|
|
||||||
chmod +r "$TENV_ROOT/var/lock"
|
|
||||||
fi
|
|
||||||
rm -f "$TENV_ROOT"/running_test.pid
|
rm -f "$TENV_ROOT"/running_test.pid
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,15 +154,21 @@ if [ -n "${DEBUG:-}" ]; then
|
|||||||
FINIT_ARGS="${FINIT_ARGS:-} finit.debug=on"
|
FINIT_ARGS="${FINIT_ARGS:-} finit.debug=on"
|
||||||
fi
|
fi
|
||||||
# shellcheck disable=2086
|
# shellcheck disable=2086
|
||||||
"$TEST_DIR/tenv/start.sh" finit ${FINIT_ARGS:-} &
|
"$TEST_DIR/tenv/start.sh" finit ${FINIT_ARGS:-} finit.debug=on &
|
||||||
finit_ppid=$!
|
finit_ppid=$!
|
||||||
echo "$finit_ppid" > "$TENV_ROOT"/running_test.pid
|
echo "$finit_ppid" > "$TENV_ROOT"/running_test.pid
|
||||||
|
|
||||||
|
>&2 echo "Finit runs as PID $finit_ppid outside of container."
|
||||||
>&2 echo "Hint: Execute 'TENV_ROOT=$TENV_ROOT $TEST_DIR/tenv/enter.sh' to enter the test namespace"
|
>&2 echo "Hint: Execute 'TENV_ROOT=$TENV_ROOT $TEST_DIR/tenv/enter.sh' to enter the test namespace"
|
||||||
log "$color_reset" 'Setup of test environment done' ''
|
log "$color_reset" 'Setup of test environment done' ''
|
||||||
|
|
||||||
finit_pid=$(retry "pgrep -P $finit_ppid")
|
finit_pid=$(retry "pgrep -P $finit_ppid")
|
||||||
|
|
||||||
tty=/dev/$(texec cat /sys/class/tty/console/active)
|
if type test_setup > /dev/null 2>&1 ; then
|
||||||
texec cat "$tty" &
|
test_setup
|
||||||
sleep 1
|
fi
|
||||||
|
|
||||||
|
#tty=/dev/$(texec cat /sys/class/tty/console/active)
|
||||||
|
#texec cat "$tty" &
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
|||||||
+31
-5
@@ -23,6 +23,7 @@
|
|||||||
DEST ?= ../tenv-root
|
DEST ?= ../tenv-root
|
||||||
srcdir ?= ../
|
srcdir ?= ../
|
||||||
|
|
||||||
|
CACHE ?= ~/.cache
|
||||||
ARCH ?= x86_64
|
ARCH ?= x86_64
|
||||||
|
|
||||||
FINITBIN ?= ./sbin/finit
|
FINITBIN ?= ./sbin/finit
|
||||||
@@ -31,12 +32,14 @@ BBVER ?= 1.31.0
|
|||||||
BBBIN = busybox-$(ARCH)
|
BBBIN = busybox-$(ARCH)
|
||||||
BBURL ?= https://www.busybox.net/downloads/binaries/$(BBVER)-defconfig-multiarch-musl/$(BBBIN)
|
BBURL ?= https://www.busybox.net/downloads/binaries/$(BBVER)-defconfig-multiarch-musl/$(BBBIN)
|
||||||
|
|
||||||
binaries = $(DEST)/bin/cat \
|
binaries = $(DEST)/bin/awk \
|
||||||
|
$(DEST)/bin/cat \
|
||||||
$(DEST)/bin/cp \
|
$(DEST)/bin/cp \
|
||||||
$(DEST)/bin/date \
|
$(DEST)/bin/date \
|
||||||
$(DEST)/bin/echo \
|
$(DEST)/bin/echo \
|
||||||
$(DEST)/bin/env \
|
$(DEST)/bin/env \
|
||||||
$(DEST)/bin/find \
|
$(DEST)/bin/find \
|
||||||
|
$(DEST)/bin/grep \
|
||||||
$(DEST)/bin/kill \
|
$(DEST)/bin/kill \
|
||||||
$(DEST)/bin/ls \
|
$(DEST)/bin/ls \
|
||||||
$(DEST)/bin/mkdir \
|
$(DEST)/bin/mkdir \
|
||||||
@@ -49,14 +52,18 @@ binaries = $(DEST)/bin/cat \
|
|||||||
$(DEST)/bin/rm \
|
$(DEST)/bin/rm \
|
||||||
$(DEST)/bin/sh \
|
$(DEST)/bin/sh \
|
||||||
$(DEST)/bin/sleep \
|
$(DEST)/bin/sleep \
|
||||||
|
$(DEST)/bin/tail \
|
||||||
$(DEST)/bin/top \
|
$(DEST)/bin/top \
|
||||||
$(DEST)/bin/touch
|
$(DEST)/bin/touch \
|
||||||
|
$(DEST)/bin/start-stop-daemon
|
||||||
|
|
||||||
dirs = $(DEST)/bin \
|
dirs = $(DEST)/bin \
|
||||||
$(DEST)/dev \
|
$(DEST)/dev \
|
||||||
$(DEST)/etc \
|
$(DEST)/etc \
|
||||||
$(DEST)/proc \
|
$(DEST)/proc \
|
||||||
$(DEST)/sbin \
|
$(DEST)/sbin \
|
||||||
|
$(DEST)/var \
|
||||||
|
$(DEST)/run \
|
||||||
$(DEST)/sys \
|
$(DEST)/sys \
|
||||||
$(DEST)/test_assets \
|
$(DEST)/test_assets \
|
||||||
$(DEST)/tmp
|
$(DEST)/tmp
|
||||||
@@ -65,6 +72,7 @@ _libs_src = $(shell ldd $(FINITBIN) | grep -Eo '/[^ ]+')
|
|||||||
libs = $(foreach path,$(_libs_src),$(abspath $(DEST))$(path))
|
libs = $(foreach path,$(_libs_src),$(abspath $(DEST))$(path))
|
||||||
|
|
||||||
all: $(dirs) $(binaries) $(libs) $(DEST)/bin/chrootsetup.sh
|
all: $(dirs) $(binaries) $(libs) $(DEST)/bin/chrootsetup.sh
|
||||||
|
touch $(DEST)/etc/fstab
|
||||||
|
|
||||||
$(dirs):
|
$(dirs):
|
||||||
mkdir -p $@
|
mkdir -p $@
|
||||||
@@ -72,11 +80,29 @@ $(dirs):
|
|||||||
$(DEST)/bin/$(BBBIN).md5:
|
$(DEST)/bin/$(BBBIN).md5:
|
||||||
cp $(srcdir)/tenv/$(notdir $@) $@
|
cp $(srcdir)/tenv/$(notdir $@) $@
|
||||||
|
|
||||||
|
.PHONY: $(DEST)/bin/$(BBBIN)
|
||||||
$(DEST)/bin/$(BBBIN): $(DEST)/bin/$(BBBIN).md5
|
$(DEST)/bin/$(BBBIN): $(DEST)/bin/$(BBBIN).md5
|
||||||
wget -O $@ $(BBURL)
|
@cd $(dir $@)
|
||||||
chmod +x $@
|
@if ! md5sum --status -c $(BBBIN).md5 2>/dev/null; then \
|
||||||
|
if [ -d $(CACHE) ]; then \
|
||||||
|
echo "Cannot find $(BBBIN), checking $(CACHE) ..."; \
|
||||||
|
cd $(CACHE); \
|
||||||
|
cp $(DEST)/bin/$(BBBIN).md5 .; \
|
||||||
|
if ! md5sum --status -c $(BBBIN).md5; then \
|
||||||
|
echo "No $(BBBIN) available downloading ..."; \
|
||||||
|
wget $(BBURL); \
|
||||||
|
else \
|
||||||
|
echo "Found valid $(BBBIN) in cache!"; \
|
||||||
|
fi; \
|
||||||
|
cp $(BBBIN) $@; \
|
||||||
|
else \
|
||||||
|
echo "Cannot find $(BBBIN), downloading ..."; \
|
||||||
|
wget -O $@ $(BBURL); \
|
||||||
|
fi; \
|
||||||
cd $(dir $@); \
|
cd $(dir $@); \
|
||||||
md5sum -c $(BBBIN).md5
|
md5sum -c $(BBBIN).md5; \
|
||||||
|
fi
|
||||||
|
@chmod +x $@
|
||||||
|
|
||||||
$(DEST)/bin/chrootsetup.sh:
|
$(DEST)/bin/chrootsetup.sh:
|
||||||
cp $(srcdir)/tenv/$(notdir $@) $@
|
cp $(srcdir)/tenv/$(notdir $@) $@
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ TENV_ROOT="${TENV_ROOT:-$(pwd)/${TEST_DIR}/tenv-root}"
|
|||||||
unshare=$(command -v unshare)
|
unshare=$(command -v unshare)
|
||||||
chroot=$(command -v chroot)
|
chroot=$(command -v chroot)
|
||||||
|
|
||||||
|
export container="unshare"
|
||||||
export PS1='\w \$ '
|
export PS1='\w \$ '
|
||||||
export PS2='> '
|
export PS2='> '
|
||||||
export PS3='#? '
|
export PS3='#? '
|
||||||
|
|||||||
Reference in New Issue
Block a user