#!/bin/bash

. /usr/lib/rc/functions

# print usage and exit
usage() {
    local name=${0##*/}
    cat >&2 << EOF
usage: $name <action> [options] [daemons]

options:
    -s, --started     Filter started daemons
    -S, --stopped     Filter stopped daemons
    -f, --failed      Filter failed daemons

<daemons> is a space separated list of script in /usr/lib/rc/sv.d
<action> can be a start, stop, restart, reload, status, ...
WARNING: initscripts are free to implement or not the above actions.

e.g: $name list
    $name list hwclock
    $name list --started hwclock
    $name start hwclock
    $name help
    $name enable 98-custom
    $name disable 98-custom
EOF
    exit ${1:-1}
}

# Check if $1 is a valid daemon name
have_daemon() {
    [[ -f /usr/lib/rc/sv.d/$1 && -x /usr/lib/rc/sv.d/$1 ]]
}

enable_auto(){
    local sv=${daemon#*-}
    if have_daemon "$sv"; then
        if [[ ! -e /etc/rc/sysinit/$daemon ]];then
            stat_busy "Enable $sv autostart"
            ln -s /usr/lib/rc/sv.d/$sv /etc/rc/sysinit/$daemon || stat_die
            stat_done
        else
            stat_busy "$sv is already autostarted"
            stat_die
        fi
    fi
}

disable_auto(){
    local sv=${daemon#*-}
    if have_daemon "$sv"; then
        if [[ -e /etc/rc/sysinit/$daemon ]];then
            stat_busy "Disable $sv autostart"
            rm /etc/rc/sysinit/$daemon || stat_die
            stat_done
        else
            stat_busy "$sv is already not autostarted"
            stat_die
        fi
    fi
}

ck_sysinit(){
    local daemon
    for daemon in ${RC_SYSINIT[@]}; do
        local sv=${daemon#*-}
        [[ $1 = "${sv#@}" ]] && return 1
    done
    return 0
}

ck_shutdown(){
    local daemon
    for daemon in ${RC_SHUTDOWN[@]}; do
        local sv=${daemon#*-}
        [[ $1 = "${sv#@}" ]] && return 1
    done
    return 0
}

check_root() {
    (( EUID == 0 )) && return
    if type -P sudo >/dev/null; then
        exec sudo -- "${orig_argv[@]}"
    else
        exec su root -c "$(printf ' %q' "${orig_argv[@]}")"
    fi
}

stat_started() {
    echo -ne "${C_OTHER}[${C_START}started${C_OTHER}]"
}

stat_stopped() {
    echo -ne "${C_OTHER}[${C_STOP}stopped${C_OTHER}]"
}

stat_failed() {
    echo -ne "${C_OTHER}[${C_FAIL}failed ${C_OTHER}]"
}

stat_sysinit() {
    if ! ck_sysinit "$1"; then
        echo -ne "${C_OTHER}[${C_DONE}sysinit${C_OTHER}]"
    else
        echo -ne "${C_OTHER}[${C_DONE}       ${C_OTHER}]"
    fi
}

stat_shutdown() {
    if ! ck_shutdown "$daemon"; then
        echo -ne "${C_OTHER}[${C_DONE}shutdown${C_OTHER}]"
    else
        echo -ne "${C_OTHER}[${C_DONE}        ${C_OTHER}]"
    fi
}

# filter list of daemons
filter_daemons() {
    local -a new_daemons=()
    for daemon in "${daemons[@]}"; do
        # check if daemons is valid
        if ! have_daemon "$daemon"; then
            printf "${C_FAIL}:: ${C_DONE}Daemon script ${C_FAIL}${daemon}${C_DONE} does \
not exist or is not executable.${C_CLEAR}\n" >&2
            exit 2
        fi
        # check filter
        (( ${filter[started]} )) && ck_daemon "$daemon" && continue
        (( ${filter[stopped]} )) && ! ck_daemon "$daemon" && continue
        (( ${filter[failed]} )) && ck_failed "$daemon" && continue
        new_daemons+=("$daemon")
    done
    daemons=("${new_daemons[@]}")
}

(( $# < 1 )) && usage

# ret store the return code of sv.d
declare -i ret=0
# daemons store daemons on which action will be executed
declare -a daemons=()
# filter store current filter mode
declare -A filter=([started]=0 [stopped]=0 [failed]=0)

# parse options
argv=$(getopt -l 'started,stopped,failed' -- 'sfS' "$@") || usage
eval set -- "$argv"

orig_argv=("$0" "$@")

# create an initial daemon list
while [[ "$1" != -- ]]; do
    case "$1" in
        -s|--started)		filter[started]=1 ;;
        -f|--failed)		filter[failed]=1 ;;
        -S|--stopped)		filter[stopped]=1 ;;
    esac
    shift
done

# remove --
shift
# get action
action=$1
shift

# get initial daemons list
for daemon; do
    daemons+=("$daemon")
done

# going into script directory
cd /usr/lib/rc/sv.d

case $action in
    help)
        usage 0 2>&1
    ;;
    list)
        # list take all daemons by default
        [[ -z $daemons ]] && for d in *; do have_daemon "$d" && daemons+=("$d"); done
        filter_daemons
        for daemon in "${daemons[@]}"; do
            s_status=$(ck_status "$daemon")
            s_sysinit=$(stat_sysinit "$daemon")
            s_shutdown=$(stat_shutdown "$daemon")
            printf "$s_status$s_sysinit$s_shutdown${C_CLEAR} $daemon\n"
        done
    ;;
    enable) check_root; enable_auto ;;
    disable) check_root; disable_auto ;;
    *)
        check_root
        # other actions need an explicit daemons list
        [[ -z $daemons ]] && usage
        filter_daemons
        cd /
        for daemon in "${daemons[@]}"; do
            /usr/lib/rc/sv.d/$daemon "$action"
            (( ret += !! $? ))  # clamp exit value to 0/1
        done
    ;;
esac

exit $ret
