mirror of
https://github.com/troglobit/finit.git
synced 2026-10-21 11:29:42 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b9cebbfd3 | ||
|
|
38791616e0 | ||
|
|
fede3fd2e1 | ||
|
|
a46a33238d | ||
|
|
afe0488bf2 | ||
|
|
ec5e42694d | ||
|
|
2e73563eea |
No files matched your search
+8
-1
@@ -4,7 +4,7 @@ Change Log
|
|||||||
All relevant changes are documented in this file.
|
All relevant changes are documented in this file.
|
||||||
|
|
||||||
|
|
||||||
[4.5][] - 2023-09-24
|
[4.5][] - 2023-10-03
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
@@ -16,6 +16,9 @@ All relevant changes are documented in this file.
|
|||||||
- Add `initctl -f` to force-skip asking Finit for existing services
|
- Add `initctl -f` to force-skip asking Finit for existing services
|
||||||
when creating new services during bootstrap, e.g. `/etc/rc.local`
|
when creating new services during bootstrap, e.g. `/etc/rc.local`
|
||||||
- `initctl runlevel` now returns `N S` instead of `N 10` in bootstrap
|
- `initctl runlevel` now returns `N S` instead of `N 10` in bootstrap
|
||||||
|
- `initctl runlevel N` during bootstrap is now allowed. It changes
|
||||||
|
the next runlevel to go to when bootstrap has completed. Effectively
|
||||||
|
overriding the `runlevel N` statement in `/etc/finit.conf`
|
||||||
- Improved logging on failure to `execvp()` a run/task/service, now
|
- Improved logging on failure to `execvp()` a run/task/service, now
|
||||||
with `errno`, e.g., "No such file or directory" when the command
|
with `errno`, e.g., "No such file or directory" when the command
|
||||||
is missing from `$PATH`
|
is missing from `$PATH`
|
||||||
@@ -30,6 +33,10 @@ All relevant changes are documented in this file.
|
|||||||
- Increased MAX path for commands, and arguments: 64 -> 256
|
- Increased MAX path for commands, and arguments: 64 -> 256
|
||||||
- The bundled watchdog daemon no longer tries to log at startup, because
|
- The bundled watchdog daemon no longer tries to log at startup, because
|
||||||
syslog is not available yet, any startup message leak to console
|
syslog is not available yet, any startup message leak to console
|
||||||
|
- Extend `if:` option with runtime evaluation of conditions. E.g., start
|
||||||
|
a task only `if:<run/foo/failure>` (here the run task 'foo' failed)
|
||||||
|
- Document new `if:`, `conflict:`, `nowarn` options for run/task/service
|
||||||
|
first introduced in v4.4
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
- Fix #227: believed to have been fixed in v4.3, the root cause was
|
- Fix #227: believed to have been fixed in v4.3, the root cause was
|
||||||
|
|||||||
+2
-1
@@ -1,4 +1,5 @@
|
|||||||
AC_INIT([Finit],[4.5-rc3],[https://github.com/troglobit/finit/issues],[finit],[https://troglobit.com/projects/finit/])
|
AC_INIT([Finit], [4.5-rc4], [https://github.com/troglobit/finit/issues],
|
||||||
|
[finit], [https://troglobit.com/projects/finit/])
|
||||||
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])
|
||||||
|
|||||||
+78
-8
@@ -164,14 +164,19 @@ everything is OK.
|
|||||||
task [S] /lib/console-setup/console-setup.sh
|
task [S] /lib/console-setup/console-setup.sh
|
||||||
service [S12345] env:-/etc/default/rsyslog rsyslogd -n $RSYSLOGD_ARGS
|
service [S12345] env:-/etc/default/rsyslog rsyslogd -n $RSYSLOGD_ARGS
|
||||||
|
|
||||||
After runlevel S, Finit proceeds to runlevel 2. (This can be changed in
|
After runlevel S, Finit proceeds to runlevel 2. This can be changed in
|
||||||
`/etc/finit.conf` using the `runlevel N` directive.) Before starting
|
`/etc/finit.conf` using the `runlevel N` directive, or by a script
|
||||||
the services in runlevel 2, Finit first stops everything that is not
|
running in runlevel S that calls, e.g., `initctl runlevel 9`. The
|
||||||
allowed to run in 2, and then brings up networking. Networking is
|
latter is useful if startup scripts detect problems outside of Finit's
|
||||||
expected to be available in all runlevels except: S, 1 (single user
|
control, e.g., critical services/devices missing or hardware problems.
|
||||||
level), 6, and 0. Networking is enabled either by the `network script`
|
|
||||||
directive, or if you have an `/etc/network/interfaces` file, Finit calls
|
Before starting the services in runlevel 2, Finit first stops everything
|
||||||
`ifup -a` -- at the very least the loopback interface is brought up.
|
that is not allowed to run in 2, and then brings up networking.
|
||||||
|
Networking is expected to be available in all runlevels except: S, 1
|
||||||
|
(single user level), 6, and 0. Networking is enabled either by the
|
||||||
|
`network script` directive, or if you have an `/etc/network/interfaces`
|
||||||
|
file, Finit calls `ifup -a` -- at the very least the loopback interface
|
||||||
|
is brought up.
|
||||||
|
|
||||||
> **Note:** when moving from runlevel S to 2, all run/task/services that
|
> **Note:** when moving from runlevel S to 2, all run/task/services that
|
||||||
> were constrained to runlevel S only are dropped from bookkeeping. So
|
> were constrained to runlevel S only are dropped from bookkeeping. So
|
||||||
@@ -839,6 +844,71 @@ These script actions *must terminate*, so they have a default execution
|
|||||||
time of 3 seconds before they are SIGKILLed, this can be adjusted using
|
time of 3 seconds before they are SIGKILLed, this can be adjusted using
|
||||||
the above `kill:SEC` syntax.
|
the above `kill:SEC` syntax.
|
||||||
|
|
||||||
|
#### Conditional Loading
|
||||||
|
|
||||||
|
Finit support conditional loading of stanzas. The following example is
|
||||||
|
take from the `system/hotplug.conf` file in the Finit distribution.
|
||||||
|
Here we only show a simplified subset.
|
||||||
|
|
||||||
|
Starting with the `nowarn` option.
|
||||||
|
|
||||||
|
service nowarn name:udevd pid:udevd /lib/systemd/systemd-udevd
|
||||||
|
service nowarn name:udevd pid:udevd udevd
|
||||||
|
|
||||||
|
When loading the .conf file Finit looks for `/lib/systemd/systemd-udevd`
|
||||||
|
if that is not found Finit automatically logs a warning. The `nowarn`
|
||||||
|
option disables this warning so that the second line can be evaluated,
|
||||||
|
which also provides a service named `udevd`.
|
||||||
|
|
||||||
|
run nowarn if:udevd <pid/udevd> udevadm settle -t 0
|
||||||
|
|
||||||
|
This line is only loaded if we know of a service named `udevd`. Again,
|
||||||
|
we do not warn if `udevadm` is not found, Execution will also stop here
|
||||||
|
until the PID condition is asserted, i.e., Finit detecting udevd has
|
||||||
|
started.
|
||||||
|
|
||||||
|
run nowarn conflict:udevd [S] mdev -s -- Populating device tree
|
||||||
|
|
||||||
|
If `udevd` is not available, we try to run `mdev`, but if that is not
|
||||||
|
found, again we do not warn.
|
||||||
|
|
||||||
|
Conditional loading statements can also be negated, so the previous stanza
|
||||||
|
can also be written as:
|
||||||
|
|
||||||
|
run nowarn if:!udevd [S] mdev -s -- Populating device tree
|
||||||
|
|
||||||
|
The reason for using `confict` in this example is that a conflict can be
|
||||||
|
resolved. Stanzas marked with `conflict:foo` are rechecked at runtime.
|
||||||
|
|
||||||
|
#### Conditional Execution
|
||||||
|
|
||||||
|
Similar to conditional loading of stanzas there is conditional runtime
|
||||||
|
execution. This can be confusing at first, since Finit already has a
|
||||||
|
condition subsystem, but this is more akin to the qualification to a
|
||||||
|
runlevel. E.g., a `task [123]` is qualified to run only in runlevel 1,
|
||||||
|
2, and 3. It is not considered for other runlevels.
|
||||||
|
|
||||||
|
Conditional execution qualify a run/task/service based on a condition.
|
||||||
|
Consider this (simplified) example from the Infix operating system:
|
||||||
|
|
||||||
|
run [S] name:startup <pid/sysrepo> confd -b --load startup-config
|
||||||
|
run [S] if:<usr/fail-startup> name:failure <pid/sysrepo> confd --load failure-config
|
||||||
|
|
||||||
|
The two run statements reside in the same .conf file so Finit runs them
|
||||||
|
in true sequence. If loading the file `startup-config` fails confd sets
|
||||||
|
the condition `usr/fail-startup`, thus allowing the next run statement
|
||||||
|
to load `failure-config`.
|
||||||
|
|
||||||
|
Notice critical the difference between `<pid/sysrepo>` condition and
|
||||||
|
`if:<usr/fail-startup>`. The former is a condition for starting and the
|
||||||
|
latter is a condition to check if a run/task/service is qualified to
|
||||||
|
even be considered.
|
||||||
|
|
||||||
|
Conditional execution statements can also be negated, so provided the
|
||||||
|
file loaded did the opposite, i.e., set a condition on success, the
|
||||||
|
previous stanza can also be written as:
|
||||||
|
|
||||||
|
run [S] if:<!usr/startup-ok> name:failure <pid/sysrepo> confd ...
|
||||||
|
|
||||||
### Run-parts Scripts
|
### Run-parts Scripts
|
||||||
|
|
||||||
|
|||||||
@@ -240,6 +240,11 @@ Show top-like listing based on cgroups.
|
|||||||
List installed plugins.
|
List installed plugins.
|
||||||
.It Nm Ar runlevel Op Ar 0-9
|
.It Nm Ar runlevel Op Ar 0-9
|
||||||
Show or set runlevel: 0 halt, 6 reboot.
|
Show or set runlevel: 0 halt, 6 reboot.
|
||||||
|
.Pp
|
||||||
|
If called at boot (runlevel S) to set the runlevel, Finit only schedules
|
||||||
|
the change, effectively overriding the configured runlevel from
|
||||||
|
.Pa /etc/finit.conf .
|
||||||
|
Useful to trigger a fail-safe mode, or similar.
|
||||||
.It Nm Ar reboot
|
.It Nm Ar reboot
|
||||||
Reboot system, default if
|
Reboot system, default if
|
||||||
.Cm reboot
|
.Cm reboot
|
||||||
|
|||||||
@@ -367,7 +367,6 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (rq.cmd) {
|
switch (rq.cmd) {
|
||||||
case INIT_CMD_RUNLVL:
|
|
||||||
case INIT_CMD_RELOAD:
|
case INIT_CMD_RELOAD:
|
||||||
case INIT_CMD_START_SVC:
|
case INIT_CMD_START_SVC:
|
||||||
case INIT_CMD_RESTART_SVC:
|
case INIT_CMD_RESTART_SVC:
|
||||||
@@ -378,7 +377,7 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
case INIT_CMD_POWEROFF:
|
case INIT_CMD_POWEROFF:
|
||||||
case INIT_CMD_SUSPEND:
|
case INIT_CMD_SUSPEND:
|
||||||
if (IS_RESERVED_RUNLEVEL(runlevel)) {
|
if (IS_RESERVED_RUNLEVEL(runlevel)) {
|
||||||
warnx("Unsupported command in runlevel S and 6.");
|
warnx("Unsupported command in runlevel S and 6/0.");
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -387,6 +386,14 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
|
|
||||||
switch (rq.cmd) {
|
switch (rq.cmd) {
|
||||||
case INIT_CMD_RUNLVL:
|
case INIT_CMD_RUNLVL:
|
||||||
|
/* Allow changing cfglevel in runlevel S */
|
||||||
|
if (IS_RESERVED_RUNLEVEL(runlevel)) {
|
||||||
|
if (runlevel != INIT_LEVEL) {
|
||||||
|
warnx("Cannot abort runlevel 6/0.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (rq.runlevel) {
|
switch (rq.runlevel) {
|
||||||
case 's':
|
case 's':
|
||||||
case 'S':
|
case 'S':
|
||||||
@@ -400,7 +407,12 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
halt = SHUT_OFF;
|
halt = SHUT_OFF;
|
||||||
if (lvl == 6)
|
if (lvl == 6)
|
||||||
halt = SHUT_REBOOT;
|
halt = SHUT_REBOOT;
|
||||||
service_runlevel(lvl);
|
|
||||||
|
/* User requested change in next runlevel */
|
||||||
|
if (runlevel == INIT_LEVEL)
|
||||||
|
cfglevel = lvl;
|
||||||
|
else
|
||||||
|
service_runlevel(lvl);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
+1
-1
@@ -237,7 +237,7 @@ static void devmon_cb(uev_t *w, void *arg, int events)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
dbg("Got %s", ev->name);
|
// dbg("Got %s", ev->name);
|
||||||
if (ev->mask & (IN_CREATE | IN_DELETE))
|
if (ev->mask & (IN_CREATE | IN_DELETE))
|
||||||
devmon_update_conds(iwp->path, ev->name, ev->mask);
|
devmon_update_conds(iwp->path, ev->name, ev->mask);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -288,7 +288,7 @@ static void generic_io_cb(uev_t *w, void *arg, int events)
|
|||||||
/* Stop watcher, callback may close descriptor on us ... */
|
/* Stop watcher, callback may close descriptor on us ... */
|
||||||
uev_io_stop(w);
|
uev_io_stop(w);
|
||||||
|
|
||||||
dbg("Calling I/O %s from runloop...", basename(p->name));
|
// dbg("Calling I/O %s from runloop...", basename(p->name));
|
||||||
p->io.cb(p->io.arg, w->fd, events);
|
p->io.cb(p->io.arg, w->fd, events);
|
||||||
|
|
||||||
/* Update fd, may be changed by plugin callback, e.g., if FIFO */
|
/* Update fd, may be changed by plugin callback, e.g., if FIFO */
|
||||||
|
|||||||
+11
-7
@@ -836,7 +836,7 @@ static int service_start(svc_t *svc)
|
|||||||
|
|
||||||
fail:
|
fail:
|
||||||
sigprocmask(SIG_SETMASK, &omask, NULL);
|
sigprocmask(SIG_SETMASK, &omask, NULL);
|
||||||
if (do_progress)
|
if (do_progress && !run_block_pid)
|
||||||
print_result(result);
|
print_result(result);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -1847,11 +1847,6 @@ void service_monitor(pid_t lost, int status)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lost == run_block_pid) {
|
|
||||||
svc_mark_clean(svc); /* done, regardless of exit status */
|
|
||||||
run_block_pid = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (svc->state) {
|
switch (svc->state) {
|
||||||
case SVC_CLEANUP_STATE:
|
case SVC_CLEANUP_STATE:
|
||||||
case SVC_SETUP_STATE:
|
case SVC_SETUP_STATE:
|
||||||
@@ -1900,6 +1895,13 @@ done:
|
|||||||
/* No longer running, update books. */
|
/* No longer running, update books. */
|
||||||
svc->start_time = svc->pid = 0;
|
svc->start_time = svc->pid = 0;
|
||||||
cont:
|
cont:
|
||||||
|
if (lost == run_block_pid) {
|
||||||
|
svc_mark_clean(svc); /* done, regardless of exit status */
|
||||||
|
run_block_pid = 0;
|
||||||
|
if (svc->desc[0])
|
||||||
|
print_result(WIFEXITED(status) ? WEXITSTATUS(status) : 1);
|
||||||
|
}
|
||||||
|
|
||||||
if (!service_step(svc)) {
|
if (!service_step(svc)) {
|
||||||
/* Clean out any bootstrap tasks, they've had their time in the sun. */
|
/* Clean out any bootstrap tasks, they've had their time in the sun. */
|
||||||
if (svc_clean_bootstrap(svc))
|
if (svc_clean_bootstrap(svc))
|
||||||
@@ -1955,7 +1957,7 @@ void service_mark_unavail(void)
|
|||||||
if (!svc->ifstmt[0])
|
if (!svc->ifstmt[0])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!svc_ifthen(svc_ident(svc, buf, sizeof(buf)), svc->ifstmt))
|
if (!svc_ifthen(1, svc_ident(svc, buf, sizeof(buf)), svc->ifstmt))
|
||||||
svc_mark(svc);
|
svc_mark(svc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2294,9 +2296,11 @@ restart:
|
|||||||
svc_set_state(svc, SVC_WAITING_STATE);
|
svc_set_state(svc, SVC_WAITING_STATE);
|
||||||
else {
|
else {
|
||||||
if (svc_is_conflict(svc)) {
|
if (svc_is_conflict(svc)) {
|
||||||
|
#if 0
|
||||||
logit(svc->nowarn ? LOG_DEBUG : LOG_INFO,
|
logit(svc->nowarn ? LOG_DEBUG : LOG_INFO,
|
||||||
"%s in conflict with %s, checking again ...",
|
"%s in conflict with %s, checking again ...",
|
||||||
svc_ident(svc, NULL, 0), svc->conflict);
|
svc_ident(svc, NULL, 0), svc->conflict);
|
||||||
|
#endif
|
||||||
if (!svc_conflicts(svc))
|
if (!svc_conflicts(svc))
|
||||||
svc_unblock(svc);
|
svc_unblock(svc);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -634,17 +634,30 @@ int svc_enabled(svc_t *svc)
|
|||||||
if (!svc)
|
if (!svc)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!svc_in_runlevel(svc, runlevel))
|
if (!svc_in_runlevel(svc, runlevel)) {
|
||||||
|
// dbg("Not in runlevel");
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (svc_is_removed(svc) || svc_is_blocked(svc))
|
if (svc_is_removed(svc) || svc_is_blocked(svc)) {
|
||||||
|
// dbg("removed (%d) / blocked (%d)", svc->removed, svc->block);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (svc_is_missing(svc))
|
if (svc_is_missing(svc)) {
|
||||||
|
// dbg("missing");
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (svc_is_tty(svc) && bootstrap)
|
if (!svc_ifthen(0, NULL, svc->ifstmt)) {
|
||||||
|
// dbg("ifthen:%s>", svc->ifstmt[0] ? svc->ifstmt : "<");
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (svc_is_tty(svc) && bootstrap) {
|
||||||
|
// dbg("is tty in bootstrap");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -688,13 +701,14 @@ int svc_conflicts(svc_t *svc)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* svc_ifthen - Check if: statement in declaration
|
* svc_ifthen - Check if: statement in declaration
|
||||||
|
* @is_conf: Set when called by service_mark_unavail()
|
||||||
* @ident: svc_t identififcation (name:id)
|
* @ident: svc_t identififcation (name:id)
|
||||||
* @stmt: if: statement from .conf file
|
* @stmt: if: statement from .conf file
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* %TRUE(1) yes, use this svc_t, %FALSE(0) prune
|
* %TRUE(1) yes, use this svc_t, %FALSE(0) prune
|
||||||
*/
|
*/
|
||||||
int svc_ifthen(const char *ident, char *stmt)
|
int svc_ifthen(int is_conf, const char *ident, char *stmt)
|
||||||
{
|
{
|
||||||
int not = 0;
|
int not = 0;
|
||||||
svc_t *svc;
|
svc_t *svc;
|
||||||
@@ -707,6 +721,9 @@ int svc_ifthen(const char *ident, char *stmt)
|
|||||||
char *ptr = ++stmt;
|
char *ptr = ++stmt;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
|
if (is_conf)
|
||||||
|
return 1;
|
||||||
|
|
||||||
if (stmt[0] == '!') {
|
if (stmt[0] == '!') {
|
||||||
stmt++;
|
stmt++;
|
||||||
not++;
|
not++;
|
||||||
@@ -717,17 +734,16 @@ int svc_ifthen(const char *ident, char *stmt)
|
|||||||
ptr[i] = 0;
|
ptr[i] = 0;
|
||||||
|
|
||||||
cond = cond_get(stmt);
|
cond = cond_get(stmt);
|
||||||
if (not && cond == COND_ON) {
|
if (not && cond == COND_ON)
|
||||||
logit(LOG_NOTICE, "skipping %s, cond %s is on.", ident, stmt);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
if (!not && cond == COND_OFF)
|
||||||
if (!not && cond == COND_OFF) {
|
|
||||||
logit(LOG_NOTICE, "skipping %s, cond %s is off.", ident, stmt);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!is_conf)
|
||||||
|
return 1;
|
||||||
|
|
||||||
if (stmt[0] == '!') {
|
if (stmt[0] == '!') {
|
||||||
stmt++;
|
stmt++;
|
||||||
not++;
|
not++;
|
||||||
|
|||||||
@@ -241,7 +241,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_conflicts (svc_t *svc);
|
int svc_conflicts (svc_t *svc);
|
||||||
int svc_ifthen (const char *ident, char *ifstm);
|
int svc_ifthen (int is_conf, const char *ident, char *stmt);
|
||||||
|
|
||||||
int svc_parse_jobstr (char *str, size_t len, void *user_data, int (*found)(svc_t *, void *), int (not_found)(char *, char *, void *));
|
int svc_parse_jobstr (char *str, size_t len, void *user_data, int (*found)(svc_t *, void *), int (not_found)(char *, char *, void *));
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user