Package: runit Version: 2.1.1-6.2 Severity: wishlist Tags: patch Hi,
Since the release of 2.88dsf-23 of sysv-rc, dependency based boot ordering is mandatory in Debian; however, insserv fails to recognise symlinks to /usr/bin/sv as valid initscripts. This makes using runit unnecessarily painful; to ease the pain, I wrote a pretty complete start-stop-daemon wrapper for runit (alas, in zsh). Diverting /sbin/start-stop-daemon to /sbin/start-stop-daemon.real and using this script, conventional initscripts continue to "work". My script determines whether it should pass the call through to the real start-stop-daemon or to use sv(8) to manage a runit service. While it's a bit of a kludge, it appears to work fairly well. An important drawback is that it needs to be adapted each time the semantics of start-stop-daemon change, but maybe that doesn't happen so often. The script uses few zsh-specific features; a determined person should be able to modify it to run in bash or even plain sh relatively easily (but I have no time/interest to do so myself). The script is licensed under the GPL v3, with the special exception that permission is granted to include it in the runit package and license it to users of the runit package under the same license as the rest of the package. Work on the script was sponsored by CAE Engineering Kft. Best regards, Andras -- Andras Korn <korn at elan.rulez.org> All that glitters may not be gold, but it sure has a high refractive index.
#!/bin/zsh # # This script is intended to wrap start-stop-daemon. It will call the # original start-stop-daemon with the supplied arguments unless the daemon # to be started appears to exist as a runit service, in which case it will # map the start-stop-daemon call to an sv(8) call. # # If called by non-root user, fall back to original start-stop-daemon # unconditionally [[ $UID -gt 0 ]] && exec /sbin/start-stop-daemon.real $@ set -A args $@ SVDIR=${SVDIR:-/etc/service} unset mode signal exec timeout startas testmode oknodo quiet verbose command svstat oknodo=0 quiet=0 while [[ -n "$1" ]]; do case "$1" in -S|--start) mode=start ;; -K|--stop) mode=stop ;; -T|--status) mode=status ;; -H|--help|-V|--version) exec /sbin/start-stop-daemon.real $args ;; -x|--exec) shift exec="$1" ;; -s|--signal) shift signal=$1 ;; --signal=*) signal="${1/--signal=/}" ;; -R|--retry) shift timeout="$1" ;; --retry=*) timeout="${1/--retry=/}" ;; -a|--startas) shift startas="$1" ;; -t|--test) testmode=1 ;; -o|--oknodo) oknodo=1 ;; -q|--quiet) quiet=1 exec >/dev/null ;; -v|--verbose) verbose=1 ;; -p|--pidfile|-n|--name|-u|--user|-g|--group|-r|--chroot|-d|--chdir|-N|--nicelevel|-P|--procsched|-I|--iosched|-k|--umask|-m|--make-pidfile) # ignored shift ;; --pidfile=*|-b|--background|--nicelevel=*|--procsched=*|--iosched=*|--umask=*) ;; --) # What follows is args to the daemon. Avoid parsing # those accidentally. break ;; *) # Assume the previous was the last option; the rest # is the name of the daemon plus args, of which we # only care about the daemon. command=$1 break ;; esac shift done # Try to infer runit service name. If our parent is an initscript, use its # basename read foo script foo </proc/$PPID/cmdline if [[ "${script:h}" = /etc/init.d ]]; then svname=${script:t} elif [[ "${$(readlink -f /proc/$PPID/exe):h}" = /etc/init.d ]]; then read svname < /proc/$PPID/comm fi # if not, try other heuristics svnames=($startas $exec $command) while ! [[ -d $SVDIR/$svname/supervise/. ]] && [[ -n "$svnames[1]" ]]; do svname=${svnames[1]:t} shift svnames done # if runit service doesn't exist, call real start-stop-daemon. if ! [[ -d $SVDIR/$svname/supervise/. ]] || [[ -z "$svname" ]]; then exec /sbin/start-stop-daemon.real $args fi # otherwise, do what we've been asked to [[ "$quiet" = "0" ]] && [[ "$verbose" = "1" ]] && echo "start-stop-daemon.runit: will act on $svname service." >&2 function sendsig() { case "$signal" in HUP|1) sv hup $svname ;; INT|2) sv interrupt $svname ;; QUIT|3) sv quit $svname ;; KILL|9) sv kill $svname ;; USR1|10) sv 1 $svname ;; USR2|12) sv 2 $svname ;; ALRM|14) sv alarm $svname ;; TERM|15) sv down $svname ;; CONT|18) sv cont $svname ;; STOP|19) sv pause $svname ;; *) echo "$0: ERROR: don't know how to send $signal signal to $svname." >&2 exit 3 ;; esac } function wait_until_exited() { counter=0 read svstat < $SVDIR/$svname/supervise/stat while ! [[ "$svstat" = down ]]; do ((counter++)) [[ $counter -gt $timeout ]] && return 1 sleep 1 read svstat < $SVDIR/$svname/supervise/stat done return 0 } function do_stop() { if [[ $timeout =~ / ]]; then # handle complex schedule OLDIFS="$IFS" IFS=/ echo $timeout | read -A schedule IFS="$OLDIFS" while [[ -n "$schedule[1]" ]]; do signal=$schedule[1] sendsig shift schedule timeout=$schedule[1] wait_until_exited && exit 0 shift schedule done exit 2 else # simple timeout if [[ -z "$signal" ]]; then if [[ $timeout =~ ^[0-9]+$ ]]; then export SVWAIT=$timeout fi if sv stop $svname; then exit 0 else exit 1 fi else sendsig [[ -n "$timeout" ]] && if wait_until_exited; then exit 0 else exit 1 fi fi fi } read svstat < $SVDIR/$svname/supervise/stat case "$mode" in start) [[ "$svstat" = run ]] && [[ "$oknodo" = "0" ]] && exit 1 # Emulate start-stop-daemon semantics [[ -z "$testmode" ]] && sv start $svname exit 0 ;; stop) [[ "$svstat" = down ]] && [[ "$oknodo" = "1" ]] && exit 1 # Emulate start-stop-daemon semantics [[ -z "$testmode" ]] && do_stop # handles --retry and --signal, therefore separate function ;; status) case "$svstat" in # States are complex; we only handle the most basic cases here and bail on # the rest (e.g. "finish" cannot be correctly reported as "running" or "not # running") run) exit 0 ;; down) exit 3 ;; *) exit 4 ;; esac ;; esac exit 0