Compare commits

...
30 Commits
Author SHA1 Message Date
Joachim Wiberg 0f4a487328 .github: tests share same sysroot, must run in sequence
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-14 10:28:16 +01:00
Joachim Wiberg f1b5b42919 test: enable debug logs for global-envs
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-14 10:25:30 +01:00
Joachim Wiberg f546129baf test: debug sysvparts
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-14 10:25:30 +01:00
Joachim Wiberg 27451ac3f2 Update ChangeLog and bump version for v4.9-rc1
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-14 06:26:27 +01:00
Joachim Wiberg 0a8f3a6250 Fix #425: flush .conf file events before reload and runlevel change
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-13 07:06:13 +01:00
Joachim Wiberg 70c4e7d774 iwatch: ensure adding a new watcher is idempotent
Some subsystems call iwatch_add() without first calling iwatch_del() on
the same path.  E.g., cgroup_config().

Issue #417 but unclear atm. if this is the root cause.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-13 05:53:24 +01:00
Joachim Wiberg 5265eee25d test: slightly more robust checkself.sh
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-11 10:17:35 +01:00
Joachim Wiberg 4b06e1a49f Silence overly verbose debug messages in cond_set/clear/update
These functions call other functions that log more detailed information.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-11 10:17:35 +01:00
Joachim Wiberg 6b9aa21509 Minor cleanup, code (style) and comments
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-11 10:17:35 +01:00
Joachim Wiberg 990307fbc9 Fix kill() on timeout of pre:/post:/ready:scripts
A long running pre/post/ready script must be killed properly, not by
targeting its process group.  Process group cleanup is handled by the
service_monitor() when reaping the script's PID.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-11 10:17:34 +01:00
Joachim Wiberg 9d8a9b7fba Check for pre:- and post:scripts in $PATH
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-11 10:17:34 +01:00
Joachim Wiberg bbc83eaa64 test: new test
New test adds /bin/fail.sh to verify that a failing pre:script (that
also takes too long to run) is detected: exit code and timeout.

Ensure existing test pass full path to /sbin/fail.sh script.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-11 10:17:33 +01:00
Joachim Wiberg 23d034f521 Prevent main process from starting if pre: script fails
Check exit status of `pre:` scripts, on failure drive service/sysv to
`crashed` state.  The exit code of `post:` scripts remain ignored for
now.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-11 09:39:40 +01:00
Joachim Wiberg 9a3148a49d Bump version to v4.9-beta1 and update ChangeLog
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-10 10:43:38 +01:00
Joachim Wiberg 8560103a24 Add individual timeout support for pre/post/ready scripts
Syntax:
    [pre|post|ready]:[0-3600,]/path/to/script

Description:
    Before this patch all pre/post/ready scripts used the global kill
    delay as timeout.  After this patch it is possible to disable the
    timeout as well as set a timeout >60, which is max kill delay.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-10 10:43:37 +01:00
Joachim Wiberg 7a75e34808 Fix initctl touch of template services
Follow-up to 465bc17, which addressed unintended restart of siblings.
This patch fixes a problem where template instantiated services are not
properly reloaded/restarted when marked as "dirty" with `initctl touch`.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-10 10:43:37 +01:00
Joachim Wiberg 4d4fc10d57 plugins: rtc: follow-up to bc8118d
In save() RTC, ensure the RTC_FILE option is actually enabled.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-10 10:43:29 +01:00
Joachim Wiberg 003faae9e9 .github: disable apparmarmor to allow testing in unshare
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-03 10:23:45 +01:00
Joachim Wiberg 01a01d65c0 Merge pull request #424 from aanderse/container/systemd-nspawn
Add systemd-nspawn to the list of container types

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-02-03 07:13:33 +01:00
Aaron Andersen 048302f06a add systemd-nspawn to the list of container types 2025-02-02 08:58:36 -05:00
Joachim Wiberg 74f0fcfccd Merge pull request #422 from az143/fstab-nofail 2024-12-20 02:18:09 +01:00
az 3cfe0a33b8 fstab with UUID/LABEL: nofail handling for fsck
add support for 'nofail' fstab option. if present, finit's fsck invocation ignores errors for this device.

this is useful if you have an fstab entry for a device with UUID= or LABEL= which isn't always present and which you'd like to not
bail on (so you set nofail). in this case finit leaves the presence-or-not decision to fsck, which exits nonzero.

for block devices that are directly listed in fstab this change isn't important, because for such finit looks for the blockdev's existence and skips the fsck if n/a.
2024-12-20 09:09:24 +10:00
Joachim Wiberg 465bc17ca4 Fix unintended restart of template siblings
Consider the case where container@.conf is an available template.  When
creating a container@foo.conf it will share the same base .conf as an
existing container@bar.conf, but we do not expect to restart bar just
because foo is instantiated.

Up until this change, all template siblings were considered "dirty" if a
new one was created or updated.  Skipping realpath() for all files that
have a '@' works around the problem.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-11-28 11:13:44 +01:00
Joachim Wiberg d4889b435d Merge pull request #419 from troglobit/rtc
RTC plugin fixes and extension

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-11-04 10:48:26 +01:00
Joachim Wiberg 49c0557ced plugins: reduce log level LOG_ERR -> LOG_WARNING
These plugins signal success and failure directly to the console, the
user should inspect syslog for more information.

This change is a follow-up to 340cae4, where kernel logs of LOG_ERR and
higher are allowed to log directly to the console.  Since syslogd has
not been started before these plugins, the log messages would otherwise
leak to the console.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-11-04 10:42:45 +01:00
Joachim Wiberg 6be16f2f6d Fix buggy --with-rtc-date=DATE, introduced in Finit v4.4
In 42ef3d3c, for v4.4-rc1, support for setting a custom RTC restore date
was introduced.  Unfortunately the configure script was wrong and caused
config.h to contain

    #define RTC_TIMESTAMP_CUSTOM "$rtc_date"

instead of

    #define RTC_TIMESTAMP_CUSTOM "2023-04-10 14:35:42"

Furthermore, the error handling for strptime() was wrong, so the restore
date was always reverted to the default.

This patch fixes both issues and extends the DATE of --with-rtc-date to
also include seconds.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-11-04 10:42:45 +01:00
Joachim Wiberg bc8118d515 Fix #418: support systems with a broken RTC
This patch introduces a new configure option --with-rtc-file=FILE.  When
enabled the RTC plugin detects missing RTC device and falls back to save
and restore system time from a file instead.  When --with-rtc-file is
used without an argument the default file is /var/lib/misc/rtc, but the
feature itself is disabled by default.

The usefulness of this feature may not be obvious at first, but some
systems are equipped with an RTC that resets to a random date at power
on.  This can be really bad in the case the date is far in the future,
because an NTP sync would then cause time skips backwards, which shows
up in logs and causes a whole lot of pain in alarm systems.

The solution is to disable the RTC driver or device tree node, and when
Finit starts up, the RTC plugin detects a the device node and instead
restores time from the last save game.  Meaning time will always only
move forwards.

NOTE: when Finit is built --with-rtc-file we always save to disk, but
      only restore from the "save game" if restoring from RTC fails.
      If the system has no RTC we always restore from disk.

      As an added bonus, this change also makes sure to periodically
      sync also the RTC with the system clock.  Useful for systems
      that do not run an NTP client.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-11-04 10:40:35 +01:00
Joachim Wiberg 0c0e880f3f plugins: refactor rtc.so
Factor out time_set() and time_get() for readability and reuse.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-11-03 09:45:27 +01:00
Joachim Wiberg 119e66a7e9 Reset color attributes and clear screen when starting up
Some boot loaders, like GRUB, leave background color artifacts from
their boot menu.  This patch resets the foreground and background
color attributes, and then clears the screen, without clearing the
scrollback buffer.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-10-28 10:58:04 +01:00
Joachim Wiberg 46ffa81f5c Only mark rdeps dirty if main service is nohup
This patch changes a behavior that's been default since Finit 4.0,
introduced in 4d05bf9 with 4.0-rc2.

If service B depends on A and A needs to be reloaded, then B may be
affected.  If A is declared as NOHUP <!>, then A will be stopped and
restarted, during which time the condition it provides is removed,
and B will also be stopped.

However, and as of this patch, if A is declared supporting HUP, then the
condition A provides will only go into flux, during which time B will be
SIGSTOPed instead of needing to be reloaded.

Fix #415

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-10-17 14:33:30 +02:00
23 changed files with 514 additions and 171 deletions
+6 -4
View File
@@ -21,7 +21,6 @@ jobs:
compiler: [gcc, clang]
fail-fast: false
env:
MAKEFLAGS: -j3
CC: ${{ matrix.compiler }}
steps:
- name: Install dependencies
@@ -33,14 +32,14 @@ jobs:
run: |
./autogen.sh
./configure --prefix= --enable-static
make V=1
make -j3 V=1
- name: Regular Finit
run: |
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
--enable-x11-common-plugin --enable-testserv-plugin --with-watchdog \
--with-keventd
make clean
make V=1
make -j3 clean
make -j3 V=1
- name: Install to /tmp
run: |
DESTDIR=/tmp make install-strip
@@ -57,6 +56,9 @@ jobs:
run: |
sudo /tmp/sbin/finit -h
sudo /tmp/sbin/initctl -h
- name: Enable unprivileged userns (unshare)
run: |
sudo sysctl kernel.apparmor_restrict_unprivileged_userns=0
- name: Run Unit Tests
run: |
make check || (cat test/test-suite.log; false)
+3
View File
@@ -39,6 +39,9 @@ jobs:
./configure --prefix=/usr --exec-prefix= --sysconfdir=/etc --localstatedir=/var \
--enable-x11-common-plugin --enable-testserv-plugin --with-watchdog \
--with-keventd
- name: Enable unprivileged userns (unshare)
run: |
sudo sysctl kernel.apparmor_restrict_unprivileged_userns=0
- name: Build release ...
run: |
make release || (cat test/test-suite.log; false)
+3
View File
@@ -41,6 +41,9 @@ jobs:
- name: Install to /tmp
run: |
DESTDIR=/tmp make install-strip
- name: Enable unprivileged userns (unshare)
run: |
sudo sysctl kernel.apparmor_restrict_unprivileged_userns=0
- name: Check dist tarball
run: |
ver=$(/tmp/sbin/initctl -V | awk '/Finit.*/ {print $2;}')
+37
View File
@@ -4,6 +4,42 @@ Change Log
All relevant changes are documented in this file.
[4.9][UNRELEASED]
--------------------
> [!CAUTION]
> This release changes how Finit reacts to the exit status of `pre:`
> scripts. Finit will now no longer start the main process if its
> `pre:` script fails for any reason. So, if you have pre scripts that,
> e.g., create directories, make sure they are idempotent.
### Changes
- Add individual timeout (optional) support for pre/post/ready scripts
- Add support for systems with broken RTC, i.e., those that at power-on
may reset the RTC to a random date instead of zero, issue #418
- Add support for detecting "in-container" when in `systemd-nspawn`
- Check exit status of `pre:` scripts, on failure drive service/sysv to
`crashed` state. (The exit code of `post:` scripts remain ignored)
- All pre/post/ready scripts are now also searched for in `$PATH`
- Reset color attributes and clear screen when starting up. This is
for boot loaders like GRUB, which leave background color artifacts
### Fixes
- Fix #415: only mark reverse-dependencies "dirty" if the main service
does not support SIGHUP. This helps avoid unnecessary restarts of
services that depend on a service that supports SIGHUP
- Fix #417: leaking inotify watchers in the cgroup subsystem
- Fix #422: honor `notfail` flag in `/etc/fstab`
- Fix #425: ordering bug in detecting .conf file changes to services
and `initctl reload`, or runlevel changes
- Fix `initctl touch` of template services, previously marking a
service created from a template as "dirty" did not take
- Fix unintended restart of template "siblings". I.e., `initctl touch`
of instantiated template service A affected B from same template
- Fix buggy `--with-rtc-date=DATE` configure option
- Fix kill on timeout of pre/post/ready scripts
[4.8][] - 2024-10-13
--------------------
@@ -1705,6 +1741,7 @@ Major bug fix release.
* Initial release
[UNRELEASED]: https://github.com/troglobit/finit/compare/4.8...HEAD
[4.9]: https://github.com/troglobit/finit/compare/4.8...4.9
[4.8]: https://github.com/troglobit/finit/compare/4.7...4.8
[4.7]: https://github.com/troglobit/finit/compare/4.6...4.7
[4.6]: https://github.com/troglobit/finit/compare/4.5...4.6
+15 -3
View File
@@ -1,4 +1,4 @@
AC_INIT([Finit], [4.8], [https://github.com/troglobit/finit/issues],
AC_INIT([Finit], [4.9-rc1], [https://github.com/troglobit/finit/issues],
[finit], [https://troglobit.com/projects/finit/])
AC_CONFIG_AUX_DIR(aux)
AM_INIT_AUTOMAKE([1.11 foreign dist-xz subdir-objects])
@@ -177,9 +177,13 @@ AC_ARG_WITH(plugin-path,
[plugin_path=$withval], [plugin_path=yes])
AC_ARG_WITH(rtc-date,
AS_HELP_STRING([--with-rtc-date=DATE], [If RTC date/time is too old, restore to DATE, format "YYYY-MM-DD HH:MM", default "2000-01-01 00:00"]),
AS_HELP_STRING([--with-rtc-date=DATE], [If RTC date/time is too old, restore to DATE, format "YYYY-MM-DD HH:MM:SS", default "2000-01-01 00:00:00"]),
[rtc_date=$withval], [rtc_date=no])
AC_ARG_WITH(rtc-file,
AS_HELP_STRING([--with-rtc-file=FILE], [If RTC is missing, save and restore system clock from this file, default: no]),
[rtc_file=$withval], [rtc_file=no])
### Enable features ###########################################################################
# Create config.h from selected features and fallback defaults
@@ -278,9 +282,16 @@ AS_IF([test "x$with_random_seed" != "xno"], [
AC_DEFINE_UNQUOTED(RANDOMSEED, "$random_path", [Improve random at boot by seeding it with sth from before.])])
AS_IF([test "x$rtc_date" != "xno"], [
AC_DEFINE(RTC_TIMESTAMP_CUSTOM, "$rtc_date", [Custom RTC restore date, default: 2000-01-01 00:00])], [
AC_DEFINE_UNQUOTED(RTC_TIMESTAMP_CUSTOM, "$rtc_date", [Custom RTC restore date, default: 2000-01-01 00:00])], [
rtc_date=""])
AS_IF([test "x$rtc_file" != "xno"], [
AS_IF([test "x$rtc_file" = "xyes"], [
rtc_file=/var/lib/misc/rtc])
AC_EXPAND_DIR(rtcfile_path, "$rtc_file")
AC_DEFINE_UNQUOTED(RTC_FILE, "$rtcfile_path", [Save and restore system time from this file if /dev/rtc is missing.])],[
AC_DEFINE_UNQUOTED(RTC_FILE, NULL)])
AS_IF([test "x$with_keventd" != "xno"], [with_keventd=yes])
AS_IF([test "x$with_sulogin" != "xno"], [
@@ -387,6 +398,7 @@ Behavior:
Boot heading..........: $heading
Plugins...............: $plugins
RTC restore date......: $RTC_DATE
RTC fallback file.....: $rtc_file
Optional features:
Install doc/..........: $enable_doc
+32 -20
View File
@@ -890,33 +890,45 @@ configurable with the following options:
* `oncrash:script` -- similarly, but instead of rebooting, call the
`post:script` action if set, see below.
When stopping a service (run/task/sysv/service), either manually or
when moving to another runlevel, Finit starts by sending `SIGTERM`, to
allow the process to shut down gracefully. If the process has not
been collected within 3 seconds, Finit sends `SIGKILL`. To halt the
process using a different signal, use the option `halt:SIGNAL`, e.g.,
`halt:SIGPWR`. To change the delay between your halt signal and KILL,
use the option `kill:SEC`, e.g., `kill:10` to wait 10 seconds before
sending `SIGKILL`.
When stopping a service (run/task/sysv/service), either manually or when
moving to another runlevel, Finit starts by sending `SIGTERM`, to allow
the process to shut down gracefully. However, if the process has not
been collected within 3 seconds, Finit will send `SIGKILL`. To stop the
process using a different signal than `SIGTERM`, use `halt:SIGNAL`,
e.g., `halt:SIGPWR`. To change the delay between the stop signal and
KILL, use the option `kill:<1-60>`, e.g., `kill:10` to wait 10 seconds
before sending `SIGKILL`.
Services support `pre:script` and `post:script` actions as well. These
run as the same `@USER:GROUP` as the service itself, with any `env:file`
sourced. The scripts must use an absolute path, but are executed from
the `$HOME` of the given user. The scripts are not called with any
argument (currently), but both get the `SERVICE_IDENT=foo` environment
variable set. Here `foo` denotes the identity of the service, which if
there are multiple services named `foo`, may be `foo:1`, or any unique
identifier specified in the .conf file. The `post:script` is called
with an additional set of environment variables:
Services, including the `sysv` variant, support pre/post/ready scripts:
* `pre:[0-3600,]script`
* `post:[0-3600,]script`
* `ready:[0-3600,]script`
The optional number (0-3600) is the timeout before Finit kills the
script, it defaults to the kill delay value and can be disabled by
setting it to zero. These scripts run as the same `@USER:GROUP` as the
service itself, with any `env:file` sourced. The scripts must use an
absolute path, but are executed from the `$HOME` of the given user. The
scripts are not called with any argument, but get a set of environment
variables:
* `SERVICE_IDENT=foo:1`
* `SERVICE_NAME=foo`
* `SERVICE_ID=1`
The `post:script` is called with an additional set of environment
variables:
- `EXIT_CODE=[exited,signal]`: set to one of `exited` or `signal`
- `EXIT_STATUS=[num,SIGNAME]`: set to one of exit status code from
the program, if it exited normally, or the signal name (`HUP`,
`TERM`, etc.) if it exited due to signal
These script actions *must terminate*, so they have a default execution
time of 3 seconds before they are SIGKILLed, this can be adjusted using
the above `kill:SEC` syntax.
> [!IMPORTANT]
> These script actions are intended for setup, cleanup, and readiness
> notification. It is up to the user to ensure the scripts terminate.
#### Conditional Loading
+180 -64
View File
@@ -36,8 +36,15 @@
#include "helpers.h"
#include "plugin.h"
/* Kernel RTC driver validates against this date for sanity check */
/*
* Kernel RTC driver validates against this date for sanity check. The
* on NTP sync the driver can also update the RTC every 11 mins. We use
* the same update interval to handle manual time set and file save.
*/
#define RTC_TIMESTAMP_BEGIN_2000 "2000-01-01 00:00:00"
#define RTC_FMT "%Y-%m-%d %H:%M:%S"
#define RTC_PERIOD (11 * 60 * 1000)
#ifdef RTC_TIMESTAMP_CUSTOM
static char *rtc_timestamp = RTC_TIMESTAMP_CUSTOM;
#else
@@ -45,6 +52,10 @@ static char *rtc_timestamp = RTC_TIMESTAMP_BEGIN_2000;
#endif
static time_t rtc_date_fallback = 946684800LL;
static char *rtc_file = RTC_FILE;
static uev_t rtc_timer;
static void tz_set(char *tz, size_t len)
{
char *ptr;
@@ -68,6 +79,125 @@ static void tz_restore(char *tz)
tzset();
}
static int time_set(struct tm *tm)
{
struct tm fallback = { 0 };
struct timeval tv = { 0 };
char tz[128];
int rc = 0;
tz_set(tz, sizeof(tz));
if (!tm) {
logit(LOG_NOTICE, "Resetting system clock to kernel default, %s.", rtc_timestamp);
tm = &fallback;
/* Attempt to set RTC to a sane value ... */
tv.tv_sec = rtc_date_fallback;
if (!gmtime_r(&tv.tv_sec, tm)) {
rc = 1;
goto out;
}
}
tm->tm_isdst = -1; /* Use tzdata to figure it out, please. */
tv.tv_sec = mktime(tm);
if (tv.tv_sec == (time_t)-1 || tv.tv_sec < rtc_date_fallback) {
errno = EINVAL;
rc = 2;
} else {
if (settimeofday(&tv, NULL) == -1)
rc = 1;
}
out:
tz_restore(tz);
return rc;
}
static int time_get(struct tm *tm)
{
struct timeval tv = { 0 };
char tz[128];
int rc = 0;
tz_set(tz, sizeof(tz));
rc = gettimeofday(&tv, NULL);
if (rc < 0 || tv.tv_sec < rtc_date_fallback)
rc = 2;
else
gmtime_r(&tv.tv_sec, tm);
tz_restore(tz);
return rc;
}
static void file_save(void *arg)
{
struct tm tm = { 0 };
int rc = 0;
FILE *fp;
if (!rtc_file)
return;
fp = fopen(rtc_file, "w");
if (!fp) {
logit(LOG_WARNING, "Failed saving system clock to %s, code %d: %s",
rtc_file, errno, strerror(errno));
return;
}
if ((rc = time_get(&tm))) {
logit(LOG_WARNING, "System clock invalid, before %s, not saving", rtc_timestamp);
print_desc(NULL, "System clock invalid, skipping");
} else {
char buf[32] = { 0 };
print_desc(NULL, "Saving system clock to file");
strftime(buf, sizeof(buf), RTC_FMT, &tm);
fprintf(fp, "%s\n", buf);
}
print(rc, NULL);
fclose(fp);
}
static void file_restore(void *arg)
{
struct tm tm = { 0 };
int rc = 1;
FILE *fp;
if (!rtc_file) {
logit(LOG_NOTICE, "System has no RTC (missing driver?), skipping restore.");
return;
}
print_desc(NULL, "Restoring system clock from backup");
fp = fopen(rtc_file, "r");
if (fp) {
char buf[32];
if (fgets(buf, sizeof(buf), fp)) {
chomp(buf);
strptime(buf, RTC_FMT, &tm);
rc = time_set(&tm);
}
fclose(fp);
} else
logit(LOG_WARNING, "Missing %s", rtc_file);
if (rc) {
time_set(NULL);
rc = 2;
}
print(rc, NULL);
}
static int rtc_open(void)
{
char *alt[] = {
@@ -91,10 +221,8 @@ static int rtc_open(void)
static void rtc_save(void *arg)
{
struct timeval tv = { 0 };
struct tm tm = { 0 };
int fd, rc = 0;
char tz[128];
if (rescue) {
dbg("Skipping %s plugin in rescue mode.", __FILE__);
@@ -105,38 +233,26 @@ static void rtc_save(void *arg)
if (fd < 0)
return;
tz_set(tz, sizeof(tz));
rc = gettimeofday(&tv, NULL);
if (rc < 0 || tv.tv_sec < rtc_date_fallback) {
if ((rc = time_get(&tm))) {
print_desc(NULL, "System clock invalid, not saving to RTC");
invalid:
logit(LOG_ERR, "System clock invalid, before %s, not saving to RTC", rtc_timestamp);
} else {
print_desc(NULL, "Saving system clock (UTC) to RTC");
rc = ioctl(fd, RTC_SET_TIME, &tm);
}
if (rc && errno == EINVAL) {
logit(LOG_WARNING, "System clock invalid, before %s, not saving to RTC", rtc_timestamp);
rc = 2;
goto out;
}
print_desc(NULL, "Saving system time (UTC) to RTC");
gmtime_r(&tv.tv_sec, &tm);
if (ioctl(fd, RTC_SET_TIME, &tm) < 0) {
if (EINVAL == errno)
goto invalid;
rc = 1;
goto out;
}
out:
tz_restore(tz);
print(rc, NULL);
close(fd);
}
static void rtc_restore(void *arg)
{
struct timeval tv = { 0 };
struct tm tm = { 0 };
int fd, rc = 0;
char tz[128];
if (rescue) {
dbg("Skipping %s plugin in rescue mode.", __FILE__);
@@ -145,66 +261,62 @@ static void rtc_restore(void *arg)
fd = rtc_open();
if (fd < 0) {
logit(LOG_NOTICE, "System has no RTC (missing driver?), skipping restore.");
file_restore(arg);
return;
}
tz_set(tz, sizeof(tz));
if (ioctl(fd, RTC_RD_TIME, &tm) < 0) {
if ((rc = ioctl(fd, RTC_RD_TIME, &tm)) < 0) {
char msg[120];
snprintf(msg, sizeof(msg), "Failed restoring system clock, %s",
EINVAL == errno ? "RTC time is too old" :
ENOENT == errno ? "RTC has no saved time" : "see log for details");
print_desc(NULL, msg);
invalid:
logit(LOG_ERR, "Failed restoring system clock from RTC.");
if (EINVAL == errno)
logit(LOG_ERR, "RTC time is too old (before %s)", rtc_timestamp);
else if (ENOENT == errno)
logit(LOG_ERR, "RTC has no previously saved (valid) time.");
else
logit(LOG_ERR, "RTC error code %d: %s", errno, strerror(errno));
/* Been here already? */
if (rc)
goto out;
/* Attempt to set RTC to a sane value ... */
tv.tv_sec = rtc_date_fallback;
if (!gmtime_r(&tv.tv_sec, &tm))
goto out;
logit(LOG_NOTICE, "Resetting RTC to kernel default, %s.", rtc_timestamp);
rc = 2;
}
if (!rc)
} else {
print_desc(NULL, "Restoring system clock (UTC) from RTC");
tm.tm_isdst = -1; /* Use tzdata to figure it out, please. */
tv.tv_sec = mktime(&tm);
if (tv.tv_sec == (time_t)-1 || tv.tv_sec < rtc_date_fallback) {
errno = EINVAL;
goto invalid;
rc = time_set(&tm);
}
if (settimeofday(&tv, NULL) == -1)
rc = 1;
if (rc) {
logit(LOG_WARNING, "Failed restoring system clock from RTC.");
if (EINVAL == errno)
logit(LOG_WARNING, "RTC time is too old (before %s)", rtc_timestamp);
else if (ENOENT == errno)
logit(LOG_WARNING, "RTC has no previously saved (valid) time.");
else
logit(LOG_WARNING, "RTC error code %d: %s", errno, strerror(errno));
print(2, NULL);
/* Try restoring from last save game */
if (rtc_file)
file_restore(arg);
} else
print(0, NULL);
out:
tz_restore(tz);
print(rc, NULL);
close(fd);
}
static void save(void *arg)
{
rtc_save(arg);
file_save(arg);
}
static void update(uev_t *w, void *arg, int events)
{
save(arg);
}
static plugin_t plugin = {
.name = __FILE__,
.hook[HOOK_BASEFS_UP] = {
.cb = rtc_restore
},
.hook[HOOK_SHUTDOWN] = {
.cb = rtc_save
.cb = save
}
};
@@ -212,10 +324,14 @@ PLUGIN_INIT(plugin_init)
{
struct tm tm = { 0 };
if (!strptime(rtc_timestamp, "%Y-%m-%d %H:%M", &tm))
rtc_date_fallback = mktime(&tm);
else
if (!strptime(rtc_timestamp, RTC_FMT, &tm)) {
logit(LOG_WARNING, "Invalid restore date '%s', reverting to '%s'",
rtc_timestamp, RTC_TIMESTAMP_BEGIN_2000);
rtc_timestamp = RTC_TIMESTAMP_BEGIN_2000;
} else
rtc_date_fallback = mktime(&tm);
uev_timer_init(ctx, &rtc_timer, update, NULL, RTC_PERIOD, RTC_PERIOD);
plugin_register(&plugin);
}
+1 -1
View File
@@ -154,7 +154,7 @@ static void setup(void *arg)
close(fd);
free(rpi);
if (rc < 0)
logit(LOG_ERR, "Failed adding entropy to kernel random pool: %s", strerror(err));
logit(LOG_WARNING, "Failed adding entropy to kernel random pool: %s", strerror(err));
print_result(rc < 0);
return;
fallback:
+3 -3
View File
@@ -288,7 +288,7 @@ int cond_update(const char *name)
svc_t *svc, *iter = NULL;
int affects = 0;
dbg("%s", name);
// dbg("%s", name);
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
if (!svc_has_cond(svc) || !cond_affects(name, svc->cond))
continue;
@@ -321,7 +321,7 @@ int cond_set_noupdate(const char *name)
void cond_set(const char *name)
{
dbg("%s", name);
// dbg("%s", name);
if (cond_set_noupdate(name))
return;
@@ -372,7 +372,7 @@ int cond_clear_noupdate(const char *name)
void cond_clear(const char *name)
{
dbg("%s", name);
// dbg("%s", name);
if (cond_clear_noupdate(name))
return;
+18 -8
View File
@@ -1432,16 +1432,22 @@ static int conf_change_act(char *dir, char *name, uint32_t mask)
strlcpy(fn, dir, sizeof(fn));
dbg("path: %s mask: %08x", fn, mask);
/* Handle disabling/removal of service */
rp = realpath(fn, NULL);
if (!rp) {
if (errno != ENOENT)
goto fail;
if (strchr(name, '@')) {
/* Skip realpath for templates */
rp = strdup(fn);
if (!rp)
goto fail;
} else {
/* Handle disabling/removal of service */
rp = realpath(fn, NULL);
if (!rp) {
if (errno != ENOENT)
goto fail;
rp = strdup(fn);
}
}
if (!rp)
goto fail;
node = conf_find(rp);
if (node) {
dbg("event already registered for %s ...", name);
@@ -1480,7 +1486,11 @@ int conf_changed(char *file)
if (!file)
return 0;
rp = realpath(file, NULL);
if (strchr(file, '@'))
rp = strdup(file);
else
rp = realpath(file, NULL);
if (!rp)
return 0;
+7 -2
View File
@@ -272,8 +272,13 @@ static int fsck(int pass)
* errors were corrected but that the boot may proceed.
*/
if (fsck_rc > 1) {
logit(LOG_CONSOLE | LOG_ALERT, "Failed fsck %s, attempting sulogin ...", dev);
sulogin(1);
if (hasmntopt(mnt,"nofail")) {
logit(LOG_CONSOLE | LOG_WARNING, "Ignoring failed fsck %s because of nofail option", dev);
fsck_rc = 0;
} else {
logit(LOG_CONSOLE | LOG_ALERT, "Failed fsck %s, attempting sulogin ...", dev);
sulogin(1);
}
}
rc += fsck_rc;
}
+5 -1
View File
@@ -87,6 +87,9 @@ void console_init(void)
/* Enable line wrap, if disabled previously, e.g., qemu */
dprint(STDOUT_FILENO, "\033[?7h", 5);
/* Reset atttributes, background and foreground color */
dprint(STDOUT_FILENO, "\033[49m\033[39m\e[2J", 14);
log_init();
}
@@ -582,7 +585,8 @@ int in_container(void)
"lxc",
"docker",
"kubepod",
"unshare"
"unshare",
"systemd-nspawn"
};
const char *files[] = {
"/run/.containerenv",
+6
View File
@@ -96,6 +96,12 @@ int iwatch_add1(struct iwatch *iw, char *file, uint32_t mask)
if (!initialized)
return -1;
iwp = iwatch_find_by_path(iw, file);
if (iwp) {
dbg("skipping, %s already registered", file);
return 0;
}
if (!fexist(file)) {
dbg("skipping %s: no such file or directory", file);
return 0;
+107 -32
View File
@@ -100,6 +100,9 @@ static void service_timeout_cb(uev_t *w, void *arg, int events)
*/
int service_timeout_after(svc_t *svc, int timeout, void (*cb)(svc_t *svc))
{
if (timeout == 0)
return 0; /* OK, not starting timer. */
if (svc->timer_cb)
return -EBUSY;
@@ -147,16 +150,17 @@ static void service_script_kill(svc_t *svc)
continue;
dbg("Killing service %s script PID %d.", svc_ident(svc, NULL, 0), ptr->pid);
kill(-ptr->pid, SIGKILL);
kill(ptr->pid, SIGKILL);
TAILQ_REMOVE(&svc_assoc_list, ptr, link);
free(ptr);
}
}
static int service_script_add(svc_t *svc, pid_t pid)
static int service_script_add(svc_t *svc, pid_t pid, int tmo)
{
struct assoc *ptr = malloc(sizeof(*ptr));
struct assoc *ptr;
ptr = malloc(sizeof(*ptr));
if (!ptr) {
err(1, "Failed starting service script timer");
return 1;
@@ -166,7 +170,7 @@ static int service_script_add(svc_t *svc, pid_t pid)
ptr->pid = pid;
TAILQ_INSERT_TAIL(&svc_assoc_list, ptr, link);
service_timeout_after(svc, svc->killdelay, service_script_kill);
service_timeout_after(svc, tmo, service_script_kill);
return 0;
}
@@ -1297,12 +1301,44 @@ static void parse_killdelay(svc_t *svc, char *delay)
svc->killdelay = (int)(sec * 1000);
}
static void parse_script(char *type, char *script, char *buf, size_t len)
/*
* pre:[0-3600,]/path/to/script
*/
static void parse_script(svc_t *svc, char *type, char *script, int *tmo, char *buf, size_t len)
{
if (access(script, X_OK))
logit(LOG_WARNING, "%s:%s is missing or not executable, skipping.", type, script);
else
strlcpy(buf, script, len);
char *found, *path;
path = strchr(script, ',');
if (path) {
const char *errstr;
long long sec;
*path++ = 0;
sec = strtonum(script, 0, 3600, &errstr);
if (errstr) {
errx(1, "%s: tmo %s is %s (0-3600)", svc_ident(svc, NULL, 0),
script, errstr);
return;
}
*tmo = (int)(sec * 1000);
} else {
path = script;
*tmo = svc->killdelay;
}
found = which(path);
if (!found) {
/* Not in $PATH, check if path exists and is executable */
if (access(path, X_OK)) {
logit(LOG_WARNING, "%s:%s is missing or not executable, skipping.",
type, path);
return;
}
} else
free(found);
strlcpy(buf, path, len);
}
/*
@@ -1770,15 +1806,15 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
else
svc->killdelay = SVC_TERM_TIMEOUT;
if (pre_script)
parse_script("pre", pre_script, svc->pre_script, sizeof(svc->pre_script));
parse_script(svc, "pre", pre_script, &svc->pre_tmo, svc->pre_script, sizeof(svc->pre_script));
else
memset(svc->pre_script, 0, sizeof(svc->pre_script));
if (post_script)
parse_script("post", post_script, svc->post_script, sizeof(svc->post_script));
parse_script(svc, "post", post_script, &svc->post_tmo, svc->post_script, sizeof(svc->post_script));
else
memset(svc->post_script, 0, sizeof(svc->post_script));
if (ready_script)
parse_script("ready", ready_script, svc->ready_script, sizeof(svc->ready_script));
parse_script(svc, "ready", ready_script, &svc->ready_tmo, svc->ready_script, sizeof(svc->ready_script));
else
memset(svc->ready_script, 0, sizeof(svc->ready_script));
if (!svc_is_tty(svc)) {
@@ -1904,24 +1940,32 @@ void service_unregister(svc_t *svc)
void service_monitor(pid_t lost, int status)
{
int sig = WIFSIGNALED(status);
int rc = WEXITSTATUS(status);
int ok = WIFEXITED(status);
svc_t *svc;
if (lost <= 1)
return;
/* main process as well as pre: and post: scripts use svc->pid */
svc = svc_find_by_pid(lost);
if (!svc) {
/* Check if ready: script in assoc list */
if (service_script_del(lost))
dbg("collected unknown PID %d", lost);
return;
}
switch (svc->state) {
case SVC_CLEANUP_STATE:
case SVC_SETUP_STATE:
/* If the setup phase fails, drive svc to crashed. */
svc->status = status;
/* fallthrough */
case SVC_CLEANUP_STATE:
dbg("collected script %s(%d), normal exit: %d, signaled: %d, exit code: %d",
svc->state == SVC_CLEANUP_STATE ? svc->post_script : svc->pre_script,
lost, WIFEXITED(status), WIFSIGNALED(status), WEXITSTATUS(status));
lost, ok, sig, rc);
/* Kill all children in the same proess group, e.g. logit */
dbg("Killing lingering children in same process group ...");
kill(-svc->pid, SIGKILL);
@@ -1929,7 +1973,7 @@ void service_monitor(pid_t lost, int status)
default:
dbg("collected %s(%d), normal exit: %d, signaled: %d, exit code: %d",
svc_ident(svc, NULL, 0), lost, WIFEXITED(status), WIFSIGNALED(status), WEXITSTATUS(status));
svc_ident(svc, NULL, 0), lost, ok, sig, rc);
svc->status = status;
break;
}
@@ -1954,10 +1998,7 @@ void service_monitor(pid_t lost, int status)
service_cleanup(svc);
} else if (svc_is_runtask(svc)) {
/* run/task should run at least once per runlevel */
if (WIFEXITED(status))
svc->started = 1;
else
svc->started = 0;
svc->started = ok;
}
done:
@@ -1965,7 +2006,7 @@ done:
svc->start_time = svc->pid = 0;
cont:
if (lost == run_block_pid) {
int result = WIFEXITED(status) ? WEXITSTATUS(status) : 1;
int result = ok ? rc : 1;
svc_mark_clean(svc); /* done, regardless of exit status */
run_block_pid = 0;
@@ -2001,6 +2042,10 @@ static void svc_mark_affected(char *cond)
* Called on conf_reload() to update service reverse dependencies.
* E.g., if ospfd depends on zebra and the zebra Finit conf has
* changed, we need to mark the ospfd Finit conf as changed too.
*
* However, a daemon that depends on syslogd (sysklogd project), need
* not be reloeaded (SIGHUP'ed or stop/started) because syslogd support
* reloading its configuration file on SIGHUP.
*/
void service_update_rdeps(void)
{
@@ -2012,6 +2057,10 @@ void service_update_rdeps(void)
if (!svc_is_changed(svc))
continue;
/* Service supports reloading conf without stop/start */
if (!svc_is_nohup(svc))
continue; /* Yup, no need to stop start rdeps */
svc_mark_affected(mkcond(svc, cond, sizeof(cond)));
}
}
@@ -2040,7 +2089,8 @@ static void service_kill_script(svc_t *svc)
if (svc->pid <= 1)
return;
kill(-svc->pid, SIGKILL);
dbg("Timeout, killing service %s script PID %d", svc_ident(svc, NULL, 0), svc->pid);
kill(svc->pid, SIGKILL);
}
/*
@@ -2051,6 +2101,9 @@ static void set_pre_post_envs(svc_t *svc, const char *type)
char buf[25 + 256] = "/etc/default:/etc/conf.d";
setenv("SERVICE_TYPE", svc_typestr(svc), 1);
setenv("SERVICE_NAME", svc->name, 1);
if (svc->id[0])
setenv("SERVICE_ID", svc->id, 1);
setenv("SERVICE_IDENT", svc_ident(svc, NULL, 0), 1);
setenv("SERVICE_SCRIPT_TYPE", type, 1);
@@ -2079,6 +2132,8 @@ static void service_pre_script(svc_t *svc)
};
char *env_file;
redirect(svc);
env_file = svc_getenv(svc);
if (env_file)
snprintf(buf, sizeof(buf), ". %s; exec %s", env_file, svc->pre_script);
@@ -2091,9 +2146,7 @@ static void service_pre_script(svc_t *svc)
}
dbg("%s: pre:script %s started as PID %d", svc_ident(svc, NULL, 0), svc->pre_script, svc->pid);
/* Short hard-coded timeout to prevent locking up Finit */
service_timeout_after(svc, svc->killdelay, service_kill_script);
service_timeout_after(svc, svc->pre_tmo, service_kill_script);
}
static void service_post_script(svc_t *svc)
@@ -2144,11 +2197,16 @@ static void service_post_script(svc_t *svc)
}
dbg("%s: post:script %s started as PID %d", svc_ident(svc, NULL, 0), svc->post_script, svc->pid);
/* Short hard-coded timeout to prevent locking up Finit */
service_timeout_after(svc, svc->killdelay, service_kill_script);
service_timeout_after(svc, svc->post_tmo, service_kill_script);
}
/*
* Unlike the pre: and post: scripts, the ready: script cannot re-use
* svc->pid, so instead we use an assoc. list for matching any scripts
* related to the svc, handled by service_script_add() below. When a
* ready: script is reaped the service_monitor() checks first for the
* svc, then calls service_script_del().
*/
void service_ready_script(svc_t *svc)
{
pid_t pid;
@@ -2184,9 +2242,7 @@ void service_ready_script(svc_t *svc)
}
dbg("%s: ready:script %s started as PID %d", svc_ident(svc, NULL, 0), svc->ready_script, pid);
/* Short hard-coded timeout to prevent locking up Finit */
service_script_add(svc, pid);
service_script_add(svc, pid, svc->ready_tmo);
}
static void service_retry(svc_t *svc)
@@ -2439,8 +2495,27 @@ restart:
break;
case SVC_SETUP_STATE:
if (!svc->pid)
svc_set_state(svc, SVC_STARTING_STATE);
if (!svc->pid) {
int rc = WEXITSTATUS(svc->status);
int ok = WIFEXITED(svc->status);
if (!ok || rc) {
const char *sig;
if (WIFSIGNALED(svc->status))
sig = sig_name(WTERMSIG(svc->status));
else
sig = "none";
logit(LOG_WARNING, "Service %s pre:%s failed, rc: %d sig:%s",
svc_ident(svc, NULL, 0), svc->pre_script, rc, sig);
svc_set_state(svc, SVC_STOPPING_STATE);
svc_crashing(svc);
} else {
svc_set_state(svc, SVC_STARTING_STATE);
}
}
break;
case SVC_WAITING_STATE:
+6
View File
@@ -169,11 +169,17 @@ void sm_init(sm_t *sm)
void sm_set_runlevel(sm_t *sm, int newlevel)
{
sm->newlevel = newlevel;
dbg("Flushing pending .conf file events ...");
conf_flush_events();
}
void sm_set_reload(sm_t *sm)
{
sm->reload = 1;
dbg("Flushing pending .conf file events ...");
conf_flush_events();
}
int sm_is_in_teardown(sm_t *sm)
+4
View File
@@ -197,8 +197,11 @@ typedef struct svc {
char desc[MAX_STR_LEN];
char env[MAX_CMD_LEN];
char pre_script[MAX_CMD_LEN];
int pre_tmo;
char post_script[MAX_CMD_LEN];
int post_tmo;
char ready_script[MAX_CMD_LEN];
int ready_tmo;
/*
* Used to forcefully kill services that won't shutdown on
@@ -259,6 +262,7 @@ static inline int svc_is_tty (svc_t *svc) { return svc && SVC_TYPE_TTY
static inline int svc_is_runtask (svc_t *svc) { return svc && (SVC_TYPE_RUNTASK & svc->type);}
static inline int svc_is_forking (svc_t *svc) { return svc && svc->forking; }
static inline int svc_is_manual (svc_t *svc) { return svc && svc->manual; }
static inline int svc_is_nohup (svc_t *svc) { return svc && (0 == svc->sighup); }
static inline int svc_in_runlevel (svc_t *svc, int runlevel) { return svc && ISSET(svc->runlevels, runlevel); }
static inline int svc_nohup (svc_t *svc) { return svc && (0 == svc->sighup || 0 != svc->args_dirty); }
+34 -28
View File
@@ -1,28 +1,28 @@
SUBDIRS = lib src
EXTRA_DIST = skel/bin/busybox-x86_64.sha256 skel/sbin/service.sh skel/etc/env \
skel/bin/pre.sh skel/bin/post.sh skel/bin/ready.sh skel/bin/slay \
skel/sbin/fail.sh skel/usr/share/runparts/ref.log \
skel/usr/share/runparts/sysv.log \
skel/etc/rc.d/foo.sh skel/etc/rc.d/S01abc.sh \
skel/etc/rc.d/test.sh skel/etc/rc.d/S02def.sh \
skel/etc/rcS.d/foo.sh skel/etc/rcS.d/test.sh \
skel/etc/rcS.d/S01abc.sh skel/etc/rcS.d/S02def.sh \
skel/cdrom/.empty skel/dev/shm/.empty skel/dev/pts/.empty \
skel/etc/inittab skel/etc/hostname skel/etc/fstab \
skel/etc/init.d/rcS skel/etc/init.d/rcK skel/tmp/.empty \
skel/etc/finit.d/.empty skel/etc/finit.d/available/.empty \
skel/etc/finit.d/enabled/.empty \
skel/sbin/task.sh skel/bin/crasher.sh \
skel/etc/init.d/S01-service.sh skel/etc/init.d/S02-serv.sh \
skel/proc/.empty skel/root/.empty skel/run/.empty \
skel/sbin/chrootsetup.sh skel/srv/.empty skel/sys/.empty \
skel/usr/bin/.empty skel/usr/lib/.empty skel/usr/sbin/.empty \
skel/home/.empty skel/usr/games/.empty skel/usr/src/.empty \
skel/usr/share/.empty skel/usr/include/.empty \
skel/usr/local/games/.empty skel/usr/local/sbin/.empty \
skel/usr/local/share/.empty skel/usr/local/src/.empty \
skel/usr/local/lib/.empty skel/usr/local/bin/.empty \
EXTRA_DIST = skel/bin/busybox-x86_64.sha256 skel/sbin/service.sh skel/etc/env \
skel/bin/pre.sh skel/bin/post.sh skel/bin/ready.sh skel/bin/slay \
skel/sbin/fail.sh skel/usr/share/runparts/ref.log \
skel/usr/share/runparts/sysv.log \
skel/etc/rc.d/foo.sh skel/etc/rc.d/S01abc.sh \
skel/etc/rc.d/test.sh skel/etc/rc.d/S02def.sh \
skel/etc/rcS.d/foo.sh skel/etc/rcS.d/test.sh \
skel/etc/rcS.d/S01abc.sh skel/etc/rcS.d/S02def.sh \
skel/cdrom/.empty skel/dev/shm/.empty skel/dev/pts/.empty \
skel/etc/inittab skel/etc/hostname skel/etc/fstab \
skel/etc/init.d/rcS skel/etc/init.d/rcK skel/tmp/.empty \
skel/etc/finit.d/.empty skel/etc/finit.d/available/.empty \
skel/etc/finit.d/enabled/.empty \
skel/sbin/task.sh skel/bin/crasher.sh skel/bin/fail.sh \
skel/etc/init.d/S01-service.sh skel/etc/init.d/S02-serv.sh \
skel/proc/.empty skel/root/.empty skel/run/.empty \
skel/sbin/chrootsetup.sh skel/srv/.empty skel/sys/.empty \
skel/usr/bin/.empty skel/usr/lib/.empty skel/usr/sbin/.empty \
skel/home/.empty skel/usr/games/.empty skel/usr/src/.empty \
skel/usr/share/.empty skel/usr/include/.empty \
skel/usr/local/games/.empty skel/usr/local/sbin/.empty \
skel/usr/local/share/.empty skel/usr/local/src/.empty \
skel/usr/local/lib/.empty skel/usr/local/bin/.empty \
skel/usr/local/etc/.empty skel/var/.empty
EXTRA_DIST += setup-sysroot.sh
@@ -40,6 +40,7 @@ EXTRA_DIST += initctl-status-subset.sh
EXTRA_DIST += notify.sh
EXTRA_DIST += pidfile.sh
EXTRA_DIST += pre-post-serv.sh
EXTRA_DIST += pre-fail.sh
EXTRA_DIST += process-depends.sh
EXTRA_DIST += rclocal.sh
EXTRA_DIST += ready-serv.sh
@@ -65,11 +66,6 @@ AM_TESTS_ENVIRONMENT += export LD_LIBRARY_PATH;
AM_TESTS_ENVIRONMENT += top_builddir=$(top_builddir);
AM_TESTS_ENVIRONMENT += export top_builddir;
checkself.sh:
@echo '#!/bin/sh' > $@
@echo shellcheck $(addprefix '"$$srcdir"'/,$(filter %.sh,$(filter-out $@, $(TESTS)))) >> $@
@chmod +x $@
TEST_EXTENSIONS = .sh
TESTS = checkself.sh
TESTS += add-remove-dynamic-service.sh
@@ -86,6 +82,7 @@ TESTS += initctl-status-subset.sh
TESTS += notify.sh
TESTS += pidfile.sh
TESTS += pre-post-serv.sh
TESTS += pre-fail.sh
TESTS += process-depends.sh
TESTS += rclocal.sh
TESTS += ready-serv.sh
@@ -109,6 +106,15 @@ TESTS += unexpected-restart.sh
check-recursive: setup-chroot
.PHONY: checkself.sh
checkself.sh:
@echo '#!/bin/sh' > $@
@echo 'set -eu' >> $@
@echo 'cd "$$srcdir" 2>/dev/null || cd "." || exit 1' >> $@
@echo 'TESTS="$(filter %.sh,$(filter-out $@, $(TESTS)))"' >> $@
@echo 'shellcheck $$TESTS' >> $@
@chmod 0755 $@
.PHONY: setup-chroot
setup-chroot:
@SYSROOT='$(abs_builddir)/sysroot/' srcdir=$(srcdir) top_builddir=$(top_builddir) $(srcdir)/setup-sysroot.sh
+3 -2
View File
@@ -27,15 +27,16 @@ test_teardown()
say "Waiting for runlevel 2"
sleep 2
#run "initctl debug"
run "initctl debug"
say "Add service stanza to $FINIT_CONF ..."
run "echo 'service serv -np -e foo:bar -- Verify foo=bar' >> $FINIT_CONF"
#run "cat $FINIT_CONF"
run "cat $FINIT_CONF"
say 'Reload Finit'
run "initctl reload"
sleep 1
run "initctl"
retry 'assert_num_children 1 serv'
say "Modify $FINIT_CONF slightly ..."
+8
View File
@@ -84,6 +84,14 @@ assert_status()
assert "Service $service $status" "$(texec initctl -p status "$service" | awk '/Status/{print $3}')" = "$status"
}
# Used by, e.g., pre-fail.sh
assert_status_full()
{
service=$1; shift
status="$*"
assert "Service $service status is: $status" "$(texec initctl -p status "$service" | awk '/Status/{sub("^ *Status : ", ""); print}')" = "$status"
}
assert_cond()
{
cond=$1
+28
View File
@@ -0,0 +1,28 @@
#!/bin/sh
# Verify Finit:
# - does not start main process when pre:script fails
# - times out and kills long running pre:script
set -eu
#export DEBUG=true
TEST_DIR=$(dirname "$0")
# shellcheck source=/dev/null
. "$TEST_DIR/lib/setup.sh"
vrfy()
{
nm=serv
tmo=$1
msg=$2
err=$3
run "echo 'service [2345] pre:$tmo,fail.sh $nm -n -- $msg' > $FINIT_CONF"
run "initctl reload"
retry "assert_status_full $nm 'crashed $err'" 50
}
#run "initctl debug"
vrfy 5 "Failing pre: script" "(code=exited, status=42)"
vrfy 1 "Timeout pre: script" "(code=signal, status=9/KILL)"
+2 -2
View File
@@ -42,8 +42,8 @@ test_one()
sep
say "Add stanza to $FINIT_CONF"
run "echo 'run fail.sh -- Failure' > $FINIT_RCSD/fail.conf"
run "echo 'run initctl touch fail' > $FINIT_RCSD/touch.conf"
run "echo 'run /sbin/fail.sh -- Failure' > $FINIT_RCSD/fail.conf"
run "echo 'run initctl touch fail' > $FINIT_RCSD/touch.conf"
test_one 2
sep
+4
View File
@@ -0,0 +1,4 @@
#!/bin/sh
sleep 2
exit 42
+2 -1
View File
@@ -10,7 +10,8 @@
#
TEST_DIR=$(dirname "$0")
#DEBUG=1
# shellcheck disable=2034
DEBUG=1
# shellcheck disable=SC2034
BOOTSTRAP="runparts sysv /etc/rcS.d"