Replace 'initctl emit <EV>' with 'initctl cond <cmd> <COND>'

This patch replaces the old 'initctl emit <EV>' idea with a more
full blown condition generator:

    initctl cond <set|clear|flux> <COND>

This aligns better with terminology used elsewhere in the new Finit
service state machine and dependency handling already documented.

The 'flux' sub-command is mostly intended for simulation/test of
Finit itself and should perhaps not be documented.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
This commit is contained in:
Joachim Nilsson
2016-07-15 15:51:57 +02:00
parent 2b74fb0e93
commit c7573fedad
3 changed files with 60 additions and 68 deletions
+4 -55
View File
@@ -694,13 +694,12 @@ not return until the given command has fully completed.
Commands:
debug Toggle Finit (daemon) debug
help This help text
emit <EV> Emit event; a predefined event: RELOAD, STOP, START
or a custom string matching an event in a service
stanza, e.g: GW:UP, IFUP:IFNAME, IFDN:IFNAME. Where
IFNAME is the interface name, e.g. eth0
reload Reload *.conf in /etc/finit.d/ and activate changes
runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot
status | show Show status of services
cond set <COND> Set (assert) condition => +COND
cond clear <COND> Clear (deassert) condition => -COND
cond flux <COND> Emulate flux condition => ~COND
cond show Show condition status
start <JOB|NAME>[:ID] Start service by job# or name, with optional ID
stop <JOB|NAME>[:ID] Stop/Pause a running service by job# or name
@@ -709,55 +708,6 @@ not return until the given command has fully completed.
version Show Finit version
```
The `emit <EV>` command can be used to send events to Finit. Built-in
events are: RELOAD, STOP, START. These events act on a lower level than
their command counterparts. The `reload` command reloads all `*.conf`
files in `/etc/finit.d/` *and* activates the changes, with `emit RELOAD`
only the `*.conf` files are reloaded.
**Note:** The `emit STOP` event is more like "prepare" than "stop".
Depending on how the service is declared, `<!>` or not, the service
may be stopped, or skipped to be be sent `SIGHUP` later when `emit
START` is issued.
To achieve the same result as `initctl reload` emit all three events:
```shell
~ $ initctl emit "RELOAD,STOP,START"
```
On an embedded system this can be used when changing complete system
configuration. Between `STOP` and `START` reset/change any hardware
or kernel settings required to be in effect before new services are
started.
```shell
# 1. Update/Change/Generate all daemon configuration files
~ $ …
# 2. Update /etc/finit.d/*.conf
~ $ …
# 3. Prepare finit, stop all old/previous services
~ $ initctl emit "RELOAD,STOP"
# 4. Reconfigure hardware, interfaces/bridges/VLANs, etc.
~ $ brctl …
~ $ vconfig …
~ $ ifconfig …
# 5. Complete finit reload by starting all new services and
# SIGHUP any changed services
~ $ initctl emit "START"
```
The `emit <EV>` command can also be used to emit custom events. In
fact, the event is a simple string. Declare a list of events in a
service stanza: `service … <GW:UP,IFUP:eth0>` to reload (`SIGHUP`) a
service when recieving the `"GW:UP"` or `"IFUP:eth0"` strings. If a
service cannot handle reload and must be stopped-started, simply add an
exclamation mark first: `service … <!GW:UP,IFUP:eth0>`.
The `<!>` notation to a service stanza can be used empty, then it will
apply to `reload` and `runlevel` commands. I.e., when a service's
`.conf` file has been changed Finit will stop and start it instead. If
@@ -768,8 +718,7 @@ behaviour, but not all daemons support this, unfortunately.
**Note:** even though it is possible to start services not belonging to
the current runlevel these services will not be respawned automatically
by Finit if they exit (crash). Hence, if the runlevel is 2, the below
Dropbear SSH service will not be restarted if it, for some reason,
exits.
Dropbear SSH service will not be restarted if it is killed or exits.
```shell
~ $ initctl status -v
+15 -3
View File
@@ -40,14 +40,14 @@ service's pidfile being created.
Triggering
----------
Conditions are triggered either by plugins or by using the `emit`
Conditions are triggered either by plugins or by using the `cond`
command of the `initctl` control tool.
* `initctl emit +your/cond/here`
* `initctl cond set your/cond/here`
To set a condition
* `initctl emit -your/cond/here`
* `initctl cond clear your/cond/here`
To clear a condition
@@ -115,6 +115,18 @@ are in the `on` state, as indicated by the `+`-prefix. `udhcpc` however
is not allowed to run since `net/vlan1/exist` condition is not satsifed.
As indicated by the `-`-prefix.
To fake interface `vlan1` suddenly appearing, and test what happens to
`udhcpc` we can enable debug mode and assert the condition, like this:
```shell
~ # initctl debug
~ # initctl cond set net/vlan1/exist
```
Then watch the console for the debug messages and then check the output
from `initctl cond show` again. (The client will likely have failed to
start, but at least the condition is now satisfied.)
Internals
---------
+41 -10
View File
@@ -173,9 +173,11 @@ static void show_cond_one(const char *_conds)
case COND_ON:
printf("+%s", cond);
break;
case COND_FLUX:
printf("\e[1m~%s\e[0m", cond);
break;
case COND_OFF:
printf("\e[1m-%s\e[0m", cond);
break;
@@ -185,10 +187,20 @@ static void show_cond_one(const char *_conds)
putchar('>');
}
static void show_cond(void)
static int do_cond_magic(char op, char *cond)
{
cond[0] = op;
return do_emit(cond);
}
static int do_cond_set (char *cond) { return do_cond_magic('+', cond); }
static int do_cond_clear(char *cond) { return do_cond_magic('-', cond); }
static int do_cond_flux (char *cond) { return do_cond_magic('~', cond); }
static int do_cond_show(char *UNUSED(arg))
{
enum cond_state cond;
svc_t *svc;
enum cond_state cond;
printf("PID Service Status Condition (+ on, ~ flux, - off)\n");
printf("====================================================================================\n");
@@ -209,12 +221,33 @@ static void show_cond(void)
show_cond_one(svc->cond);
putchar('\n');
}
return 0;
}
static int do_cond(char *UNUSED(arg))
static int do_cond(char *cmd)
{
show_cond();
return 0;
int c;
char *arg;
command_t command[] = {
{ "set", do_cond_set },
{ "clear", do_cond_clear },
{ "flux", do_cond_flux },
{ "show", do_cond_show },
{ NULL, NULL }
};
arg = strpbrk(cmd, " ");
if (arg) {
*arg = 0;
for (c = 0; command[c].cmd; c++) {
if (!strcmp(command[c].cmd, cmd))
return command[c].cb(arg);
}
}
return do_cond_show(NULL);
}
static int show_version(char *UNUSED(arg))
@@ -345,13 +378,12 @@ static int usage(int rc)
"Commands:\n"
" debug Toggle Finit (daemon) debug\n"
" help This help text\n"
" emit <EV> Emit event; a predefined event: RELOAD, STOP, START\n"
" or a custom string matching an event in a service\n"
" stanza, e.g: GW:UP, IFUP:IFNAME, IFDN:IFNAME. Where\n"
" IFNAME is the interface name, e.g. eth0\n"
" reload Reload *.conf in /etc/finit.d/ and activate changes\n"
" runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot\n"
" status | show Show status of services\n"
" cond set <COND> Set (assert) condition => +COND\n"
" cond clear <COND> Clear (deassert) condition => -COND\n"
" cond flux <COND> Emulate flux condition => ~COND\n"
" cond show Show condition status\n"
" start <JOB|NAME>[:ID] Start service by job# or name, with optional ID\n"
" stop <JOB|NAME>[:ID] Stop/Pause a running service by job# or name\n"
@@ -366,7 +398,6 @@ int main(int argc, char *argv[])
int c;
command_t command[] = {
{ "debug", toggle_debug },
{ "emit", do_emit },
{ "reload", do_reload },
{ "runlevel", do_runlevel },
{ "status", show_status },