runsv(8)
π runsv(8) β like, the whole manual, but make it make sense
okay bestie, gather round, because this is runsv(8) from the System Manager's Manual and it's genuinely one of the most iconic little supervisors in the Unix cinematic universe. it starts your service, it watches your service, and if you're fancy it also runs your log service. main character energy fr fr. π
β¨ NAME β¨
runsv β starts and monitors a service and optionally an appendant log service π¦
πΈ SYNOPSIS πΈ
runsv service
π DESCRIPTION π
so first things first: service must be a directory. that's the vibe check, no exceptions. π
runsv switches into the directory service and starts ./run. that's the whole ritual. then:
- if
./runexits and./finishexists,runsvstarts./finish. - if
./finishdoesn't exist, or./finishexits,runsvrestarts./run.
the cycle never ends bestie, it's a loop, it's giving immortal. π₯
and lowkey important: if ./run or ./finish exit immediately, runsv waits a second before starting ./finish or restarting ./run. one whole second. it's pacing itself, as it should. β
now the part where ./finish gets two arguments, and yes both matter:
- the first one is
./run's exit code β or-1if./rundidn't exit normally. π - the second one is the least significant byte of the exit status as determined by
waitpid(2). for instance it's0if./runexited normally, and the signal number if./runwas terminated by a signal. π
and if runsv cannot start ./run for some reason? the exit code is 111 and the status is 0. write that down. π
okay so if the file service/down exists, runsv does not start ./run immediately. it's on pause, it's in its quiet era. the control interface (see below, keep scrolling bestie) can be used to start the service and to give other commands to runsv.
now the log service part, and this is where it gets highkey gorgeous: if the directory service/log exists, runsv creates a pipe, redirects service/run's and service/finish's standard output to the pipe, switches to the directory service/log and starts ./run. and the standard input of service/log/run is redirected to read from the pipe. it's a whole relay race and everyone ate. π
runsv also keeps receipts. it maintains status information:
- in a binary format (compatible to the daemontools'
superviseprogram) inservice/supervise/statusandservice/log/supervise/status - and in a human-readable format in
service/supervise/stat,service/log/supervise/stat,service/supervise/pid,service/log/supervise/pid
yes that's four human-readable files and two binary ones. every single one of them listed. π«Ά
π CONTROL π
the named pipes service/supervise/control, and (optionally) service/log/supervise/control are provided to give commands to runsv. you can use sv(8) to control the service or just write one of the following characters to the named pipe. it's that simple, no cap:
uβ Up. if the service is not running, start it. if the service stops, restart it. β¬οΈdβ Down. if the service is running, send it aTERMsignal, and then aCONTsignal. if./runexits, start./finishif it exists. after it stops, do not restart service. β¬οΈoβ Once. if the service is not running, start it. do not restart it if it stops. 1οΈβ£pβ Pause. if the service is running, send it aSTOPsignal. βΈοΈcβ Continue. if the service is running, send it aCONTsignal. βΆοΈhβ Hangup. if the service is running, send it aHUPsignal. πaβ Alarm. if the service is running, send it aALRMsignal. β°iβ Interrupt. if the service is running, send it aINTsignal. πqβ Quit. if the service is running, send it aQUITsignal. πͺ1β User-defined 1. if the service is running, send it aUSR1signal. π₯2β User-defined 2. if the service is running, send it aUSR2signal. π₯tβ Terminate. if the service is running, send it aTERMsignal. βοΈkβ Kill. if the service is running, send it aKILLsignal. πxβ Exit. if the service is running, send it aTERMsignal, and then aCONTsignal. do not restart the service. if the service is down, and no log service exists,runsvexits. if the service is down and a log service exists,runsvcloses the standard input of the log service, and waits for it to terminate. if the log service is down,runsvexits. this command is ignored if it is given toservice/log/supervise/control. πͺβ¨
Example: to send a TERM signal to the socklog-unix service, either do
# sv term /service/socklog-unix
or
# printf t >/service/socklog-unix/supervise/control
both work, pick your fighter. π₯
heads up bestie:printf(1)usually blocks if norunsvprocess is running in the service directory. so if it just hangs there staring at you, that's why. π«
π§ CUSTOMIZE CONTROL π§
okay so this is the glow-up feature and it's so underrated. for each control character c other than o, d, and x sent to the control pipe, runsv first checks if service/control/c exists and is executable. if so, it starts service/control/c and waits for it to terminate, before interpreting the command. and if the program exits with return code 0, runsv refrains from sending the service the corresponding signal. β¨
the command o is always considered as command u. π (yes, always. even though o was excluded above. that's the rule.)
on command d first service/control/t is checked, and then service/control/d. on command x first service/control/t is checked, and then service/control/x.
specifically, and here's the play-by-play π :
if the service is running or paused, control characters d and x are handled as follows:
runsvchecks whetherservice/control/texists and is executable and runs it if yes.- if
service/control/texits nonzero, or is not executable or doesn't exist,runsvsends the service aTERMsignal. runsvsends the service aCONTsignal, disregardingservice/control/ceven if it exists and is executable.runsvchecks whetherservice/control/d(orcontrol/x) exists and is executable and runs it if yes. its exit status is ignored.
that step 4 exit status? ignored. we simply do not perceive it. π«Ά
the control program runs with the process id of service as its first argument, or the empty string if there's no pid. π
and the plot twist nobody wanted: the control of the optional log service cannot be customized. periodt. π
β SIGNALS β
if runsv receives a TERM signal, it acts as if the character x was written to the control pipe. so a TERM is basically a text message saying "x" and it understands immediately. β¨
πΈ EXIT CODES πΈ
runsvexits111on an error on startup or if anotherrunsvis running in service. π¨runsvexits0if it was told to exit. ποΈ
π₯ SEE ALSO π₯
sv(8), chpst(8), svlogd(8), runit(8), runit-init(8), runsvdir(8), runsvchdir(8), utmpset(8)
π AUTHOR π
Gerrit Pape <pape@smarden.org>
and that's the whole page, bestie π β it lives in the System Manager's Manual (that's the manual name, now you know β¨) and the page itself is runsv(8), both at the top of this little screed and stamped at the very bottom where the date/version footer normally sits. mwah π π¦ π β
π¦ where this page comes from
- alpine 3.24: runit-doc 2.3.1-r0 Β· BSD
- nixpkgs unstable: runit 2.3.1
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms