# 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