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

Reply via email to