Runit exits with error if process tells itself to go down

1.3k views Asked by At

I'm seeing some unexpected behavior with runit and not sure how to get it to do what I want without throwing an error during termination. I have a process that sometimes knows it should stop itself and not let itself be restarted (thus should call sv d on itself). This works if I never change the user but produces errors if I switch to a non-root user when running.

I'll use the same finish script for both examples:

#!/bin/bash -e
echo "downtest finished with exit code $1 and exit status $2"

The run script that works as expected (prints downtest finished with exit code 0 and exit status 0 to syslog):

#!/bin/bash -e
exec 2>&1
echo "running downtest"
sv d downtest
exit 0

The run script that doesn't work as expected (prints downtest finished with exit code -1 and exit status 15 to syslog):

#!/bin/bash -e
exec 2>&1
echo "running downtest"
chpst -u ubuntu sudo sv d downtest
exit 0

I get the same result if I use su ubuntu instead of chpst.

Any ideas on why I see this behavior and how to fix it so calling sudo sv d downtest results in a clean process exit rather than returning error status codes?

2

There are 2 answers

7
Charles Duffy On BEST ANSWER

sv d sends a SIGTERM if the process is still running. This is signal 15, hence the error being handled in the manner in question.

By contrast, to tell a running program not to start up again after it exits on its own (thus allowing that opportunity), use sv o (once) instead.

Alternately, you can trap SIGTERM in your script when you're expecting it:

trap 'exit 0' TERM

If you want to make this conditional:

trap 'if [[ $ignore_sigterm ]]; then exit 0; fi' TERM

...and then run

ignore_sigterm=1

before triggering sv d.

7
nbari On

Has a workaround try a subshell for running (chpst -u ubuntu sudo sv d downtest) that will help to allow calling the last exit 0 since now is not being called because is exiting before.

#!/bin/sh
exec 2>&1
echo "running downtest"
(sudo sv d downtest)
exit 0

Indeed, for stopping the process you don’t need chpst -u ubuntu if want to stop or control the service as another user just need to adjust the permissions to the ./supervise directory that’s why probably you are getting the exit code -1

Checking the runsv man:

Two arguments are given to ./finish. The first one is ./run’s exit code, or -1 if ./run didn’t exit normally. The second one is the least significant byte of the exit status as determined by waitpid(2); for instance it is 0 if ./run exited normally, and the signal number if ./run was terminated by a signal. If runsv cannot start ./run for some reason, the exit code is 111 and the status is 0.

And from the faq:


Is it possible to allow a user other than root to control a service Using the sv program to control a service, or query its status informations, only works as root. Is it possible to allow non-root users to control a service too?

Answer: Yes, you simply need to adjust file system permissions for the ./supervise/ subdirectory in the service directory. E.g.: to allow the user burdon to control the service dhcp, change to the dhcp service directory, and do

# chmod 755 ./supervise
# chown burdon ./supervise/ok ./supervise/control ./supervise/status

In case you would like to full stop/start you could remove the symlink of your run service, but that will imply to create it again when you want the service up.

Just in case, because of this and other cases, I came up with immortal to simplify the stop/start/restart/retries of services without root privileges, full based on daemontools & runit just adapted to some new flows.