All pastes #205803 Raw Edit

Miscellany

public text v1 · immutable
#205803 ·published 2006-10-17 01:52 UTC
rendered paste body
# Copyright 1999-2004 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

# RC Dependency and misc service functions
RC_GOT_SERVICES="yes"

[[ ${RC_GOT_FUNCTIONS} != "yes" ]] && source /sbin/functions.sh

if [[ ${RC_GOT_DEPTREE_INFO} != "yes" ]] ; then
        # Only try and update if we are root
        if [[ ${EUID} == "0" ]] && ! /sbin/depscan.sh ; then
                echo
                eerror "Error running '/sbin/depscan.sh'!"
                eerror "Please correct any problems above."
                exit 1
        fi

        source "${svcdir}/deptree"
        if [[ ${RC_GOT_DEPTREE_INFO} != "yes" ]] ; then
                echo
                eerror "Dependency info is missing!  Please run"
                eerror "  # /sbin/depscan.sh"
                eerror "to fix this."
                exit 1
        fi
fi

#####################
# Internal variables
#####################

# The name of the service whose dependency info we currently have
rc_name=
# The index of the service whose dependency info we currently have
rc_index=0
# Our dependency types ...
rc_ineed=
rc_needsme=
rc_iuse=
rc_usesme=
rc_ibefore=
rc_iafter=
rc_broken=
rc_mtime=

############
# Functions
############

# bool get_service_index(service, index)
#
#   Print the index of 'service'.  'index' is the current index.
#
get_service_index() {
        if [[ -z $1 || -z $2 ]] ; then
                echo "0"
                return 1
        fi

        local x myservice="$1" index="$2"

        # Do we already have the index?
        if [[ -n ${index} && ${index} -gt 0 \
                && ${myservice} == "${RC_DEPEND_TREE[${index}]}" ]] ; then
                        echo "${index}"
                        return 0
        fi

        for (( x=1; x<=${RC_DEPEND_TREE[0]}; x++ )); do
                index="$(( ${x} * ${rc_index_scale} ))"
                if [[ ${myservice} == "${RC_DEPEND_TREE[${index}]}" ]] ; then
                        echo "${index}"
                        return 0
                fi
        done

        echo "0"
        return 1
}

# bool get_dep_info(service)
#
#   Set the Dependency variables to contain data for 'service'
#
get_dep_info() {
        [[ -z $1 ]] && return 1

        local myservice="$1"

        # We already have the right stuff ...
        [[ ${myservice} == "${rc_name}" && -n ${rc_mtime} ]] && return 0

        rc_index="$(get_service_index "${myservice}" "${rc_index}")"
        rc_mtime="${RC_DEPEND_TREE[$((${rc_index} + ${rc_type_mtime}))]}"

        # Verify that we have the correct index (rc_index) ...
        # [[ ${rc_index} == "0" ]] && return 1

        rc_name="${RC_DEPEND_TREE[${rc_index}]}"
        rc_ineed="${RC_DEPEND_TREE[$((${rc_index} + ${rc_type_ineed}))]}"
        rc_needsme="${RC_DEPEND_TREE[$((${rc_index} + ${rc_type_needsme}))]}"
        rc_iuse="${RC_DEPEND_TREE[$((${rc_index} + ${rc_type_iuse}))]}"
        rc_usesme="${RC_DEPEND_TREE[$((${rc_index} + ${rc_type_usesme}))]}"
        rc_ibefore="${RC_DEPEND_TREE[$((${rc_index} + ${rc_type_ibefore}))]}"
        rc_iafter="${RC_DEPEND_TREE[$((${rc_index} + ${rc_type_iafter}))]}"
        rc_broken="${RC_DEPEND_TREE[$((${rc_index} + ${rc_type_broken}))]}"
        rc_mtime="${RC_DEPEND_TREE[$((${rc_index} + ${rc_type_mtime}))]}"
        return 0
}

# string check_dependency(deptype, service1)
#
#   List all the services that depend on 'service1' of dependency
#   type 'deptype'
#
# bool check_dependency(deptype, -t, service1, service2)
#
#   Returns true if 'service2' is a dependency of type 'deptype'
#   of 'service1'
#
check_dependency() {
        [[ -z $1 || -z $2 ]] && return 1

        local x myservice deps

        # Set the dependency variables to relate to 'service1'
        if [[ $2 == "-t" ]] ; then
                [[ -z $3 || -z $4 ]] && return 1
                myservice="$3"
        else
                myservice="$2"
        fi

        if ! get_dep_info "${myservice}" >/dev/null ; then
                eerror "Could not get dependency info for ${myservice}!" > /dev/stderr
                eerror "Please run:" > /dev/stderr
                eerror "  # /sbin/depscan.sh" > /dev/stderr
                eerror "to try and fix this." > /dev/stderr
                return 1
        fi

        # Do we have valid info for 'deptype' ?
        deps="rc_$1"
        [[ -z ${!deps} ]] && return 1

        if [[ $2 == "-t" && -n $4 ]]; then
                # Check if 'service1' have 'deptype' dependency on 'service2'
                for x in ${!deps} ; do
                        [[ ${x} == "$4" ]] && return 0
                done
                return 1
        else
                # Just list all services that 'service1' have 'deptype' dependency on.
                echo "${!deps}"
                return 0
        fi
}

# Same as for check_dependency, except 'deptype' is set to
# 'ineed'.  It will return all the services 'service1' NEED's.
ineed() {
        check_dependency ineed "$@" 
}

# Same as for check_dependency, except 'deptype' is set to
# 'needsme'.  It will return all the services that NEED 'service1'.
needsme() {
        check_dependency needsme "$@"
}

# Same as for check_dependency, except 'deptype' is set to
# 'iuse'.  It will return all the services 'service1' USE's.
iuse() {
        check_dependency iuse "$@"
}

# Same as for check_dependency, except 'deptype' is set to
# 'usesme'.  It will return all the services that USE 'service1'.
usesme() {
        check_dependency usesme "$@"
}

# Same as for check_dependency, except 'deptype' is set to
# 'ibefore'.  It will return all the services that are started
# *after* 'service1' (iow, it will start 'service1' before the
# list of services returned).
ibefore() {
        check_dependency ibefore "$@"
}

# Same as for check_dependency, except 'deptype' is set to
# 'iafter'.  It will return all the services that are started
# *before* 'service1' (iow, it will start 'service1' after the
# list of services returned).
iafter() {
        check_dependency iafter "$@"
}

# Same as for check_dependency, except 'deptype' is set to
# 'broken'.  It will return all the services that 'service1'
# NEED, but are not present.
broken() {
        check_dependency broken "$@"
}

# bool is_fake_service(service, runlevel)
#
#   Returns ture if 'service' is a fake service in 'runlevel'.
#
is_fake_service() {
        local x fake_services

        [[ -z $1 || -z $2 ]] && return 1

        [[ $2 != "${BOOTLEVEL}" && -e /etc/runlevels/"${BOOTLEVEL}"/.fake ]] && \
                fake_services="$( < /etc/runlevels/"${BOOTLEVEL}"/.fake )"

        [[ -e /etc/runlevels/"$2"/.fake ]] && \
                fake_services="${fake_services} $( < /etc/runlevels/"$2"/.fake )"

        for x in ${fake_services} ; do
                [[ $1 == "${x##*/}" ]] && return 0
        done

        return 1
}

# bool in_runlevel(service, runlevel)
#
#   Returns true if 'service' is in runlevel 'runlevel'.
#
in_runlevel() {
        [[ -z $1 || -z $2 ]] && return 1

        [[ -L "/etc/runlevels/$2/$1" ]] && return 0

        return 1
}

# bool is_runlevel_start()
#
#   Returns true if it is a runlevel change, and we are busy
#   starting services.
#
is_runlevel_start() {
        [[ -d "${svcdir}/softscripts.old" ]]
}

# bool is_runlevel_stop()
#
#   Returns true if it is a runlevel change, and we are busy
#   stopping services.
#
is_runlevel_stop() {
        [[ -d "${svcdir}/softscripts.new" ]]
}

# void save_options(char *option, char *optstring)
#
#    save the settings ("optstring") for "option"
#
save_options() {
        local myopts="$1"

        shift
        if [[ ! -d "${svcdir}/options/${SVCNAME}" ]] ; then
                mkdir -p -m 0755 "${svcdir}/options/${SVCNAME}"
        fi

        echo "$*" > "${svcdir}/options/${SVCNAME}/${myopts}"
}

# char *get_options(char *option)
#
#    get the "optstring" for "option" that was saved
#    by calling the save_options function
#
get_options() {
        local svc="${SVCNAME}"
        [[ -n $2 ]] && svc="$2"

        if [[ -f "${svcdir}/options/${svc}/$1" ]] ; then
                echo "$(< ${svcdir}/options/${svc}/$1)"
        fi
}

# void sevice_message([char *type] char *message)
#
# Print out a service message if we are on parallel
service_message() {
        [[ ${RC_PARALLEL_STARTUP} != "yes" || ${RC_QUIET} == "yes" ]] && return

        local cmd="einfo"
        case "$1" in
                1|error|eerror)
                        cmd="eerror"
                        shift
                        ;;
                ewarn)
                        cmd="ewarn"
                        shift
                        ;;
        esac

        local r="${RC_QUIET_STDOUT}"
        RC_QUIET_STDOUT="no"
        ${cmd} "$@"
        RC_QUIET_STDOUT="${r}"
}

# bool begin_service( service )
#
#   atomically marks the service as being executed
#   use like this:
#
#   if begin_service service ; then
#         whatever is in here can only be executed by one process
#         end_service service
#   fi
begin_service() {
        local service="$1"
        [[ -z ${service} ]] && return 1

        [[ ${START_CRITICAL} == "yes" || ${STOP_CRITICAL} == "yes" ]] && return 0

        mkfifo "${svcdir}/exclusive/${service}" 2> /dev/null
}

# void end_service(service, exitcode)
#
#   stops executing a exclusive region and
#   wakes up anybody who is waiting for the exclusive region
#
end_service() {
        local service="$1" exitstatus="$2"
        [[ -z ${service} ]] && return

        # if we are doing critical services, there is no fifo
        [[ ${START_CRITICAL} == "yes" || ${STOP_CRITICAL} == "yes" ]] && return

        if [[ -n ${exitstatus} ]] ; then
                echo "${exitstatus}" > "${svcdir}/exitcodes/${service}"
        fi

        # move the fifo to a unique name so no-one is waiting for it
        local fifo="${svcdir}/exclusive/${service}"
        if [[ -e ${fifo} ]] ; then
                local tempname="${fifo}.$$"
                mv -f "${fifo}" "${tempname}"

                # wake up anybody that was waiting for the fifo
                touch "${tempname}"

                # We dont need the fifo anymore
                rm -f "${tempname}"
        fi
}

# int wait_service(service)
#
# If a service has started, or a fifo does not exist return 0
# Otherwise, wait until we get an exit code via the fifo and return
# that instead.
wait_service() {
        local service="$1"
        local fifo="${svcdir}/exclusive/${service}"

        [[ ${START_CRITICAL} == "yes" || ${STOP_CRITICAL} == "yes" ]] && return 0
        [[ ! -e ${fifo} ]] && return 0

        # This will block until the service fifo is touched
        # Otheriwse we don't block
        # We need to use cat instead of the bash inbuilt < so we don't see errors
        local tmp="$( cat "${fifo}" 2>/dev/null )"
        local exitstatus="$( < "${svcdir}/exitcodes/${service}" )"

        return "${exitstatus}"
}

