mirror of
https://github.com/troglobit/finit.git
synced 2026-10-13 10:14:47 +00:00
doc: convert the documentation to the block format
The syntax overview no longer describes a line-based format, since that is not what the rest of the documentation shows. It now covers the grammar, the two naming conventions, the nine aliases, and the leading '-' on a path, and it says plainly that both formats are still read and told apart per file by content. Without that, a reader with an existing configuration is left wondering what happened to it. service-opts.md was a list of modifiers to place between a directive and its command, so it needed rewriting rather than translating: there are no positions left to describe. It is now grouped by what the settings do. conditions.md needed correcting. It presented '!' as a condition prefix alongside '~'. It is neither a condition nor a negation, it is a flag on the block that means one thing on a service and another on a run or task, so it is spelled reload-signal and required here, and the page maps the old form to both. Two things the pages claimed are not true. The kill delay range is 1-300, not 1-60, and stop and reload scripts are no longer run without a timeout. ChangeLog.md keeps its line-based examples. Those sit in historical release entries, and rewriting them in a syntax that did not exist at the time would misdate the format. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
+5
-1
@@ -171,7 +171,11 @@ Notice the `--` separator.
|
||||
To debug startup issues, in particular issues with getty/login, add
|
||||
the following to your Finit .conf file:
|
||||
|
||||
tty [12345789] notty noclear
|
||||
tty board {
|
||||
runlevel = "12345789"
|
||||
notty = true
|
||||
noclear = true
|
||||
}
|
||||
|
||||
The `notty` option ensures reusing the stdin/stdout set up by the
|
||||
kernel. Remember, this is only for debugging and would leave your
|
||||
|
||||
+60
-17
@@ -14,12 +14,21 @@ specified separated by comma. Multiple conditions are logically AND'ed
|
||||
during evaluation, i.e. all conditions must be satisfied in order for a
|
||||
service to run.
|
||||
|
||||
Two special prefixes can be used inside the angle brackets:
|
||||
One prefix can be used on a condition:
|
||||
|
||||
- `!` -- service does not support `SIGHUP` (noreload), or run/task
|
||||
should not block runlevel changes (i.e., bootstrap)
|
||||
- `~` -- propagate reload from this dependency, see below
|
||||
|
||||
The line-based format also accepts a leading `!` on the list, which is
|
||||
not a condition and not a negation. It is a flag on the block, and it
|
||||
means two unrelated things depending on where it sits: a service does
|
||||
not support `SIGHUP` (noreload), or a run/task should not block
|
||||
runlevel changes, i.e. bootstrap. Each of those is its own key here:
|
||||
|
||||
| Line-based | Block format |
|
||||
|---|---|
|
||||
| `<!...>` on a service or sysv | `reload-signal = "none"` |
|
||||
| `<!...>` on a run or task | `required = false` |
|
||||
|
||||
Finit guarantees by default that all run/tasks run (at least) once
|
||||
per runlevel. For most tasks this is a good default, for example
|
||||
checking SSH host keys or loading keymap. However, for conditions
|
||||
@@ -27,7 +36,12 @@ that are unlikely to happen it is not. (See example below.)
|
||||
|
||||
### Example
|
||||
|
||||
service [2345] <pid/setupd,pid/zebra> /sbin/netd -- Network monitor
|
||||
service netd {
|
||||
description = "Network monitor"
|
||||
runlevel = "2345"
|
||||
conditions = { "pid/setupd", "pid/zebra" }
|
||||
command = "/sbin/netd"
|
||||
}
|
||||
|
||||
In this example the Network monitor daemon `netd` is not started until
|
||||
both the `pid/setupd` *and* `pid/zebra` conditions are satisfied. A
|
||||
@@ -42,15 +56,28 @@ being created, i.e., the service's default readiness notification.
|
||||
Another example is `dropbear`, it does not support `SIGHUP`, but we can
|
||||
also see optional sourcing of arguments from an environment file:
|
||||
|
||||
service [2345789] <!> env:-/etc/default/dropbear dropbear -F -R $DROPBEAR_ARGS -- Dropbear SSH daemon
|
||||
service dropbear {
|
||||
description = "Dropbear SSH daemon"
|
||||
runlevel = "2345789"
|
||||
reload-signal = "none"
|
||||
envfile = "-/etc/default/dropbear"
|
||||
command = "dropbear -F -R $DROPBEAR_ARGS"
|
||||
}
|
||||
|
||||
Finally, the weird "block runlevel changes" example. Here we see what
|
||||
happens when Finit receives `SIGPWR`, sent from a power daemon like
|
||||
[powstatd(8)][]. A condition is asserted and a user can set up their
|
||||
own task to act on it. We do not want this task to block Finit from
|
||||
moving to the next runlevel after bootstrap, so we set `<!>`:
|
||||
moving to the next runlevel after bootstrap, so we set
|
||||
`required = false`:
|
||||
|
||||
task [S0123456789] <!sys/pwr/fail> name:pwrfail initctl poweroff -- Power failure, shutting down
|
||||
task pwrfail {
|
||||
description = "Power failure, shutting down"
|
||||
runlevel = "S0123456789"
|
||||
conditions = { "sys/pwr/fail" }
|
||||
required = false
|
||||
command = "initctl poweroff"
|
||||
}
|
||||
|
||||
|
||||
Propagating Reload in Dependencies
|
||||
@@ -65,13 +92,23 @@ not care if it reloads its config.
|
||||
For services that need to react when their upstream reloads, the `~`
|
||||
prefix propagates the reload from the dependency:
|
||||
|
||||
service <pid/svc_a> name:svc_b /sbin/svc_b -- Needs A (barrier)
|
||||
service <!~pid/svc_b> name:svc_c /sbin/svc_c -- Propagate reload from B
|
||||
service svc_b {
|
||||
description = "Needs A (barrier)"
|
||||
conditions = { "pid/svc_a" }
|
||||
command = "/sbin/svc_b"
|
||||
}
|
||||
|
||||
service svc_c {
|
||||
description = "Propagate reload from B"
|
||||
conditions = { "~pid/svc_b" }
|
||||
reload-signal = "none"
|
||||
command = "/sbin/svc_c"
|
||||
}
|
||||
|
||||
Here, `<~pid/svc_b>` means: propagate a reload of `svc_b` to `svc_c`.
|
||||
When `svc_b` reloads, `svc_c` will be restarted (because of `!`,
|
||||
noreload) instead of merely resumed. If `svc_c` supported `SIGHUP`
|
||||
(no `!` prefix), it would be sent `SIGHUP` instead.
|
||||
When `svc_b` reloads, `svc_c` will be restarted, because of
|
||||
`reload-signal = "none"`, instead of merely resumed. If `svc_c`
|
||||
supported `SIGHUP`, it would be sent `SIGHUP` instead.
|
||||
|
||||
This is similar to systemd's `PropagatesReloadTo=` directive, but
|
||||
declared on the consumer side rather than the provider side.
|
||||
@@ -103,7 +140,12 @@ services, or run/task jobs, on external site-dependent stimuli.
|
||||
|
||||
**Example:**
|
||||
|
||||
service [2345] <usr/foo> alarm --arg foo -- Foo alarm
|
||||
service alarm {
|
||||
description = "Foo alarm"
|
||||
runlevel = "2345"
|
||||
conditions = { "usr/foo" }
|
||||
command = "alarm --arg foo"
|
||||
}
|
||||
|
||||
For convenience, prefixing with `usr/` is allowed, but any other slashes
|
||||
or period characters are disallowed. E.g., to trigger the `Foo alarm`,
|
||||
@@ -126,8 +168,9 @@ Static (one-shot) conditions, like `usr/`, never enter the `flux` state.
|
||||
> "touch" or recreate, their PID file on `SIGHUP`. This can be done by
|
||||
> calling `utimensat()` on the PID file. Provided, of course, that the
|
||||
> service supports reloading on `SIGHUP`, otherwise it will be restarted
|
||||
> by Finit when they instead exit on the signal. For such services, use
|
||||
> `<!>` to tell Finit the service does not support `SIGHUP`.
|
||||
> by Finit when they instead exit on the signal. For such services,
|
||||
> set `reload-signal = "none"` to tell Finit the service does not
|
||||
> support `SIGHUP`.
|
||||
|
||||
|
||||
Built-in Conditions
|
||||
@@ -307,8 +350,8 @@ restarts that would otherwise occur because a depending service was sent
|
||||
|
||||
Services with the `~` prefix are an exception to this rule: when their
|
||||
conditions return to `on` after being in `flux`, the reload is propagated
|
||||
-- the service is reloaded (SIGHUP) or restarted (noreload `!`) instead
|
||||
of simply being resumed.
|
||||
-- the service is reloaded (SIGHUP), or restarted if it has
|
||||
`reload-signal = "none"`, instead of simply being resumed.
|
||||
|
||||
Therefore, any plugin that supplies Finit with conditions must ensure
|
||||
that their state is updated after each reconfiguration. This can be
|
||||
|
||||
+109
-80
@@ -23,77 +23,66 @@ Finit provides three different cgroup directives for controlling resource alloca
|
||||
Top-level Cgroup Definition
|
||||
----------------------------
|
||||
|
||||
**Syntax:** `cgroup NAME settings`
|
||||
**Syntax:** `cgroup NAME { settings }`
|
||||
|
||||
# Top-level cgroups and their default settings. All groups mandatory
|
||||
# but more can be added, max 8 groups in total currently. The cgroup
|
||||
# 'root' is also available, reserved for RT processes. Settings are
|
||||
# as-is, only one shorthand 'mem.' exists, other than that it's the
|
||||
# cgroup v2 controller default names.
|
||||
cgroup init cpu.weight:100
|
||||
cgroup user cpu.weight:100
|
||||
cgroup system cpu.weight:9800
|
||||
cgroup init { cpu.weight = 100 }
|
||||
cgroup user { cpu.weight = 100 }
|
||||
cgroup system { cpu.weight = 9800 }
|
||||
|
||||
Adding an extra cgroup `maint/` will require you to adjust the weight of
|
||||
the above three. We leave `init/` and `user/` as-is reducing weight of
|
||||
`system/` to 9700.
|
||||
|
||||
cgroup system cpu.weight:9700
|
||||
cgroup system { cpu.weight = 9700 }
|
||||
|
||||
# Example extra cgroup 'maint'
|
||||
cgroup maint cpu.weight:100
|
||||
cgroup maint { cpu.weight = 100 }
|
||||
|
||||
By default, the `system/` cgroup is selected for almost everything. The
|
||||
`init/` cgroup is reserved for PID 1 itself and its closest relatives.
|
||||
The `user/` cgroup is for local TTY logins spawned by getty.
|
||||
|
||||
Global Cgroup Selector
|
||||
----------------------
|
||||
Joining a Cgroup
|
||||
----------------
|
||||
|
||||
**Syntax:** `cgroup.NAME[,options]` (standalone directive)
|
||||
**Syntax:** `cgroup NAME { settings }` (inside a service block)
|
||||
|
||||
To select a different top-level cgroup, e.g. `maint/`, for a group of
|
||||
run/task/service directives in a `.conf` file, use the `cgroup.NAME`
|
||||
directive as a standalone line:
|
||||
Every block says which group it joins, by name. An empty block joins
|
||||
without changing anything:
|
||||
|
||||
cgroup.maint
|
||||
service [...] <...> /path/to/foo args -- description
|
||||
service [...] <...> /path/to/bar args -- description
|
||||
service foo {
|
||||
cgroup maint {}
|
||||
command = "/path/to/foo args"
|
||||
}
|
||||
|
||||
Both services will run in the `maint/` cgroup.
|
||||
service bar {
|
||||
cgroup maint {}
|
||||
command = "/path/to/bar args"
|
||||
}
|
||||
|
||||
You can also include options with the global selector:
|
||||
Both services run in the `maint/` cgroup. Settings inside the block
|
||||
apply to that service alone:
|
||||
|
||||
cgroup.system,delegate
|
||||
service [...] <...> /path/to/foo args -- description
|
||||
service foo {
|
||||
cgroup maint {
|
||||
cpu.max = 10000
|
||||
memory.max = 655360
|
||||
}
|
||||
command = "/path/to/foo args"
|
||||
}
|
||||
|
||||
Per-Service Cgroup Option
|
||||
--------------------------
|
||||
|
||||
**Syntax:** `cgroup.NAME[,options]` or `cgroup:options` (service option)
|
||||
|
||||
To override the cgroup for a specific service, use the `cgroup.NAME`
|
||||
option within the service directive:
|
||||
|
||||
service [...] <...> cgroup.maint /path/to/foo args -- description
|
||||
|
||||
This form also allows per-service limits. Two syntaxes are supported:
|
||||
|
||||
**New comma-separated syntax (recommended):**
|
||||
|
||||
service [...] <...> cgroup.maint,cpu.max:10000,mem.max:655360 /path/to/foo args -- description
|
||||
|
||||
**Old colon-separated syntax (legacy):**
|
||||
|
||||
service [...] <...> cgroup.maint:cpu.max:10000,mem.max:655360 /path/to/foo args -- description
|
||||
|
||||
You can also apply options to the current default cgroup (without changing it)
|
||||
using the `cgroup:options` syntax:
|
||||
|
||||
service [...] <...> cgroup:cpu.max:10000,mem.max:655360 /path/to/foo args -- description
|
||||
|
||||
Both syntaxes work identically. The new comma-separated syntax is recommended
|
||||
as it's more consistent with other option parsing in Finit.
|
||||
> [!NOTE]
|
||||
> The legacy format has a standalone `cgroup.NAME` line that selects a
|
||||
> group for every stanza following it in the file, and a `cgroup:options`
|
||||
> form that applies settings to whichever group is current without
|
||||
> naming it. Neither has an equivalent here, by design: a block that
|
||||
> joins a group says so itself, so the group cannot depend on what came
|
||||
> earlier in the file.
|
||||
|
||||
Note the `mem.` exception to the rule: every cgroup setting maps directly to
|
||||
cgroup v2 syntax. I.e., `cpu.max` maps to the file `/sys/fs/cgroup/maint/foo/cpu.max`.
|
||||
@@ -108,40 +97,66 @@ configuration filename (without the `.conf` extension). For example, a
|
||||
service defined in `system/10-hotplug.conf` would create a cgroup at
|
||||
`/sys/fs/cgroup/system/10-hotplug/` by default.
|
||||
|
||||
To use a more descriptive name (recommended for clarity), you can specify
|
||||
`name:` in the cgroup directive:
|
||||
To use a more descriptive name (recommended for clarity), set `name`
|
||||
inside the cgroup block:
|
||||
|
||||
service [...] <...> cgroup.system,name:udevd /lib/systemd/systemd-udevd -- Device event daemon
|
||||
service udevd {
|
||||
description = "Device event daemon"
|
||||
cgroup system { name = "udevd" }
|
||||
command = "/lib/systemd/systemd-udevd"
|
||||
}
|
||||
|
||||
This creates the cgroup at `/sys/fs/cgroup/system/udevd/` instead.
|
||||
|
||||
The syntax supports combining the name override with other options:
|
||||
`name` combines with any other setting:
|
||||
|
||||
service [...] <...> cgroup.system,name:udevd,cpu.max:10000 /lib/systemd/systemd-udevd -- Device event daemon
|
||||
service udevd {
|
||||
description = "Device event daemon"
|
||||
cgroup system {
|
||||
name = "udevd"
|
||||
cpu.max = 10000
|
||||
}
|
||||
command = "/lib/systemd/systemd-udevd"
|
||||
}
|
||||
|
||||
Or with delegation:
|
||||
|
||||
service [2345] @podman:podman \
|
||||
cgroup.containers,name:podman,delegate,mem.max:4G \
|
||||
/usr/bin/podman system service -- Podman API
|
||||
service podman {
|
||||
description = "Podman API"
|
||||
runlevel = "2345"
|
||||
user = "podman"
|
||||
group = "podman"
|
||||
cgroup containers {
|
||||
name = "podman"
|
||||
delegate = true
|
||||
memory.max = 4G
|
||||
}
|
||||
command = "/usr/bin/podman system service"
|
||||
}
|
||||
|
||||
A daemon using `SCHED_RR` currently needs to run outside the default cgroups.
|
||||
A daemon using `SCHED_RR` currently needs to run outside the default
|
||||
cgroups.
|
||||
|
||||
service [...] <...> cgroup.root /path/to/daemon arg -- Real-Time process
|
||||
service rt {
|
||||
description = "Real-Time process"
|
||||
cgroup root {}
|
||||
command = "/path/to/daemon arg"
|
||||
}
|
||||
|
||||
Cgroup Delegation
|
||||
-----------------
|
||||
|
||||
For services that need to create their own child cgroups (container runtimes
|
||||
like Docker, Podman, systemd-nspawn, LXC), use the `delegate` option:
|
||||
like Docker, Podman, systemd-nspawn, LXC), set `delegate`:
|
||||
|
||||
service [2345] @dockerd:dockerd \
|
||||
cgroup.system,delegate /usr/bin/dockerd -- Docker daemon
|
||||
|
||||
Or with the old colon syntax:
|
||||
|
||||
service [2345] @dockerd:dockerd \
|
||||
cgroup.system:delegate /usr/bin/dockerd -- Docker daemon
|
||||
service dockerd {
|
||||
description = "Docker daemon"
|
||||
runlevel = "2345"
|
||||
user = "dockerd"
|
||||
group = "dockerd"
|
||||
cgroup system { delegate = true }
|
||||
command = "/usr/bin/dockerd"
|
||||
}
|
||||
|
||||
This allows the container runtime to:
|
||||
|
||||
@@ -159,32 +174,46 @@ When delegation is enabled, Finit:
|
||||
|
||||
**Requirements:**
|
||||
|
||||
- The service should specify `@user:group` for proper ownership
|
||||
- The service should specify `user` and `group` for proper ownership
|
||||
- Controllers are delegated from the parent cgroup
|
||||
|
||||
**Example with additional config (new syntax):**
|
||||
**Example with additional config:**
|
||||
|
||||
service [2345] @podman:podman \
|
||||
cgroup.containers,delegate,mem.max:4G \
|
||||
/usr/bin/podman system service -- Podman API
|
||||
service podman {
|
||||
description = "Podman API"
|
||||
runlevel = "2345"
|
||||
user = "podman"
|
||||
group = "podman"
|
||||
cgroup containers {
|
||||
delegate = true
|
||||
memory.max = 4G
|
||||
}
|
||||
command = "/usr/bin/podman system service"
|
||||
}
|
||||
|
||||
**Or with old syntax:**
|
||||
|
||||
service [2345] @podman:podman \
|
||||
cgroup.containers:delegate,mem.max:4G \
|
||||
/usr/bin/podman system service -- Podman API
|
||||
|
||||
Both examples delegate the cgroup while also setting a 4GB memory limit.
|
||||
This delegates the cgroup while also setting a 4GB memory limit.
|
||||
|
||||
**Container template example:**
|
||||
|
||||
Here's a real-world example from [Infix OS](https://github.com/kernelkit/infix)
|
||||
for running rootful podman container instances using delegation:
|
||||
|
||||
sysv log:prio:local1,tag:%i kill:30 pid:!/run/container:%i.pid \
|
||||
pre:0,/usr/sbin/container cleanup:0,/usr/sbin/container \
|
||||
cgroup.system,delegate \
|
||||
[2345] <!> :%i container -n %i -- container %i
|
||||
sysv container:%i {
|
||||
description = "container %i"
|
||||
runlevel = "2345"
|
||||
reload-signal = "none"
|
||||
pidfile = "/run/container:%i.pid"
|
||||
stop-timeout = 30
|
||||
log { priority = "local1" identity = "%i" }
|
||||
|
||||
exec-start-pre = "/usr/sbin/container"
|
||||
exec-start-pre-timeout = 0
|
||||
exec-cleanup = "/usr/sbin/container"
|
||||
exec-cleanup-timeout = 0
|
||||
|
||||
cgroup system { delegate = true }
|
||||
command = "container -n %i"
|
||||
}
|
||||
|
||||
This template uses `sysv` type with delegation, demonstrating that cgroup
|
||||
delegation works with different service types, not just `service`.
|
||||
|
||||
+7
-6
@@ -6,15 +6,16 @@ and any `*.conf`, was added. It is worth noting that these are global
|
||||
and *shared with all* services -- the only way to have a service-local
|
||||
environment is detailed in [Services Environment](service-env.md).
|
||||
|
||||
The syntax for global environment variables is straight forward. In
|
||||
Finit v4.4 the `set` keyword was added for completeness, but the old
|
||||
syntax (without the `set ` prefix) is still honored:
|
||||
Global environment variables go in an `environment` block, `env` for
|
||||
short:
|
||||
|
||||
set foo=bar
|
||||
set baz="qux"
|
||||
environment {
|
||||
foo = "bar"
|
||||
baz = "qux"
|
||||
}
|
||||
|
||||
On reload of .conf files, all tracked environment variables are cleared
|
||||
so if `foo=bar` is removed from `finit.conf`, or any `finit.d/*.conf`
|
||||
so if `foo` is removed from `finit.conf`, or any `finit.d/*.conf`
|
||||
file, it will no longer be used by Finit or any new (!) started
|
||||
run/tasks or services. The environment of already started processes can
|
||||
not be changed.
|
||||
|
||||
+98
-13
@@ -6,24 +6,109 @@ the navigation menu.
|
||||
Configuration File Syntax
|
||||
--------------------------
|
||||
|
||||
The file format is line based, empty lines and comments, lines starting
|
||||
with `#`, are ignored. A configuration directive starts with a keyword
|
||||
followed by a space and the rest of the line is treated as the value.
|
||||
|
||||
As of Finit v4.4, configuration directives can be broken up in multiple
|
||||
lines using the continuation character `\`, and trailing comments are
|
||||
also allowed. Example:
|
||||
A `.conf` file is a series of blocks. Every setting is a key inside
|
||||
one, so nothing has to be remembered by position:
|
||||
|
||||
```aconf
|
||||
# Escape \# chars if you want them literal in, e.g., descriptions
|
||||
service name:sysklogd [S123456789] \
|
||||
env:-/etc/default/sysklogd \
|
||||
syslogd -F $SYSLOGD_ARGS \
|
||||
-- System log daemon \# 1 # Comments allowed
|
||||
service sysklogd {
|
||||
description = "System log daemon"
|
||||
runlevel = "S123456789"
|
||||
envfile = "-/etc/default/sysklogd"
|
||||
command = "syslogd -F $SYSLOGD_ARGS"
|
||||
}
|
||||
```
|
||||
|
||||
Values are quoted strings, bare words, or integers. Lists use braces,
|
||||
and a block may carry a title, which becomes the service identity:
|
||||
|
||||
```aconf
|
||||
# shell comment
|
||||
// C++ comment
|
||||
/* C comment */
|
||||
|
||||
key = "value" # string
|
||||
number = 20 # integer
|
||||
flag = true # boolean
|
||||
list = { "one", "two" } # string list
|
||||
block title { key = "value" } # titled section
|
||||
|
||||
path = "${HOME}/thing" # environment expansion
|
||||
include("/etc/finit.d/extra.conf") # include another file
|
||||
```
|
||||
|
||||
Bare words work wherever a string is expected, so `memory.max = 65M`
|
||||
and `restart = always` need no quotes.
|
||||
|
||||
### Two conventions
|
||||
|
||||
Keys are kebab-case, never `snake_case` or `CamelCase`: `restart-sec`,
|
||||
`stop-timeout`, `reboot-watchdog`.
|
||||
|
||||
Keys that take a list are plural: `conditions`, `conflicts`,
|
||||
`capabilities`, `modules`, `extra-groups`. Two imperatives keep their
|
||||
singular form because they are verbs rather than nouns: `mknod` and
|
||||
`include`.
|
||||
|
||||
### Short forms
|
||||
|
||||
Nine keys have an alias. An alias may abbreviate the canonical name,
|
||||
or preserve the spelling the line-based format used; it never renames.
|
||||
|
||||
| Canonical | Alias | Canonical | Alias |
|
||||
|---|---|---|---|
|
||||
| `description` | `desc` | `manual-start` | `manual` |
|
||||
| `conditions` | `cond` | `remain-after-exit` | `remain` |
|
||||
| `capabilities` | `caps` | `stop-signal` | `halt` |
|
||||
| `modules` | `mod` | `stop-timeout` | `kill` |
|
||||
| `envfile` | `env` | | |
|
||||
|
||||
### Optional paths
|
||||
|
||||
A leading `-` on a path means carry on if it is not there:
|
||||
|
||||
```aconf
|
||||
service foo {
|
||||
envfile = "-/etc/default/foo" # skip the file if missing
|
||||
command = "-/usr/sbin/foo" # skip the whole block if missing
|
||||
}
|
||||
```
|
||||
|
||||
That is the only mark meaning "optional". Two others mean something
|
||||
else: `!` on `runlevel` inverts the set, e.g. `runlevel = "!12345"`,
|
||||
and `~` on a condition propagates a reload from the service it names.
|
||||
Both are covered where they apply.
|
||||
|
||||
|
||||
Both Formats Are Read
|
||||
---------------------
|
||||
|
||||
Finit also reads the line-based format it has always used, where a
|
||||
stanza is a keyword followed by values whose meaning comes from their
|
||||
position:
|
||||
|
||||
```aconf
|
||||
service [S123456789] env:-/etc/default/sysklogd syslogd -F $SYSLOGD_ARGS -- System log daemon
|
||||
```
|
||||
|
||||
That format still works and is not going away. It is frozen at the
|
||||
Finit 4.x feature set, so new settings appear only in the block format,
|
||||
and the documentation is written in blocks throughout.
|
||||
|
||||
There is no new file extension and no marker line. Every file is still
|
||||
`*.conf`, and Finit decides which format a file is in by reading it: if
|
||||
it parses as blocks it is a block file, otherwise it goes to the
|
||||
line-based parser. A file is one format or the other, never a mix.
|
||||
|
||||
Because the two are told apart before either parser commits, a typo
|
||||
reports its own file and line instead of being mistaken for the other
|
||||
format:
|
||||
|
||||
```
|
||||
parse error: /etc/finit.d/foo.conf:3: no such option 'commnad'
|
||||
```
|
||||
|
||||
The .conf files `/etc/finit.conf` and `/etc/finit.d/*` support many
|
||||
directives. Some are restricted, e.g., only available at bootstrap,
|
||||
settings. Some are restricted, e.g., only available at bootstrap,
|
||||
runlevel `S`. Read on in [Files & Layout](files.md) for more on how
|
||||
to structure your .conf files.
|
||||
|
||||
|
||||
+14
-3
@@ -38,12 +38,19 @@ Log rotation is controlled using the global `log` setting.
|
||||
|
||||
**Example:**
|
||||
|
||||
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
|
||||
service ntpd {
|
||||
description = "NTP daemon"
|
||||
log {
|
||||
priority = "user.warn"
|
||||
identity = "ntpd"
|
||||
}
|
||||
command = "/sbin/ntpd pool.ntp.org"
|
||||
}
|
||||
|
||||
Output Buffering
|
||||
----------------
|
||||
|
||||
When using the `log` directive, Finit redirects the service's stdout and
|
||||
When using the `log` block, Finit redirects the service's stdout and
|
||||
stderr to a pipe connected to a logger process. Programs detect this as
|
||||
non-interactive output (i.e., `isatty()` returns false) and typically
|
||||
switch from line-buffered to fully-buffered mode.
|
||||
@@ -53,7 +60,11 @@ directly, so this is rarely an issue. However, if a service's log
|
||||
messages appear delayed or batched, you can force line-buffered output
|
||||
by wrapping the command with `stdbuf`:
|
||||
|
||||
service log /usr/bin/stdbuf -oL /path/to/command -- My service
|
||||
service myservice {
|
||||
description = "My service"
|
||||
log { }
|
||||
command = "/usr/bin/stdbuf -oL /path/to/command"
|
||||
}
|
||||
|
||||
The `-oL` option forces line-buffered output, and `-o0` forces unbuffered
|
||||
output. See `stdbuf(1)` for details.
|
||||
|
||||
@@ -48,7 +48,10 @@ system administrator.
|
||||
The bundled default `rescue.conf` contains nothing more than:
|
||||
|
||||
runlevel 1
|
||||
tty [12345] rescue
|
||||
tty rescue {
|
||||
runlevel = "12345"
|
||||
rescue = true
|
||||
}
|
||||
|
||||
The `tty` has the `rescue` option set, which works similar to the board
|
||||
bring-up tty option `notty`. The major difference being that `sulogin`
|
||||
@@ -57,6 +60,9 @@ is started to query for root/admin password. If `sulogin` is not found,
|
||||
|
||||
If Finit cannot find `/lib/finit/rescue.conf` it defaults to:
|
||||
|
||||
tty [12345] rescue
|
||||
tty rescue {
|
||||
runlevel = "12345"
|
||||
rescue = true
|
||||
}
|
||||
|
||||
There is no way to exit the *fallback* rescue mode.
|
||||
+10
-2
@@ -26,8 +26,16 @@ the lifetime of your system.
|
||||
|
||||
Example:
|
||||
|
||||
task [S] /lib/console-setup/console-setup.sh
|
||||
service [S12345] env:-/etc/default/rsyslog rsyslogd -n $RSYSLOGD_ARGS
|
||||
task console-setup {
|
||||
runlevel = "S"
|
||||
command = "/lib/console-setup/console-setup.sh"
|
||||
}
|
||||
|
||||
service rsyslogd {
|
||||
runlevel = "S12345"
|
||||
envfile = "-/etc/default/rsyslog"
|
||||
command = "rsyslogd -n $RSYSLOGD_ARGS"
|
||||
}
|
||||
|
||||
When bootstrap has completed, Finit moves to runlevel 2. This can be
|
||||
changed in `/etc/finit.conf` using the `runlevel N` directive, or by a
|
||||
|
||||
@@ -13,7 +13,12 @@ file `/etc/default/foo`. Like this:
|
||||
|
||||
* `/etc/finit.conf`:
|
||||
|
||||
service [2345] env:-/etc/default/foo foo -n $FOO_OPTIONS -- Example foo daemon
|
||||
service foo {
|
||||
description = "Example foo daemon"
|
||||
runlevel = "2345"
|
||||
envfile = "-/etc/default/foo"
|
||||
command = "foo -n $FOO_OPTIONS"
|
||||
}
|
||||
|
||||
Here the service `foo` is started with `-n`, to make sure it runs in the
|
||||
foreground, and the with the options found in the environment file. With
|
||||
@@ -22,6 +27,8 @@ the `ps` command we can see that the process is started with:
|
||||
foo -n --extra-arg=bar -s -x
|
||||
|
||||
> [!NOTE]
|
||||
> The leading `-` in `env:` determines if Finit should treat a missing
|
||||
> environment file as blocking the start of the service or not. When
|
||||
> `-` is used, a missing environment file does *not* block the start.
|
||||
> The leading `-` on `envfile` determines if Finit should treat a
|
||||
> missing environment file as blocking the start of the service or not.
|
||||
> When `-` is used, a missing environment file does *not* block the
|
||||
> start. The same mark works on `command`, where it means carry on if
|
||||
> the binary is missing.
|
||||
|
||||
+134
-98
@@ -1,21 +1,22 @@
|
||||
Service Options
|
||||
===============
|
||||
|
||||
The run/task/tty/service/sysv directives take modifiers, or options, to
|
||||
control their behavior. This section lists them with their limitations.
|
||||
All modifiers must be placed between the directive and its command.
|
||||
The `run`, `task`, `tty`, `service` and `sysv` blocks take settings as
|
||||
keys. This section lists them with their limitations.
|
||||
|
||||
The name of a service, shown by the `initctl` tool, defaults to the
|
||||
basename of the service executable. It can be changed with the `name:`
|
||||
option:
|
||||
The name of a service, shown by the `initctl` tool, is the block title.
|
||||
It defaults to the basename of the executable if the title is omitted:
|
||||
|
||||
name:<service-name>
|
||||
service sshd {
|
||||
command = "/usr/sbin/sshd -D"
|
||||
}
|
||||
|
||||
For multiple instances of a service, with the same `name`, set the
|
||||
identifier `:ID` to prevent Finit from replacing previous instances:
|
||||
For multiple instances of a service, with the same name, add an
|
||||
identifier after a colon to prevent Finit from replacing previous
|
||||
instances:
|
||||
|
||||
service name:ssdp :eth1 ssdpd eth1 -- Windows discovery on eth1
|
||||
service name:ssdp :eth2 ssdpd eth2 -- Windows discovery on eth2
|
||||
service ssdp:eth1 { command = "ssdpd eth1" }
|
||||
service ssdp:eth2 { command = "ssdpd eth2" }
|
||||
|
||||
The [`initctl`](../initctl.md) tool will list these two services as:
|
||||
|
||||
@@ -23,107 +24,140 @@ The [`initctl`](../initctl.md) tool will list these two services as:
|
||||
- ssdp:eth2
|
||||
|
||||
Conflicting services that must be prevented from starting, use the
|
||||
`conflict:` option:
|
||||
`conflicts` key:
|
||||
|
||||
service [S12345789] udevd -- Device event management daemon
|
||||
run [S] conflict:udevd mdev -s -- Populating device tree
|
||||
service udevd { command = "udevd" }
|
||||
run mdev {
|
||||
runlevel = "S"
|
||||
conflicts = { "udevd" }
|
||||
command = "mdev -s"
|
||||
}
|
||||
|
||||
Multiple conflicting services can be separated using `,`:
|
||||
The list may name several, and an instance is named the same way it is
|
||||
declared:
|
||||
|
||||
service :1 abc
|
||||
service :2 abc
|
||||
service conflict:abc:1,abc:2 cde
|
||||
service abc:1 { command = "abc 1" }
|
||||
service abc:2 { command = "abc 2" }
|
||||
service cde { conflicts = { "abc:1", "abc:2" } command = "cde" }
|
||||
|
||||
If a service should not be automatically started, it can be configured
|
||||
as manual with the optional `manual` argument. The service can then be
|
||||
started at any time by running `initctl start <service>`.
|
||||
If a service should not be automatically started, set `manual-start`.
|
||||
It can then be started at any time with `initctl start <service>`:
|
||||
|
||||
manual:yes
|
||||
service lldpd {
|
||||
manual-start = true
|
||||
command = "/usr/sbin/lldpd -d"
|
||||
}
|
||||
|
||||
Other run/task/service options are:
|
||||
Other run/task/service settings are:
|
||||
|
||||
* `caps:...` -- see the [Linux Capabilities](capabilities.md) section
|
||||
* `cgroup.NAME[,opts]` or `cgroup:opts` -- see the [Cgroups](cgroups.md) section
|
||||
* `env:[-]/path/to/env` -- see the [Service Environment](service-env.md) section
|
||||
* `log:...` -- see [Redirecting Output](logging.md#redirecting-output)
|
||||
* `tty:<dev>` -- see [Controlling TTY](tty.md#controlling-tty)
|
||||
* `nowarn` -- see [Conditional Loading](services.md#conditional-loading)
|
||||
* `notify:...` -- see [Service Synchronization](service-sync.md)
|
||||
* `if:...` -- see [Conditional Execution](services.md#conditional-execution)
|
||||
* `type:forking` -- see description of the [service](services.md) directive
|
||||
* `capabilities` -- see the [Linux Capabilities](capabilities.md) section
|
||||
* `cgroup NAME {}` -- see the [Cgroups](cgroups.md) section
|
||||
* `envfile` -- see the [Service Environment](service-env.md) section
|
||||
* `log {}` -- see [Redirecting Output](logging.md#redirecting-output)
|
||||
* `tty` -- see [Controlling TTY](tty.md#controlling-tty)
|
||||
* `notify` -- see [Service Synchronization](service-sync.md)
|
||||
* `if` -- see [Conditional Execution](services.md#conditional-execution)
|
||||
* `type = "forking"` -- see description of the [service](services.md) block
|
||||
* a leading `-` on `command` -- see [Conditional Loading](services.md#conditional-loading)
|
||||
|
||||
As mentioned previously, services are automatically started, restarted,
|
||||
and stopped, depending on the configuration and conditions. Within the
|
||||
confines of that the following options are available:
|
||||
Restarting
|
||||
----------
|
||||
|
||||
* `restart:NUM` -- number of times Finit tries to restart a crashing
|
||||
service, default: 10, max: 255. When this limit is reached the
|
||||
service is marked *crashed* and must be restarted manually with
|
||||
`initctl restart NAME`
|
||||
* `restart_sec:SEC` -- number of seconds before Finit tries to restart
|
||||
a crashing service, default: 2 seconds for the first five retries,
|
||||
then back-off to 5 seconds. The maximum of this configured value
|
||||
and the above (2 and 5) will be used
|
||||
* `restart:always` -- no upper limit on the number of times Finit
|
||||
tries to restart a crashing service. Same as `restart:-1`
|
||||
* `norestart` -- dont restart on failures, same as `restart:0`
|
||||
* `respawn` -- bypasses the `restart` mechanism completely, allows
|
||||
endless restarts. Useful in many use-cases, but not what `service`
|
||||
was originally designed for so not the default behavior
|
||||
* `remain:yes` -- for `run` and `task` only. Prevents the task from
|
||||
re-running on runlevel re-entry and ensures the `post:` script runs
|
||||
when the task is explicitly stopped or leaves its valid runlevels.
|
||||
Similar to systemd's `RemainAfterExit=yes`. See [Task and Run](task-and-run.md)
|
||||
for more details
|
||||
* `oncrash:reboot` -- when all retries have failed, and the service
|
||||
has *crashed*, if this option is set the system is rebooted
|
||||
* `oncrash:script` -- similarly, but instead of rebooting, call the
|
||||
`post:script` action with exit code `crashed`, see below
|
||||
* `reload:'script [args]'` -- some services do not support `SIGHUP` but
|
||||
may have other ways to update the configuration of a running daemon.
|
||||
When `reload:script` is defined it is preferred over `SIGHUP`. Like
|
||||
systemd, Finit sets `$MAINPID` as a convenience to scripts, which in
|
||||
effect also allow `reload:'kill -HUP $MAINPID'`
|
||||
* `stop:'script [args]'` -- some services may require alternate methods
|
||||
to be stopped. If a `stop:script` is defined it is preferred over
|
||||
`SIGTERM` and `stop`, for `service` and `sysv`, respectively.
|
||||
Similar to `reload:script`, Finit sets `$MAINPID`
|
||||
Services are automatically started, restarted, and stopped, depending
|
||||
on the configuration and conditions. Within the confines of that the
|
||||
following settings are available:
|
||||
|
||||
> [!CAUTION]
|
||||
> Both `reload:script` and `stop:script` are called as PID 1, without
|
||||
> any timeout! Meaning, it is up to you to ensure the script is not
|
||||
> blocking for seconds at a time or never terminates.
|
||||
* `restart-max = NUM` -- number of times Finit tries to restart a
|
||||
crashing service, default: 10, max: 255. When this limit is
|
||||
reached the service is marked *crashed* and must be restarted
|
||||
manually with `initctl restart NAME`
|
||||
* `restart-sec = SEC` -- number of seconds before Finit tries to
|
||||
restart a crashing service, default: 2 seconds for the first five
|
||||
retries, then back-off to 5 seconds. The maximum of this
|
||||
configured value and the above (2 and 5) will be used
|
||||
* `restart = "always"` -- no upper limit on the number of times Finit
|
||||
tries to restart a crashing service
|
||||
* `restart = "never"` -- do not restart on failures. `false` is
|
||||
accepted as a synonym, and `true` selects the default policy
|
||||
* `respawn = true` -- bypasses the `restart` mechanism completely,
|
||||
allowing endless restarts. Exiting is treated as normal work
|
||||
rather than failure, so the service is restarted at once instead of
|
||||
being counted and delayed. This is how a `tty` behaves; it is not
|
||||
what `service` was designed for, so it is not the default
|
||||
* `remain-after-exit = true` -- for `run` and `task` only. Prevents
|
||||
the task from re-running on runlevel re-entry and ensures the
|
||||
`exec-stop-post` script runs when the task is explicitly stopped or
|
||||
leaves its valid runlevels. This is systemd's `RemainAfterExit=`.
|
||||
See [Task and Run](task-and-run.md) for more details
|
||||
* `oncrash = "reboot"` -- when all retries have failed, and the
|
||||
service has *crashed*, the system is rebooted
|
||||
* `oncrash = "script"` -- similarly, but instead of rebooting, call
|
||||
the `exec-stop-post` script with exit code `crashed`, 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 (unless a `stop:'script'` is used).
|
||||
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`.
|
||||
Stopping and reloading
|
||||
----------------------
|
||||
|
||||
Services, including the `sysv` variant, support pre/post/ready and
|
||||
cleanup scripts:
|
||||
When stopping a service, either manually or when moving to another
|
||||
runlevel, Finit starts by sending `SIGTERM` to let the process shut
|
||||
down gracefully. If it has not been collected within 3 seconds,
|
||||
`SIGKILL` follows. Both ends of that are configurable:
|
||||
|
||||
* `pre:[0-3600,]script` -- called before the sysv/service is stated
|
||||
* `post:[0-3600,]script` -- called after the sysv/service has stopped
|
||||
* `ready:[0-3600,]script` -- called when the sysv/service is ready
|
||||
* `cleanup:[0-3600,]script` -- called when run/task/sysv/service is removed
|
||||
* `stop-signal = "SIGPWR"` -- send this instead of `SIGTERM`
|
||||
* `stop-timeout = 10` -- seconds to wait before `SIGKILL`, 1-300
|
||||
|
||||
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 are executed
|
||||
from the `$HOME` of the given user. The scripts are not called with any
|
||||
argument, but get a set of environment variables:
|
||||
Some services need more than a signal:
|
||||
|
||||
* `exec-stop = "script [args]"` -- run instead of sending the stop
|
||||
signal, and instead of `stop` for `sysv`
|
||||
* `exec-reload = "script [args]"` -- run instead of sending `SIGHUP`.
|
||||
Like systemd, Finit sets `$MAINPID` as a convenience to scripts,
|
||||
which in effect also allows `exec-reload = "kill -HUP $MAINPID"`
|
||||
|
||||
If a daemon cannot be reloaded with a signal at all, say so and Finit
|
||||
restarts it instead:
|
||||
|
||||
service dropbear {
|
||||
reload-signal = "none"
|
||||
command = "/usr/sbin/dropbear -R -F"
|
||||
}
|
||||
|
||||
`SIGHUP` is the default and the only other accepted value, with or
|
||||
without the `SIG` prefix and in any case.
|
||||
|
||||
Scripts
|
||||
-------
|
||||
|
||||
Services, including the `sysv` variant, support six lifecycle scripts:
|
||||
|
||||
* `exec-start-pre` -- called before the sysv/service is started
|
||||
* `exec-start-ready` -- called when the sysv/service is ready
|
||||
* `exec-stop` -- called instead of the stop signal
|
||||
* `exec-stop-post` -- called after the sysv/service has stopped
|
||||
* `exec-reload` -- called instead of `SIGHUP`
|
||||
* `exec-cleanup` -- called when run/task/sysv/service is removed
|
||||
|
||||
Each takes a matching `-timeout`, in seconds, 0-3600, after which Finit
|
||||
kills the script. It defaults to the `stop-timeout` value and can be
|
||||
disabled by setting it to zero:
|
||||
|
||||
service foo {
|
||||
exec-start-pre = "/etc/foo/pre.sh"
|
||||
exec-start-pre-timeout = 10
|
||||
command = "/usr/sbin/foo"
|
||||
}
|
||||
|
||||
These scripts run as the same user and group as the service itself,
|
||||
with any `envfile` sourced. They 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. Yes, the text is correct, the naming was an accident:
|
||||
The `exec-stop-post` script is called with an additional set of
|
||||
environment variables. Yes, the text is correct, the naming was an
|
||||
accident:
|
||||
|
||||
- `EXIT_CODE=[exited,signal,crashed]`: normal exit, signaled, or
|
||||
crashed
|
||||
@@ -131,11 +165,13 @@ variables. Yes, the text is correct, the naming was an accident:
|
||||
the program, if it exited normally, or the signal name (`HUP`,
|
||||
`TERM`, etc.) if it exited due to signal
|
||||
|
||||
When a run/task/sys/service is removed (disable + reload) it is first
|
||||
stopped and then removed from the runlevel. The `post:script` always
|
||||
runs when the process has stopped, and the `cleanup:script` runs when
|
||||
the the stanza has been removed from the runlevel.
|
||||
When a run/task/sysv/service is removed (disable + reload) it is first
|
||||
stopped and then removed from the runlevel. The `exec-stop-post`
|
||||
script always runs when the process has stopped, and `exec-cleanup`
|
||||
runs when the stanza has been removed from the runlevel.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> These script actions are intended for setup, cleanup, and readiness
|
||||
> notification. It is up to the user to ensure the scripts terminate.
|
||||
> notification. A script that outlives its timeout is killed, so pick
|
||||
> one that suits the work, or set it to zero to opt out and take
|
||||
> responsibility for the script terminating.
|
||||
|
||||
@@ -38,10 +38,10 @@ This will be made the default in Finit 5.0. In this mode of operation,
|
||||
every service needs to explicitly declare their readiness notification,
|
||||
like this:
|
||||
|
||||
service notify:pid watchdogd
|
||||
service notify:systemd foo
|
||||
service notify:s6 bar
|
||||
service notify:none qux
|
||||
service watchdogd { notify = "pid" command = "watchdogd" }
|
||||
service foo { notify = "systemd" command = "foo" }
|
||||
service bar { notify = "s6" command = "bar" }
|
||||
service qux { notify = "none" command = "qux" }
|
||||
|
||||
The `notify:none` syntax is for completeness in systems which run in
|
||||
`readiness pid` mode (default). Services declared with `notify:none`
|
||||
@@ -50,8 +50,15 @@ will transition to ready as soon as Finit has started them, e.g.,
|
||||
|
||||
To synchronize two services the following condition can be used:
|
||||
|
||||
service notify:pid watchdogd
|
||||
service <service/watchdogd/ready> stress-ng --cpu 8
|
||||
service watchdogd {
|
||||
notify = "pid"
|
||||
command = "watchdogd"
|
||||
}
|
||||
|
||||
service stress-ng {
|
||||
conditions = { "service/watchdogd/ready" }
|
||||
command = "stress-ng --cpu 8"
|
||||
}
|
||||
|
||||
For details on the syntax and options, see below.
|
||||
|
||||
|
||||
@@ -14,7 +14,12 @@ example employs a wrapper script in `/etc/start.d`.
|
||||
|
||||
* `/etc/finit.d/available/program.conf`:
|
||||
|
||||
service [235] <!> /etc/start.d/program -- Example Program
|
||||
service program {
|
||||
description = "Example Program"
|
||||
runlevel = "235"
|
||||
reload-signal = "none"
|
||||
command = "/etc/start.d/program"
|
||||
}
|
||||
|
||||
* `/etc/start.d/program:`
|
||||
|
||||
|
||||
+160
-70
@@ -19,20 +19,25 @@ the most reliable way to monitor a service.
|
||||
|
||||
However, not all daemons support running in the foreground, or they may
|
||||
start logging to the foreground as well, these are forking daemons and
|
||||
are supported using the same syntax as forking `sysv` services, using
|
||||
the `pid:!/path/to/pidfile.pid` syntax. There is an alternative syntax
|
||||
that may be more intuitive, where Finit can also guess the PID file
|
||||
based on the daemon's command name:
|
||||
are supported using the same syntax as forking `sysv` services, by
|
||||
naming the file to watch with `pidfile`. There is an alternative that
|
||||
may be more intuitive, where Finit can also guess the PID file based on
|
||||
the daemon's command name:
|
||||
|
||||
service type:forking ntpd -- NTP daemon
|
||||
service ntpd {
|
||||
description = "NTP daemon"
|
||||
type = "forking"
|
||||
command = "ntpd"
|
||||
}
|
||||
|
||||
This example lets BusyBox `ntpd` daemonize itself. Finit uses the
|
||||
basename of the binary to guess the PID file to watch for the PID:
|
||||
`/var/run/ntpd.pid`. If Finit guesses wrong, you have to submit the
|
||||
full `pid:!/path/to/file.pid`.
|
||||
`/var/run/ntpd.pid`. If Finit guesses wrong, name the file yourself
|
||||
with `pidfile = "/path/to/file.pid"`.
|
||||
|
||||
With `pid:!/path`, the file belongs to the service: Finit reads it
|
||||
but does not create or remove it. The one exception is *stale*
|
||||
The file belongs to the service: Finit reads it but does not create or
|
||||
remove it. That is the default, and `pidfile-create = true` is what
|
||||
asks Finit to write the file instead. The one exception is *stale*
|
||||
cleanup — if the service dies without removing its own pidfile
|
||||
(SIGKILL, OOM, segfault), and the file still names the just-reaped
|
||||
PID, Finit removes it before the next retry. This prevents daemons
|
||||
@@ -44,56 +49,75 @@ from getting stuck in a crash-restart loop.
|
||||
In the case of `ospfd` (below), we omit the `-d` flag (daemonize) to
|
||||
prevent it from forking to the background:
|
||||
|
||||
service [2345] <pid/zebra> /sbin/ospfd -- OSPF daemon
|
||||
service ospfd {
|
||||
description = "OSPF daemon"
|
||||
runlevel = "2345"
|
||||
conditions = { "pid/zebra" }
|
||||
command = "/sbin/ospfd"
|
||||
}
|
||||
|
||||
`[2345]` denote the runlevels `ospfd` is allowed to run in, they are
|
||||
optional and default to level 2-5 if omitted.
|
||||
|
||||
`<...>` is the condition for starting `ospfd`. In this example Finit
|
||||
`runlevel` denotes the runlevels `ospfd` is allowed to run in, it is
|
||||
optional and defaults to level 2-4 if omitted.
|
||||
|
||||
`conditions` lists what must be asserted before starting `ospfd`. In this example Finit
|
||||
waits for another service, `zebra`, to have created its PID file in
|
||||
`/var/run/quagga/zebra.pid` before starting `ospfd`. Finit watches
|
||||
*all* files in `/var/run`, for each file named `*.pid`, or `*/pid`,
|
||||
Finit opens it and find the matching `NAME:ID` using the PID.
|
||||
|
||||
The condition can be prefixed with `!` and/or `~`:
|
||||
A condition may be prefixed with `~` to propagate a reload of the
|
||||
upstream service to this one, rather than merely pausing and resuming
|
||||
it:
|
||||
|
||||
- `<!pid/zebra>` -- `ospfd` does not support `SIGHUP` (noreload)
|
||||
- `<~pid/zebra>` -- propagate reload from `zebra` to `ospfd`
|
||||
- `<!~pid/zebra>` -- both: noreload and propagate reload
|
||||
conditions = { "~pid/zebra" }
|
||||
|
||||
For details, see the [Finit Conditions](../conditions.md) document.
|
||||
If `ospfd` cannot be reloaded with `SIGHUP` at all, that is a property
|
||||
of `ospfd` and not of the condition, so it is said directly:
|
||||
|
||||
reload-signal = "none"
|
||||
|
||||
The legacy format spells that second one as a `!` leading the condition
|
||||
list, which is not accepted here. For details, see the
|
||||
[Finit Conditions](../conditions.md) document.
|
||||
|
||||
Some services do not maintain a PID file and rather than patching each
|
||||
application Finit provides a workaround. A `pid` keyword can be set
|
||||
to have Finit automatically create (when starting) and later remove
|
||||
(when stopping) the PID file. The file is created in the `/var/run`
|
||||
directory using the `basename(1)` of the service. The default can be
|
||||
modified with an optional `pid:`-argument:
|
||||
application Finit provides a workaround. With `pidfile-create` Finit
|
||||
creates the file when starting and removes it when stopping. The path
|
||||
comes from `pidfile`, which takes three forms:
|
||||
|
||||
pid[:[/path/to/]filename[.pid]]
|
||||
pidfile = true # /var/run/<command basename>.pid
|
||||
pidfile = "bar" # a bare name, /var/run/bar.pid
|
||||
pidfile = "/run/bar.pid" # an explicit path
|
||||
|
||||
For example, by adding `pid:/run/bar.pid` to the service `/sbin/bar`,
|
||||
that PID file will, not only be created and removed automatically, but
|
||||
also be used by the Finit condition subsystem. So a service/run/task
|
||||
can depend on `<pid/bar>`, like this foo will not be started until bar
|
||||
has started:
|
||||
Such a file is also used by the Finit condition subsystem, so another
|
||||
service, run or task can depend on `pid/bar`. Here foo is not started
|
||||
until bar has:
|
||||
|
||||
service pid:/run/bar.pid bar -- Bar Service
|
||||
service <pid/bar> foo -- Foo Service
|
||||
service bar {
|
||||
description = "Bar Service"
|
||||
pidfile = "/run/bar.pid"
|
||||
pidfile-create = true
|
||||
command = "bar"
|
||||
}
|
||||
|
||||
service foo {
|
||||
description = "Foo Service"
|
||||
conditions = { "pid/bar" }
|
||||
command = "foo"
|
||||
}
|
||||
|
||||
Needless to say, it is better if `bar` creates its own PID file when it
|
||||
has completed starting up and is ready for service.
|
||||
|
||||
As an alternative "readiness" notification, Finit supports both systemd
|
||||
and s6 style notification. This can be enabled by using the `notify`
|
||||
option:
|
||||
and s6 style notification. This is enabled with the `notify` key:
|
||||
|
||||
* `notify:systemd` -- tells Finit the service uses the `sd_notify()`
|
||||
* `notify = "systemd"` -- tells Finit the service uses the `sd_notify()`
|
||||
API to signal PID 1 when it has completed its startup and is ready
|
||||
to service events. The [sd_notify()][] API expects `NOTIFY_SOCKET`
|
||||
to be set to the socket where the application can send `"READY=1\n"`
|
||||
when it is starting up or has processed a `SIGHUP`.
|
||||
* `notify:s6` -- puts Finit in s6 compatibility mode. Compared to the
|
||||
* `notify = "s6"` -- puts Finit in s6 compatibility mode. Compared to the
|
||||
systemd notification, [s6 expect][] compliant daemons to send `"\n"`
|
||||
and then close their socket. Finit takes care of "hard-wiring" the
|
||||
READY state as long as the application is running, events across any
|
||||
@@ -101,7 +125,11 @@ option:
|
||||
(must be >3) on then command line, Finit provides the following
|
||||
syntax (`%n` is replaced by Finit with then descriptor number):
|
||||
|
||||
service [S12345789] notify:s6 mdevd -O 4 -D %n
|
||||
service mdevd {
|
||||
runlevel = "S12345789"
|
||||
notify = "s6"
|
||||
command = "mdevd -O 4 -D %n"
|
||||
}
|
||||
|
||||
[sd_notify()]: https://www.freedesktop.org/software/systemd/man/sd_notify.html
|
||||
[s6 expect]: https://skarnet.org/software/s6/notifywhenup.html
|
||||
@@ -115,7 +143,13 @@ then service's ready condition which other services can depend on:
|
||||
|
||||
This can be used to synchronize the start of another run/task/service:
|
||||
|
||||
task [S] <service/mdevd/ready> @root:root mdevd-coldplug
|
||||
task mdevd-coldplug {
|
||||
runlevel = "S"
|
||||
conditions = { "service/mdevd/ready" }
|
||||
user = "root"
|
||||
group = "root"
|
||||
command = "mdevd-coldplug"
|
||||
}
|
||||
|
||||
Finit waits for `mdevd` to notify it, before starting `mdevd-coldplug`.
|
||||
Notice how both start in runlevel S, and the coldplug task only runs in
|
||||
@@ -131,20 +165,29 @@ Non-privileged Services
|
||||
-----------------------
|
||||
|
||||
Every `run`, `task`, or `service` can also list the privileges the
|
||||
`/path/to/cmd` should be executed with. Prefix the command with
|
||||
`@USR[:GRP[,SUPP,...]]`, where group and supplementary groups are
|
||||
optional, like this:
|
||||
command should be executed with, using `user`, `group` and
|
||||
`extra-groups`, all optional:
|
||||
|
||||
run [2345] @joe:users logger "Hello world"
|
||||
run hello {
|
||||
runlevel = "2345"
|
||||
user = "joe"
|
||||
group = "users"
|
||||
command = "logger \"Hello world\""
|
||||
}
|
||||
|
||||
Finit reads the user's supplementary group membership from `/etc/group`
|
||||
automatically. Any groups the user belongs to will be inherited by
|
||||
the service.
|
||||
|
||||
To specify additional supplementary groups beyond those in `/etc/group`,
|
||||
append them after the primary group, separated by commas:
|
||||
To specify additional supplementary groups beyond those in
|
||||
`/etc/group`, list them in `extra-groups`:
|
||||
|
||||
service @caddy:caddy,ssl-cert /usr/bin/caddy run
|
||||
service caddy {
|
||||
user = "caddy"
|
||||
group = "caddy"
|
||||
extra-groups = { "ssl-cert" }
|
||||
command = "/usr/bin/caddy run"
|
||||
}
|
||||
|
||||
This runs the `caddy` service as user `caddy`, with primary group
|
||||
`caddy`, inheriting any groups `caddy` is a member of in `/etc/group`,
|
||||
@@ -152,14 +195,22 @@ plus the additional `ssl-cert` group. This is useful when a service
|
||||
needs access to resources owned by groups not listed in `/etc/group`.
|
||||
|
||||
For multiple instances of the same command, e.g. a DHCP client or
|
||||
multiple web servers, add `:ID` somewhere between the `run`, `task`,
|
||||
`service` keyword and the command, like this:
|
||||
multiple web servers, add `:ID` to the block title, like this:
|
||||
|
||||
service :80 [2345] httpd -f -h /http -p 80 -- Web server
|
||||
service :8080[2345] httpd -f -h /http -p 8080 -- Old web server
|
||||
service httpd:80 {
|
||||
description = "Web server"
|
||||
runlevel = "2345"
|
||||
command = "httpd -f -h /http -p 80"
|
||||
}
|
||||
|
||||
Without the `:ID` to the service the latter will overwrite the former
|
||||
and only the old web server would be started and supervised.
|
||||
service httpd:8080 {
|
||||
description = "Old web server"
|
||||
runlevel = "2345"
|
||||
command = "httpd -f -h /http -p 8080"
|
||||
}
|
||||
|
||||
Without the `:ID` the latter will overwrite the former and only the old
|
||||
web server would be started and supervised.
|
||||
|
||||
|
||||
Conditional Loading
|
||||
@@ -169,35 +220,58 @@ 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.
|
||||
Starting with the leading `-` on `command`.
|
||||
|
||||
service nowarn name:udevd pid:udevd /lib/systemd/systemd-udevd
|
||||
service nowarn name:udevd pid:udevd udevd
|
||||
service udevd {
|
||||
pidfile = "udevd"
|
||||
command = "-/lib/systemd/systemd-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,
|
||||
service udevd {
|
||||
pidfile = "udevd"
|
||||
command = "-udevd"
|
||||
}
|
||||
|
||||
When loading the .conf file Finit looks for
|
||||
`/lib/systemd/systemd-udevd`, and if that is not found it logs a
|
||||
warning. The leading `-` says a missing binary is expected here, so
|
||||
the stanza is skipped quietly and the second block can be evaluated,
|
||||
which also provides a service named `udevd`.
|
||||
|
||||
run nowarn if:udevd <pid/udevd> :1 udevadm settle -t 0
|
||||
run udevadm:1 {
|
||||
runlevel = "S"
|
||||
if = "udevd"
|
||||
conditions = { "pid/udevd" }
|
||||
command = "-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
|
||||
run mdev {
|
||||
description = "Populating device tree"
|
||||
runlevel = "S"
|
||||
conflicts = { "udevd" }
|
||||
command = "-mdev -s"
|
||||
}
|
||||
|
||||
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:
|
||||
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
|
||||
run mdev {
|
||||
description = "Populating device tree"
|
||||
runlevel = "S"
|
||||
if = "!udevd"
|
||||
command = "-mdev -s"
|
||||
}
|
||||
|
||||
The reason for using `conflict` in this example is that a conflict can be
|
||||
resolved. Stanzas marked with `conflict:foo` are rechecked at runtime.
|
||||
resolved. Stanzas naming a conflict are rechecked at runtime.
|
||||
|
||||
|
||||
Conditional Execution
|
||||
@@ -212,21 +286,37 @@ runlevel. E.g., a `task [123]` is qualified to run only in runlevel 1,
|
||||
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
|
||||
run startup {
|
||||
runlevel = "S"
|
||||
conditions = { "pid/sysrepo" }
|
||||
command = "confd -b --load startup-config"
|
||||
}
|
||||
|
||||
run failure {
|
||||
runlevel = "S"
|
||||
if = "<usr/fail-startup>"
|
||||
conditions = { "pid/sysrepo" }
|
||||
command = "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 the critical difference between the `<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.
|
||||
Notice the critical difference between the `conditions` list and `if`.
|
||||
The former is a condition for starting; the latter is a condition to
|
||||
check whether a run/task/service is qualified to even be considered.
|
||||
`if` has a negation of its own, `!`, which is unrelated to anything in
|
||||
the `conditions` list.
|
||||
|
||||
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 failure {
|
||||
runlevel = "S"
|
||||
if = "<!usr/startup-ok>"
|
||||
conditions = { "pid/sysrepo" }
|
||||
command = "confd ..."
|
||||
}
|
||||
|
||||
+10
-4
@@ -24,9 +24,10 @@ calls `init-script restart` on `initctl reload`. Similar to how
|
||||
`service` stanzas work.
|
||||
|
||||
Forking services started with `sysv` scripts can be monitored by Finit
|
||||
by declaring the PID file to look for: `pid:!/path/to/pidfile.pid`.
|
||||
Notice the leading `!`, it signifies Finit should not try to create the
|
||||
file, but rather watch that file for the resulting forked-off PID. This
|
||||
by declaring the PID file to look for: `pidfile = "/path/to/file.pid"`.
|
||||
Finit does not create that file, it watches it for the resulting
|
||||
forked-off PID, which is the default; `pidfile-create = true` is what
|
||||
asks Finit to write it instead. This
|
||||
syntax also works for forking daemons that do not have a command line
|
||||
option to run it in the foreground, more on this below in `service`.
|
||||
|
||||
@@ -64,7 +65,12 @@ Start/Stop Scripts
|
||||
For syntax details, see [SysV Init Scripts](#sysv-init-scripts), above.
|
||||
Here follows an example taken from a Debian installation:
|
||||
|
||||
sysv [2345] <pid/syslogd> /etc/init.d/openbsd-inetd -- OpenBSD inet daemon
|
||||
sysv inetd {
|
||||
description = "OpenBSD inet daemon"
|
||||
runlevel = "2345"
|
||||
conditions = { "pid/syslogd" }
|
||||
command = "/etc/init.d/openbsd-inetd"
|
||||
}
|
||||
|
||||
The init script header could be parsed to extract `Default-Start:` and
|
||||
other parameters for the `sysv` command to Finit. There is currently no
|
||||
|
||||
+24
-12
@@ -40,27 +40,35 @@ One-shot like 'run', but starts in parallel with the next command.
|
||||
Both `run` and `task` commands are run in a shell, so basic pipes and
|
||||
redirects can be used:
|
||||
|
||||
task [s] echo "foo" | cat >/tmp/bar
|
||||
task bar {
|
||||
runlevel = "S"
|
||||
command = "echo \"foo\" | cat >/tmp/bar"
|
||||
}
|
||||
|
||||
Please note, `;`, `&&`, `||`, and similar are *not supported*. Any
|
||||
non-trivial constructs are better placed in a separate shell script.
|
||||
|
||||
|
||||
remain:yes
|
||||
----------
|
||||
remain-after-exit
|
||||
-----------------
|
||||
|
||||
By default, a `run` or `task` will re-run each time its runlevel is
|
||||
entered, and its `post:` script does not run on completion.
|
||||
entered, and its `exec-stop-post` script does not run on completion.
|
||||
|
||||
With `remain:yes`, the task runs once and does not re-run on runlevel
|
||||
re-entry:
|
||||
With `remain-after-exit`, the task runs once and does not re-run on
|
||||
runlevel re-entry:
|
||||
|
||||
task [2345] remain:yes /usr/sbin/setup-firewall -- Firewall setup
|
||||
task firewall {
|
||||
description = "Firewall setup"
|
||||
runlevel = "2345"
|
||||
remain-after-exit = true
|
||||
command = "/usr/sbin/setup-firewall"
|
||||
}
|
||||
|
||||
This has the following effects:
|
||||
|
||||
* The task does not re-run on runlevel re-entry
|
||||
* The `post:` script runs when:
|
||||
* The `exec-stop-post` script runs when:
|
||||
- The task is explicitly stopped (`initctl stop NAME`)
|
||||
- The task leaves its valid runlevels (e.g., runlevel change)
|
||||
|
||||
@@ -72,12 +80,16 @@ This is useful for tasks that set up persistent state where:
|
||||
**Example:** Setting up firewall rules with cleanup on shutdown:
|
||||
|
||||
```
|
||||
task [2345] remain:yes \
|
||||
post:/usr/sbin/teardown-firewall \
|
||||
/usr/sbin/setup-firewall -- Firewall setup
|
||||
task firewall {
|
||||
description = "Firewall setup"
|
||||
runlevel = "2345"
|
||||
remain-after-exit = true
|
||||
exec-stop-post = "/usr/sbin/teardown-firewall"
|
||||
command = "/usr/sbin/setup-firewall"
|
||||
}
|
||||
```
|
||||
|
||||
The firewall rules are created once. The `post:` script runs when
|
||||
The firewall rules are created once. The `exec-stop-post` script runs when
|
||||
entering runlevel 0 (halt) or 6 (reboot), or on explicit stop.
|
||||
|
||||
> [!NOTE]
|
||||
|
||||
@@ -5,15 +5,19 @@ Finit comes with rudimentary support for templating, similar to that of
|
||||
systemd. Best illustrated with an example:
|
||||
|
||||
$ initctl show avahi-autoipd@
|
||||
service :%i avahi-autoipd --syslog %i -- ZeroConf for %i
|
||||
service avahi-autoipd:%i {
|
||||
description = "ZeroConf for %i"
|
||||
command = "avahi-autoipd --syslog %i"
|
||||
}
|
||||
|
||||
To enable ZeroConf for, e.g., `eth0`, use
|
||||
|
||||
$ initctl enable avahi-autoipd@eth0.conf
|
||||
|
||||
The enabled symlink will be set up to `avahi-autoipd@.conf` and every
|
||||
instance of `%i` will in the instantiated directive be replaced with
|
||||
`eth0`. Inspect the resulting instantiated template with `initctl show
|
||||
instance of `%i` will be replaced with `eth0` before the file is
|
||||
parsed, so it works in the block title, in any value, and in the
|
||||
command line alike. Inspect the resulting instantiated template with `initctl show
|
||||
avahi-autoipd:eth0` and check the status of a running instance with:
|
||||
|
||||
```
|
||||
|
||||
+44
-8
@@ -19,7 +19,13 @@ The default baud rate is 0, i.e., keep kernel default.
|
||||
|
||||
**Example:**
|
||||
|
||||
tty [12345] /dev/ttyAMA0 115200 noclear vt220
|
||||
tty ttyAMA0 {
|
||||
runlevel = "12345"
|
||||
device = "/dev/ttyAMA0"
|
||||
baud = 115200
|
||||
term = "vt220"
|
||||
noclear = true
|
||||
}
|
||||
|
||||
The second `tty` syntax variant is for using an external getty, like
|
||||
agetty or the BusyBox getty.
|
||||
@@ -38,8 +44,16 @@ the user to press enter before starting getty.
|
||||
|
||||
**Example:**
|
||||
|
||||
tty [12345] /sbin/getty -L 115200 /dev/ttyAMA0 vt100
|
||||
tty [12345] /sbin/agetty -L ttyAMA0 115200 vt100 nowait
|
||||
tty getty {
|
||||
runlevel = "12345"
|
||||
command = "/sbin/getty -L 115200 /dev/ttyAMA0 vt100"
|
||||
}
|
||||
|
||||
tty agetty {
|
||||
runlevel = "12345"
|
||||
command = "/sbin/agetty -L ttyAMA0 115200 vt100"
|
||||
nowait = true
|
||||
}
|
||||
|
||||
The `noclear` option disables clearing the TTY after each session.
|
||||
Clearing the TTY when a user logs out is usually preferable.
|
||||
@@ -69,13 +83,21 @@ can be omitted to keep the kernel default.
|
||||
|
||||
**Example:**
|
||||
|
||||
tty [12345] @console noclear vt220
|
||||
tty console {
|
||||
runlevel = "12345"
|
||||
device = "@console"
|
||||
term = "vt220"
|
||||
noclear = true
|
||||
}
|
||||
|
||||
On really bare bones systems, or for board bringup, Finit can give you a
|
||||
shell prompt as soon as bootstrap is done, without opening any device
|
||||
node:
|
||||
|
||||
tty [12345789] notty
|
||||
tty board {
|
||||
runlevel = "12345789"
|
||||
notty = true
|
||||
}
|
||||
|
||||
This should of course not be enabled on production systems. Because it
|
||||
may give a user root access without having to log in. However, for
|
||||
@@ -83,7 +105,10 @@ board bringup and system debugging it can come in handy.
|
||||
|
||||
One can also use the `service` stanza to start a stand-alone shell:
|
||||
|
||||
service [12345] /bin/sh -l
|
||||
service shell {
|
||||
runlevel = "12345"
|
||||
command = "/bin/sh -l"
|
||||
}
|
||||
|
||||
Controlling TTY for Services
|
||||
----------------------------
|
||||
@@ -109,5 +134,16 @@ TTY device.
|
||||
|
||||
**Example:**
|
||||
|
||||
service [2345] tty:/dev/ttyS0 /usr/sbin/foo -- Foo on serial console
|
||||
task [S] tty:@console my-setup-script -- Board bringup on console
|
||||
service foo {
|
||||
description = "Foo on serial console"
|
||||
runlevel = "2345"
|
||||
tty = "/dev/ttyS0"
|
||||
command = "/usr/sbin/foo"
|
||||
}
|
||||
|
||||
task setup {
|
||||
description = "Board bringup on console"
|
||||
runlevel = "S"
|
||||
tty = "@console"
|
||||
command = "my-setup-script"
|
||||
}
|
||||
+31
-8
@@ -98,29 +98,52 @@ Some components are optional: runlevel(s), condition(s) and description,
|
||||
making it easy to create simple start scripts and still possible for more
|
||||
advanced uses as well:
|
||||
|
||||
service /usr/sbin/sshd -D
|
||||
service sshd {
|
||||
command = "/usr/sbin/sshd -D"
|
||||
}
|
||||
|
||||
Dependencies are handled using [conditions](conditions.md). One of
|
||||
the most common conditions is to wait for basic networking to become
|
||||
available:
|
||||
|
||||
service <net/route/default> nginx -- High performance HTTP server
|
||||
service nginx {
|
||||
description = "High performance HTTP server"
|
||||
conditions = { "net/route/default" }
|
||||
command = "nginx"
|
||||
}
|
||||
|
||||
Here is another example where we instruct Finit to not start BusyBox
|
||||
`ntpd` until `syslogd` has started properly. Finit waits for `syslogd`
|
||||
to create its PID file, by default `/var/run/syslogd.pid`.
|
||||
|
||||
service [2345] log <!pid/syslogd> ntpd -n -N -p pool.ntp.org
|
||||
service [S12345] syslogd -n -- Syslog daemon
|
||||
service ntpd {
|
||||
runlevel = "2345"
|
||||
conditions = { "pid/syslogd" }
|
||||
reload-signal = "none"
|
||||
log { }
|
||||
command = "ntpd -n -N -p pool.ntp.org"
|
||||
}
|
||||
|
||||
Notice the `log` keyword, BusyBox `ntpd` uses `stderr` for logging when
|
||||
run in the foreground. With `log` Finit redirects `stdout` + `stderr`
|
||||
to the system log daemon using the command line `logger(1)` tool.
|
||||
service syslogd {
|
||||
description = "Syslog daemon"
|
||||
runlevel = "S12345"
|
||||
command = "syslogd -n"
|
||||
}
|
||||
|
||||
Notice the empty `log` block, BusyBox `ntpd` uses `stderr` for logging
|
||||
when run in the foreground. With it Finit redirects `stdout` +
|
||||
`stderr` to the system log daemon using the command line `logger(1)`
|
||||
tool.
|
||||
|
||||
A service, or task, can have multiple dependencies listed. Here we wait
|
||||
for *both* `syslogd` to have started and basic networking to be up:
|
||||
|
||||
service [2345] log <pid/syslogd,net/route/default> ntpd -n -N -p pool.ntp.org
|
||||
service ntpd {
|
||||
runlevel = "2345"
|
||||
conditions = { "pid/syslogd", "net/route/default" }
|
||||
log { }
|
||||
command = "ntpd -n -N -p pool.ntp.org"
|
||||
}
|
||||
|
||||
If either condition fails, e.g. loss of networking, `ntpd` is stopped
|
||||
and as soon as it comes back up again `ntpd` is restarted automatically.
|
||||
|
||||
+9
-5
@@ -212,13 +212,17 @@ A fourth group also exists, the `root` group. It is also _reserved_ and
|
||||
primarily intended for RT tasks. If you have RT tasks they need to be
|
||||
declared as such in their service stanza like this:
|
||||
|
||||
service [...] <...> cgroup.root /path/to/foo args -- description
|
||||
service foo {
|
||||
cgroup root {}
|
||||
command = "/path/to/foo args"
|
||||
}
|
||||
|
||||
or
|
||||
Every block names the group it joins, so a second RT task says so too:
|
||||
|
||||
cgroup.root
|
||||
service [...] <...> /path/to/foo args -- description
|
||||
service [...] <...> /path/to/bar args -- description
|
||||
service bar {
|
||||
cgroup root {}
|
||||
command = "/path/to/bar args"
|
||||
}
|
||||
|
||||
See the [Cgroups](config/cgroups.md) section for more information, e.g.,
|
||||
how to configure per-group limits.
|
||||
|
||||
+30
-9
@@ -27,13 +27,22 @@ Finit can *not* start and monitor a daemon that:
|
||||
|
||||
### Forks to bg w/ PID file
|
||||
|
||||
There are two syntax variants, type 1 and type 2. The former is the
|
||||
traditional one used also for `sysv` start/stop scripts, and the latter
|
||||
is inspired by systemd, with a twist -- it lets Finit guess the pifdile
|
||||
to look for based on the standard path and the basename of the command.
|
||||
There are two variants. The former names the pidfile to watch, as for
|
||||
`sysv` start/stop scripts, and the latter is inspired by systemd, with a
|
||||
twist -- it lets Finit guess the pidfile based on the standard path and
|
||||
the basename of the command.
|
||||
|
||||
service pid:!/run/serv.pid serv -- Forking service, type 1
|
||||
service type:forking serv -- Forking service, type 2
|
||||
service serv {
|
||||
description = "Forking service, type 1"
|
||||
pidfile = "/run/serv.pid"
|
||||
command = "serv"
|
||||
}
|
||||
|
||||
service serv {
|
||||
description = "Forking service, type 2"
|
||||
type = "forking"
|
||||
command = "serv"
|
||||
}
|
||||
|
||||
In this example the resulting files to watch for are `/run/serv.pid` and
|
||||
`/var/run/serv.pid`, respectively. On most modern Linux systems this is
|
||||
@@ -41,17 +50,29 @@ the same directory (`/var/run` is a symlink to `../run`).
|
||||
|
||||
### Runs in fg w/ PID file
|
||||
|
||||
service serv -n -p -- Foreground service w/ PID file
|
||||
service serv {
|
||||
description = "Foreground service w/ PID file"
|
||||
command = "serv -n -p"
|
||||
}
|
||||
|
||||
### Runs in fg 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
|
||||
service serv {
|
||||
description = "Foreground service w/o PID file"
|
||||
pidfile = "/run/serv.pid"
|
||||
pidfile-create = true
|
||||
command = "serv -n"
|
||||
}
|
||||
|
||||
### Runs in fg w/ custom PID file
|
||||
|
||||
service pid:/run/servy.pid serv -n -p -P /run/servy.pid -- Foreground service w/ custom PID file
|
||||
service serv {
|
||||
description = "Foreground service w/ custom PID file"
|
||||
pidfile = "/run/servy.pid"
|
||||
command = "serv -n -p -P /run/servy.pid"
|
||||
}
|
||||
|
||||
[1]: config/service-sync.md
|
||||
|
||||
Reference in New Issue
Block a user