1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
# Example: long-running daemon with restart-on-failure.
#
# This is the bread-and-butter pattern: a daemon that should run
# forever, restart if it crashes, and run as an unprivileged user.
[service]
type = "daemon"
description = "Example HTTP server (long-running daemon)"
[exec]
start = "/usr/sbin/example-httpd"
# Run as the 'webuser' account, in /var/lib/example as the cwd.
user = "webuser"
working_directory = "/var/lib/example"
# Pass environment to the child. Each entry is "KEY=value".
environment = ["LANG=C", "EXAMPLE_LOG_LEVEL=info"]
[restart]
# Restart automatically when the process exits with non-zero status.
# Options: "always" (restart on any exit), "failure" (default; only on
# non-zero exit), "never" (don't restart).
on = "failure"
# Wait 5 seconds between restart attempts (back-off would be a future feature).
delay = 5
# Give up after 5 failed restart attempts in a row. The service then
# transitions to STATE_MAINTENANCE and zygctl reports "failed". Set to
# -1 for unlimited.
max_retries = 5
# Example: oneshot setup task.
#
# Runs once at boot, expected to exit quickly with status 0.
# zyginit considers a successful oneshot "online" for dependency purposes.
[service]
type = "oneshot"
description = "Mount additional filesystems (oneshot setup)"
[exec]
# A path beginning with "./" resolves relative to this service's directory,
# so the helper script lives at examples/oneshot-setup/start.sh.
start = "./start.sh"
[dependencies]
# Run after root-fs is online. zyginit topologically sorts services into
# tiers based on these dependencies.
requires = ["root-fs"]
#!/bin/sh
# Mount everything in /etc/vfstab that's not already mounted.
exec mountall
# Example: task with a runtime condition.
#
# A 'task' may run for any duration but is expected to eventually
# exit cleanly. Unlike 'oneshot', tasks aren't expected to exit
# immediately. Unlike 'daemon', tasks never restart.
#
# The [condition] block declares pre-flight checks. If any condition
# fails at startup, the service enters STATE_SKIPPED without forking —
# no failure, no restart loop. Useful for platform probes.
[service]
type = "task"
description = "ACPI hotplug daemon (skipped on platforms without ACPI)"
[exec]
start = "/usr/sbin/example-acpihpd"
[condition]
# This file must exist for the service to start. If missing, the
# service is SKIPPED with reason "missing /dev/acpi".
exists_file = "/dev/acpi"
# Alternative form: at least one of these paths must exist (OR semantics
# across the list, AND with other condition keys).
# exists_file_any = ["/dev/acpi", "/dev/acpihp"]
# A command that must exit 0 (5-second timeout). Useful for richer
# probes than file existence — e.g., checking a hardware flag.
# command = "/usr/sbin/example-acpihpd --probe"
# Example: daemon with a companion stop script.
#
# Some services need an explicit shutdown sequence rather than just
# being signaled. The [exec].stop field references a script in the
# same directory. zyginit runs it with a stop timeout (default 60s)
# before falling back to SIGKILL.
[service]
type = "daemon"
description = "Database daemon with graceful shutdown"
[exec]
start = "./start.sh"
stop = "./stop.sh"
user = "dbuser"
[stop]
# How long zyginit waits for stop.sh to finish before escalating
# to SIGKILL. Default is 60 seconds.
timeout = 30
#!/bin/sh
# Start the database, foregrounded so zyginit can supervise it directly.
exec /usr/sbin/example-dbd --foreground --config /etc/example-db.conf
#!/bin/sh
# Graceful shutdown: tell the daemon to flush and exit cleanly.
exec example-dbctl --shutdown --wait
|