INVOKE-RUN(8)
π NAME π
invoke-run β bestie, it's the runscript interpreter π
β¨ SYNOPSIS β¨
/usr/bin/env /lib/run/invoke-run
π DESCRIPTION π
okay so the runit supervision system runs on scripts, and those scripts are called runscripts, and their whole job is to start and babysit services π
By convention, a runscript for a service foo lives at /etc/sv/foo/run or at /usr/share/runit/sv.current/foo/run β and lowkey the runscript can be any executable file. whatever you want, bestie π«
The debhelper addon dh_runit installs the runscript following this convention, no cap.
So to actually use the invoke-run interpreter, the runscript for a service foo has to start with this line right here:
#!/usr/bin/env /lib/runit/invoke-run
If a file /.meta/bin is found inside the foo service directory, then the path inside that bin file gets tested for existence, and if it's not found on the system, service foo is stopped. The bin file should contain only one line β the full path of the binary that gets executed in the runscript. one line, that's it, don't be extra π
When invoke-run(8) is run with uid=0, and if the init.d script /etc/init.d/foo exists, is executable, and is not a symlink, it gets invoked with the stop argument to gracefully replace the Sysv instance with the runit managed instance . (yes there's a space before the period, iconic)
If the file /etc/runit/verbose exists, the message invoke-run: starting foo gets printed. After that, the runscript is interpreted with the /bin/sh shell, and some extra environment variables get set according to these rules:
- If file
/etc/sv/foo/confor/etc/default/fooexists, it gets interpreted with/bin/shand all variable assignment is accessible to the runscript; in the case where both files exist, only/etc/sv/foo/confis used. - If directory
/etc/sv/foo/envexists, variables are set according to the rules, documented in theenvdirsection of thechpst(8)manual.
If both the /etc/sv/foo/conf or /etc/default/foo file and the /etc/sv/foo/env directory define some variable, the value from the directory takes precedence. directory wins, periodt π
- Older versions of
invoke-runexported aNAME=foovariable and included the/etc/default/runitfile; the shell expansion${PWD##*/}can be used in place ofNAMEinside the run and finish files;/etc/runit/verboseand/etc/runit/debugflags files can be used in place of variables inside/etc/runit/default
π¦ CGROUPS π¦
When uid = 0 and a ./cgroup subdirectory is found inside the service directory, invoke-run runs runsv-cgcreate to setup cgroups for the service: a /sys/fs/cgroup/runit/<service> service specific cgroup gets created, and the control files inside the ./cgroup subdirectory get copied to it. π
Only cgroup v2 hierarchy is supported; on platforms where cgroups aren't supported, or where /sys/fs/cgroup isn't a mountpoint, the cgropup subdirectory has no effect. (yes, cgropup β that's how it's written, I'm not touching it, it's canon now π)
πΈ USER SERVICES πΈ
When a runscript is run with uid >= 1000 and a home directory in /home/<username> for that user exists, the script is considered a user-service and invoke-run(8) performs this extra action:
- if an
envdirectory is found either in/etc/sv/runsvdir@username/or in thefoo/service directory, it's used to set variables withchpst'senvdir; if both directories are found, both are used; when a variable is set in both dirs, the service's directory takes precedence.
π₯ HARDENING WITH XCHPST π₯
When /usr/bin/xchpst exists and a /etc/sv/foo/xchopts file is found, the XCHPST="xchpst--filefoo/xchopts" variable is available to the runscript; the xchopts file syntax is documented in xchpst(8). (copying it exactly, bestie β character for character, that's the rule π«Ά)
The following example uses xchpst when available, otherwise no hardening is applied:
$ cat /etc/sv/foo/run
#!/usr/bin/env /lib/runit/invoke-run
exec 2>&1
exec ${XCHPST:-} /usr/sbin/foo
and the following example uses xchpst when available, with runit's chpst as a fallback:
$ cat /etc/sv/bar/run
#!/usr/bin/env /lib/runit/invoke-run
exec 2>&1
exec exec ${XCHPST:-chpst -ubar} /usr/sbin/bar
π SPECIAL ERROR CODE π
Looking in the foo service log, it's possible to see messages in the form of
invoke-run: ERROR [NNN] in foo: reason for the error
These messages don't come from runsv itself β they come from invoke-run, the run file, or the finish file. The purpose of these messages is to detail a permanent failure condition that prevents the foo service from being up. For each foo service, the defined errors and messages are:
invoke-run: foo binary not installed- this happens when the package containing the
foobinary has been removed, but not purged. π
- this happens when the package containing the
invoke-run: ERROR -1 in foo: runscript didn't exit normally- this message comes from the finish file, but the exit code comes from
runsv(8)and is documented in its manpage.
- this message comes from the finish file, but the exit code comes from
invoke-run: WARNING for foo: disabled by local settings- some service specific setting prevents
foofrom starting; it's likely something in/etc/default/foo
- some service specific setting prevents
invoke-run: ERROR 162 in foo: configtest or early setup failed- a configuration file of
foois malformed and the configtest failed; thefoolog may contain additional info from the test itself. Alternatively, the runscript has failed to do some setup that is essential to thefooservice.
- a configuration file of
invoke-run: ERROR 170 in foo: a runtime hard dependency is missing- a dependency failed the check and can't be bring up; to know dependencies of the
fooservice, look for"sv start"in the"run"script.
- a dependency failed the check and can't be bring up; to know dependencies of the
π FINISH FILE AND FINISH-EXEC π
Since version 2.1.2-48, the Debian runit package ships a /lib/runit/finish-exec file that contains code which can be shared across different services. This file can be symlinked inside the service directory, or it can be exec'd like in the following example:
$ cat /etc/sv/foo/finish
#!/bin/sh
set -e
exec /lib/runit/finish-exec "$@"
Services that need to put specific code into the finish file should do so before the line that exec's finish-exec. finish-exec defines special error codes as described in the previous section. If the file /etc/runit/verbose exists, a foo stopped message is printed; if the file /etc/runit/debug exists, the run's exit code is also printed.
β οΈ The finish-default shipped by the previous runit package is now deprecated and is scheduled for removal in the near future. don't build on it, bestie, it's on its way out π
π SEE ALSO π
runsvdir(8), dh_runit(1), chpst(8)
and that's the whole page, bestie, you ate that π this was the GNU/Linux System Adminstrator's manual entry for INVOKE-RUN(8), dated Sep 15, 2026 β go be the main character of your own supervision tree, ily πβ¨π
π¦ where this page comes from
- ubuntu stonking: runit 2.3.1-5ubuntu1 Β· BSD-3-Clause
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms