#!/bin/sh -e
#
# description:	Starts and stops each hotpluggable subsystem.
#		On startup, may simulate hotplug events for devices
#		that were present at boot time, before filesystems
#		used by /sbin/hotplug became available.

PATH=/sbin:/bin:/usr/sbin:/usr/bin

[ -x /sbin/hotplug ] || exit 0

if [ ! -f /proc/sys/kernel/hotplug ]; then
   echo "Kernel hotplug support not enabled."
   exit 0
fi

# execution order of the *.rc scripts
RC_ORDER="pci usb isapnp"

[ -e /etc/default/hotplug ] && . /etc/default/hotplug

# Takes two parameters: list to sort through and list of elements
# that should be removed from it. As a side effect it modifies
# $prune_output (the list with the elements removed) and $prune_discard
# (the list of the elements discarded).
prune() {
    unset prune_output prune_discard
    local discard

    for x in $1; do
	unset discard
	for y in $2; do
	    [ $x = $y ] && discard=yes
	done
	if [ "$discard" ]; then
	    prune_discard="$prune_discard $x"
	else
	    prune_output="$prune_output $x"
	fi
    done
}

# Prints the elements from the first argument, in the order in which they
# appear in the second argument.
sort_with_deps() {
    local unordered

    # Get the list of elements that have no ordering requirement.
    prune "$1" "$2"
    unordered=$prune_output

    # Reverse psychology here. Throw away all items of the DEPLIST that
    # we actually want. prune_discard will have them in the right order.
    prune "$2" "$prune_discard"

    # Append the elements with no ordering to the sorted list.
    echo "$prune_discard $unordered"

    unset prune_output prune_discard
}

quiet_printk() {
    [ -w /proc/sys/kernel/printk -a "$QUIET" ] || return 0
    SAVED_LOGLEVEL=$(cat /proc/sys/kernel/printk)
    echo "1 4 1 7" > /proc/sys/kernel/printk
}

restore_printk() {
    [ "$SAVED_LOGLEVEL" ] || return 0
    echo "$SAVED_LOGLEVEL" > /proc/sys/kernel/printk
}

run_rcs() {
    for RC in /etc/hotplug/*.rc; do
	local basename=${RC#/etc/hotplug/}
	SUBSYSTEMS="$SUBSYSTEMS ${basename%.rc}"
    done

    SUBSYSTEMS=$(sort_with_deps "$SUBSYSTEMS" "$RC_ORDER")

    if [ "$QUIET" ]; then
	printf "$2:"
    else
	printf "$2:\n"
    fi

    for name in $SUBSYSTEMS; do
	if [ "$(eval echo \$HOTPLUG_RC_$name)" = no \
		-o ! -x /etc/hotplug/$name.rc ]; then
	    [ "$QUIET" ] || printf "   %-8s [disabled]\n" $name
	    continue
	fi

	if   [ "$1" = status ]; then
	    /etc/hotplug/$name.rc $1 || true
	    continue
	elif [ "$QUIET" ]; then
	    printf " %s" $name
	    /etc/hotplug/$name.rc $1 > /dev/null 2>&1 || printf "[failed]"
	else
	    local STATUS="success"
	    printf "   %-8s\n" $name
	    /etc/hotplug/$name.rc $1 || STATUS="failed"
	    printf "   %-8s [%s]\n" $name $STATUS
	fi
    done

    if [ "$QUIET" ]; then
	printf ".\n"
    else
	printf "done.\n"
    fi
}

case "$1" in
start)
    quiet_printk
    run_rcs $1 "Starting hotplug subsystem"
    restore_printk
    ;;

stop)
    quiet_printk
    run_rcs $1 "Stopping hotplug subsystem"
    restore_printk
    ;;

restart|force-reload)
    quiet_printk
    run_rcs stop  "Stopping hotplug subsystem"
    run_rcs start "Starting hotplug subsystem"
    restore_printk
    ;;

status)
    unset QUIET
    run_rcs $1 "Hotplug status"
    ;;

*)
    echo "Usage: $0 {start|stop|restart|status|force-reload}" >&2
    exit 1
    ;;
esac

exit 0