# int start_service(service)
#
#   Start 'service' if it is not already running.
#
start_service() {
        local service="$1"
        [[ -z ${service} ]] && return 1

        if [[ ! -e "/etc/init.d/${service}" ]] ; then
                mark_service_stopped "${service}"
                return 1
        fi

        service_starting "${service}" && return 0
        service_started "${service}" && return 0
        service_inactive "${service}" && return 1

        if is_fake_service "${service}" "${SOFTLEVEL}" ; then
                mark_service_started "${service}"
                splash "svc_start" "${service}"
                splash "svc_started" "${service}" "0"
                return 0
        fi

        begin_service "${service}" || return 0
        splash "svc_start" "${service}"
        if [[ ${RC_PARALLEL_STARTUP} != "yes" || \
                  ${START_CRITICAL} == "yes" ]] ; then
                # if we can not start the services in parallel
                # then just start it and return the exit status
                (
                        profiling name "/etc/init.d/${service} start"
                        "/etc/init.d/${service}" start
                )

                service_started "${service}" || service_inactive "${service}" \
                        || service_scheduled "${service}"
                retval=$?

                end_service "${service}" "${retval}"
                splash "svc_started" "${service}" "${retval}"

                return "${retval}"
        else
                # if parallel startup is allowed, start it in background
                (
                        profiling name "/etc/init.d/${service} start"
                        "/etc/init.d/${service}" start

                        service_started "${service}" || service_inactive "${service}" \
                                || service_scheduled "${service}"
                        retval=$?

                        end_service "${service}" "${retval}"
                        splash "svc_started" "${service}" "${retval}"
                ) &
                return 0
        fi
}

# int stop_service(service)
#
#   Stop 'service' if it is not already running.
#
stop_service() {
        local service="$1"
        [[ -z ${service} ]] && return 1

        if [[ ! -e "/etc/init.d/${service}" ]] ; then
                mark_service_stopped "${service}"
                return 0
        fi

        service_stopping "${service}" && return 0
        service_stopped "${service}" && return 0

        local level="${SOFTLEVEL}"
        is_runlevel_stop && level="${OLDSOFTLEVEL}"

        if is_fake_service "${service}" "${level}" ; then
                splash "svc_stop" "${service}"
                mark_service_stopped "${service}"
                splash "svc_stopped" "${service}" "0"
                return 0
        fi

        begin_service "${service}" || return 0

        splash "svc_stop" "${service}"
        if [[ ${RC_PARALLEL_STARTUP} != "yes" || \
                  ${STOP_CRITICAL} == "yes" ]] ; then
                # if we can not start the services in parallel
                # then just start it and return the exit status
                ( "/etc/init.d/${service}" stop )
                service_stopped "${service}"
                retval=$?
                end_service "${service}" "${retval}"
                splash "svc_stopped" "${service}" "${retval}"
                return "${retval}"
        else
                # if parallel startup is allowed, start it in background
                (
                        ( "/etc/init.d/${service}" stop )
                        service_stopped "${service}"
                        retval=$?
                        end_service "${service}" "${retval}"
                        splash "svc_stopped" "${service}" "${retval}"
                ) &
                return 0
        fi
}

# bool mark_service_coldplugged(service)
#
#   Mark 'service' as coldplugged.
#
mark_service_coldplugged() {
        [[ -z $1 ]] && return 1

        ln -snf "/etc/init.d/$1" "${svcdir}/coldplugged/$1"
        return 0
}

# bool mark_service_starting(service)
#
#   Mark 'service' as starting.
#
mark_service_starting() {
        [[ -z $1 ]] && return 1

        ln -sn "/etc/init.d/$1" "${svcdir}/starting/$1" 2>/dev/null || return 1

        [[ -f "${svcdir}/started/$1" ]] && rm -f "${svcdir}/started/$1"
        [[ -f "${svcdir}/inactive/$1" ]] \
                && mv "${svcdir}/inactive/$1" "${svcdir}/wasinactive/$1"
        return 0
}

# bool mark_service_started(service)
#
#   Mark 'service' as started.
#
mark_service_started() {
        [[ -z $1 ]] && return 1

        ln -snf "/etc/init.d/$1" "${svcdir}/started/$1"

        rm -f "${svcdir}/starting/$1" "${svcdir}/inactive/$1" \
                "${svcdir}/wasinactive/$1" "${svcdir}/stopping/$1" \
                "${svcdir}"/scheduled/*/"$1"

        return 0 
}

# bool mark_service_inactive(service)
#
#   Mark service as inactive
#
mark_service_inactive() {
        [[ -z $1 ]] && return 1

        ln -snf "/etc/init.d/$1" "${svcdir}/inactive/$1"

        rm -f "${svcdir}/started/$1" "${svcdir}/wasinactive/$1" \
                "${svcdir}/starting/$1" "${svcdir}/stopping/$1"

        return 0
}

# bool mark_service_stopping(service)
#
#   Mark 'service' as stopping.
#
mark_service_stopping() {
        [[ -z $1 ]] && return 1

        ln -sn "/etc/init.d/$1" "${svcdir}/stopping/$1" 2>/dev/null || return 1

        rm -f "${svcdir}/started/$1"
        [[ -f "${svcdir}/inactive/$1" ]] \
                && mv "${svcdir}/inactive/$1" "${svcdir}/wasinactive/$1"

        return 0
}

# bool mark_service_stopped(service)
#
#   Mark 'service' as stopped.
#
mark_service_stopped() {
        [[ -z $1 ]] && return 1

        rm -Rf "${svcdir}/daemons/$1" "${svcdir}/starting/$1" \
                "${svcdir}/started/$1" "${svcdir}/inactive/$1" \
                "${svcdir}/wasinactive/$1" "${svcdir}/stopping/$1" \
                "${svcdir}/scheduled/$1" "${svcdir}/options/$1" \
                "${svcdir}/coldplugged/$1"

        return 0
}

# bool test_service_state(char *service, char *state)
#
#   Returns 0 if the service link exists and points to a file, otherwise 1
#   If 1 then the link is erased if it exists
test_service_state() {
        [[ -z $1 || -z $2 ]] && return 1

        local f="${svcdir}/$2/$1"

        # Service is in the state requested
        [[ -L ${f} ]] && return 0

        [[ ! -e ${f} ]] && rm -f "${f}"
        return 1
}

# bool service_coldplugged(service)
#
#   Returns true if 'service' is coldplugged
#
service_coldplugged() {
        test_service_state "$1" "coldplugged"
}

# bool service_starting(service)
#
#   Returns true if 'service' is starting
#
service_starting() {
        test_service_state "$1" "starting"
}

# bool service_started(service)
#
#   Returns true if 'service' is started
#
service_started() {
        test_service_state "$1" "started"
}

# bool service_inactive(service)
#
#   Returns true if 'service' is inactive
#
service_inactive() {
        test_service_state "$1" "inactive"
}

# bool service_wasinactive(service)
#
#   Returns true if 'service' is inactive
#
service_wasinactive() {
        test_service_state "$1" "wasinactive"
}

# bool service_stopping(service)
#
#   Returns true if 'service' is stopping
#
service_stopping() {
        test_service_state "$1" "stopping"
}

# bool service_stopped(service)
#
#   Returns true if 'service' is stopped
#
service_stopped() {
        [[ -z $1 ]] && return 1

        service_starting "$1" && return 1
        service_started "$1" && return 1
        service_stopping "$1" && return 1
        service_inactive "$1" && return 1

        return 0
}

# char service_scheduled_by(service)
#
#   Returns a list of services which will try and start 'service' when they
#   are started
#
service_scheduled_by() {
        [[ -z $1 ]] && return 1

        local x= s= r=
        for x in $(dolisting "${svcdir}/scheduled/*/$1") ; do
                s="${x%/*}"
                r="${r} ${s##*/}"
        done

        echo "${r:1}"
}

# bool service_scheduled()
#
#   Returns true if 'service' is scheduled to be started by another service
#
service_scheduled() {
        [[ -n $(service_scheduled_by "$@") ]]
}

# bool mark_service_failed(service)
#
#   Mark service as failed for current runlevel.  Note that
#   this is only valid on runlevel change ...
#
mark_service_failed() {
        [[ -z $1 || ! -d "${svcdir}/failed" ]] && return 1

        ln -snf "/etc/init.d/$1" "${svcdir}/failed/$1"
}

# bool service_failed(service)
#
#   Return true if 'service' have failed during this runlevel.
#
service_failed() {
        [[ -n $1 && -L "${svcdir}/failed/$1" ]]
}

# bool service_started_daemon(char *interface, char *daemon, int index)
# Returns 0 if the service started the given daemon
# via start-stop-daemon, otherwise 1.
# If index is emtpy, then we don't care what the first daemon launched
# was, otherwise the daemon must also be at that index
service_started_daemon() {
        local service="$1" daemon="$2" index="${3:-[0-9]*}"
        local daemonfile="${svcdir}/daemons/${service}"

        [[ ! -e ${daemonfile} ]] && return 1
        grep -q '^RC_DAEMONS\['"${index}"'\]="'${daemon}'"$' "${daemonfile}"
}

# bool net_service(service)
#
#   Returns true if 'service' is a service controlling a network interface
#
net_service() {
        [[ -n $1 && ${1%%.*} == "net" && ${1#*.} != "$1" ]]
}

# bool is_net_up(char *exclude)
#
#    Return true if service 'net' is considered up, else false.
#
#    Notes for RC_NET_STRICT_CHECKING values:
#      none  net is up without checking anything - usefull for vservers
#      lo    Interface 'lo' is counted and if only it is up, net is up.
#      no    Interface 'lo' is not counted, and net is down even with it up,
#            so there have to be at least one other interface up.
#      yes   All interfaces must be up.
is_net_up() {
        local x=

        case "${RC_NET_STRICT_CHECKING}" in
                none)
                        return 0
                        ;;
                lo)
                        service_started "net.lo"
                        return $?
                        ;;
                yes)
                        for x in $(dolisting "/etc/runlevels/${BOOTLEVEL}/net.*") \
                                $(dolisting "/etc/runlevels/${SOFTLEVEL}/net.*") ; do
                                local y="${x##*/}"
                                [[ ${y} == "$1" ]] && return 1
                                service_started "${y}" || return 1
                        done
                        return 0
                        ;;
                *)
                        for x in $(dolisting "${svcdir}/started/net.*") ; do
                                local y="${x##*/}"
                                [[ ${y} == "$1" ]] && continue
                                [[ ${y} != "net.lo" ]] && return 0
                        done
                        return 1 
                ;;
        esac
}

# bool dependon(service1, service2)
#
#   Does service1 depend (NEED or USE) on service2 ?
#
dependon() {
        ineed -t "$1" "$2" || iuse -t "$1" "$2"
}

# string validi(use/after, service)
#
#   This is the main code for valid_after and valid_iuse
#   No point in writing it twice!
valid_i() {
        # Just set to dummy for now (don't know if $svcdir/softlevel exists yet).
        local mylevel="${BOOTLEVEL}" x= valid=

        [[ $1 != "after" && $1 != "use" ]] && return 1

        # Cannot be SOFTLEVEL, as we need to know current runlevel
        [[ -f "${svcdir}/softlevel" ]] && mylevel=$( < "${svcdir}/softlevel" )

        for x in $( i$1 "$2" ) ; do
                [[ -e "/etc/runlevels/${BOOTLEVEL}/${x}" || \
                   -e "/etc/runlevels/${mylevel}/${x}" || \
                   ${x} == "net" ]] \
                                && valid="${valid} ${x}"
        done

        echo "${valid:1}"
        return 0
}

# string valid_iuse(service)
#
#   This will only give the valid use's for the service
#   (they must be in the boot or current runlevel)
#
valid_iuse() {
        valid_i "use" "$1"
}

#string valid_iafter(service)
#
#   Valid services for current or boot rc level that should start
#   before 'service'
#
valid_iafter() {
        valid_i "after" "$1"
}

# string trace_dependencies(service[s])
#
#   Get and sort the dependencies of given service[s].
#
trace_dependencies() {
        local -a services=( "$@" ) net_deps=()
        local i= j= net_services= x=

        if [[ $1 == -* ]]; then
                deptype="${1/-/}"
                if net_service "${SVCNAME}" ; then
                        services=( "net" "${SVCNAME}" )
                else
                        services=( "${SVCNAME}" )
                fi
        fi

        if is_net_up || is_runlevel_stop ; then
                for x in $(dolisting "${svcdir}/started/net.*") \
                        $(dolisting "${svcdir}/inactive/net.*") ; do
                        net_services="${net_services} ${x##*/}"
                done
        else
                for x in $(dolisting "/etc/runlevels/${BOOTLEVEL}/net.*") \
                        $(dolisting "/etc/runlevels/${SOFTLEVEL}/net.*") \
                        $(dolisting "/etc/runlevels/coldplugged/net.*") ; do
                        net_services="${net_services} ${x##*/}"
                done
        fi

        # Cache the generic "net" depends
        net_deps=( $( ineed net ) $( valid_iuse net )   )
        if is_runlevel_start || is_runlevel_stop ; then
                net_deps=( "${net_deps[@]}" $( valid_iafter net ) )
        fi

        # OK, this is a topological sort
        # The bonus about doing it in bash is that we can calculate our sort
        # order as we calculate our dependencies
        local -a visited sorted
        visit_service() {
                local service="$1" dep x
                local -a deps

                [[ " ${visited[@]} " == *" ${service} "* ]] && return
                visited=( "${visited[@]}" "${service}" )

                if [[ -n ${deptype} ]] ; then
                        deps=( $( "${deptype}" "${service}" ) )
                else
                        deps=( $( ineed "${service}" ) $( valid_iuse "${service}" ) ) 
                        if is_runlevel_start || is_runlevel_stop ; then
                                deps=( "${deps[@]}" $( valid_iafter "${service}" ) )
                        fi

                        # If we're a net service, we have to get deps for ourself
                        # and the net service as we're both
                        net_service "${service}" && deps=( "${deps[@]}" "${net_deps[@]}" )

                        x=" ${deps[@]} "
                        deps=( "${deps[@]}" ${x// net / ${net_services} } )
                fi

                services=( "${services[@]}" "${deps[@]}" )
                for dep in ${deps[@]}; do
                        visit_service "${dep}"
                done
                sorted=( "${sorted[@]}" "${service}" )
        }

        for (( i=0; i<${#services[@]}; i++)); do
                visit_service "${services[i]}"
        done

        services=( "${sorted[@]}" )

        if [[ -n ${deptype} ]] ; then
                # If deptype is set, we do not want the name of this service
                x=" ${services[@]} "
                services=( ${x// ${SVCNAME} / } )

                # If its a net service, do not include "net"
                if net_service "${SVCNAME}" ; then
                        x=" ${services[@]} "
                        sorted=( ${services// net / } )
                fi
        fi

        echo "${services[@]}"
}

# bool query_before(service1, service2)
#
#   Return true if 'service2' should be started *before*
#   service1.
#
query_before() {
        local x list
        local netservice="no"

        [[ -z $1 || -z $2 ]] && return 1

        list="$( trace_dependencies "$1" )"

        net_service "$2" && netservice="yes"

        for x in ${list} ; do
                [[ ${x} == "$2" ]] && return 0

                # Also match "net" if this is a network service ...
                [[ ${netservice} == "yes" && ${x} == "net" ]] && return 0
        done

        return 1
}

# vim:ts=4