#!/bin/bash
# Copyright 1999-2007 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

source /sbin/functions.sh
esyslog() { :; }

argv0=${0##*/}

usage() {
cat << FOO
usage: ${argv0} -a|add script runlevel1 [runlevel2 ...]
       ${argv0} -d|del script [runlevel1 ...]
       ${argv0} -s|show [-v|--verbose] [runlevel1 ...]

examples:
       # ${argv0} add net.eth0 default
       Adds the net.eth0 script (in /etc/init.d) to the "default" runlevel.

       # ${argv0} del sysklogd
       Deletes the sysklogd script from all runlevels.  The original script
       is not deleted, just any symlinks to the script in /etc/runlevels/*.

       # ${argv0} del net.eth2 default wumpus
       Delete the net.eth2 script from the default and wumpus runlevels.
       All other runlevels are unaffected.  Again, the net.eth2 script
       residing in /etc/init.d is not deleted, just any symlinks in
       /etc/runlevels/default and /etc/runlevels/wumpus.

       # ${argv0} show
       Show all enabled scripts and list at which runlevels they will
       execute.  Run with --verbose to see all available scripts.
FOO
	exit ${1:-0}
}

add() {
	local ret=0
	local x=
	local myscript=

	if [[ $# -lt 2 ]] ; then
		eerror "Usage: ${argv0} add <script> runlevel1 [runlevel2 ...]" 1>&2
		exit 1
	fi

	[[ ${quiet} -gt 0 ]] && exec 2> /dev/null

	myscript=$1
	if [[ ! -e ${ROOT}/etc/init.d/${myscript} ]] ; then
		eerror "${argv0}: '${ROOT}etc/init.d/${myscript}' not found; aborting" 1>&2
		exit 1
	fi
	shift
	for x in $* ; do
		if [[ ! -e ${ROOT}etc/runlevels/${x} ]] ; then
			ewarn "runlevel '${x}' not found; skipping" 1>&2
			((++ret))
			continue
		fi
		if [[ -L ${ROOT}etc/runlevels/${x}/${myscript} ]] ; then
			ewarn "${myscript} already installed in runlevel '${x}'; skipping" 1>&2
			continue
		fi
		if [[ ! -x ${ROOT}etc/init.d/${myscript} ]] ; then
			ewarn "${myscript} not executable; skipping" 1>&2
			((++ret))
			continue
		fi
		ln -snf "/etc/init.d/${myscript}" "${ROOT}etc/runlevels/${x}/${myscript}"
		if [[ $? -ne 0 ]] ; then
			eerror "${argv0}: failed to add '${myscript}' to '${x}'" 1>&2
			((++ret))
			continue
		fi
		einfo "${myscript} added to runlevel ${x}"
	done

	return ${ret}
}

del() {
	local x=
	local mylevels=
	local myscript=
	local remlevels=

	if [[ $# -lt 1 ]] ; then
		eerror "Usage: ${argv0} del <script> [runlevel1 ...]" 1>&2
		exit 1
	fi

	[[ ${quiet} -gt 0 ]] && exec 2> /dev/null

	myscript=$1
	shift
	if [[ $# -eq 0 ]] ; then
		mylevels=$(cd "${ROOT}"etc/runlevels/; ls)
	else
		mylevels="$*"
	fi
	remlevels=""
	for x in ${mylevels} ; do
		# -e will return false for broken symlinks so we need the extra -L
		[[ ! -L ${ROOT}etc/runlevels/${x}/${myscript} ]] && \
		[[ ! -e ${ROOT}etc/runlevels/${x}/${myscript} ]] && continue

		remlevels="${remlevels} ${x}"
		if [[ ! -L ${ROOT}etc/runlevels/${x}/${myscript} ]] ; then
			ewarn "Removing invalid init.d script: '${ROOT}etc/runlevels/${x}/${myscript}'" 1>&2
		fi
		rm -f "${ROOT}etc/runlevels/${x}/${myscript}"
		((ret+=$?))
	done
	if [[ -z ${remlevels} ]] ; then
		ewarn "'${myscript}' not found in any of the specified runlevels" 1>&2
	elif [[ ${quiet} -eq 0 ]] ; then
		einfo "'${myscript}' removed from the following runlevels:${remlevels}"
	fi
	return ${ret}
}

show() {
	local x=
	local y=
	local mylevels=
	local myscripts=

	shopt -s nullglob
	if [[ $# -eq 0 ]] ; then
		mylevels=$(cd "${ROOT}"etc/runlevels/; ls)
	else
		mylevels="$*"
		# verify runlevels provided by user
		for y in ${mylevels} ; do
			[[ ! -d ${ROOT}etc/runlevels/${y} ]] && ewarn "Runlevel doesn't exist: ${y}"
		done
	fi
	myscripts=$(cd "${ROOT}"etc/init.d; ls)

	# Sanity check to make sure everything is kosher ...
	for x in $(find "${ROOT}"etc/runlevels -type l) ; do
		[[ -e ${x} ]] || ewarn "Broken runlevel entry: ${x}"
	done
	for x in $(find "${ROOT}"etc/runlevels -maxdepth 1 ! -type l -a ! -type d) ; do
		ewarn "Invalid runlevel entry: ${x}"
	done

	for x in ${myscripts} ; do
		# skip *.sh scripts as they are helpers, not init.d scripts
		[[ ${x} == *.sh ]] && continue

		# unless we are running in verbose mode, don't display scripts
		# that aren't in any runlevels that we are examining
		if [[ ${verbose} -eq 0 ]] ; then
			local found_it=0
			for y in ${mylevels} ; do
				if [[ -L ${ROOT}etc/runlevels/${y}/${x} ]] ; then
					found_it=1
					break
				fi
			done
			[[ ${found_it} -eq 0 ]] && continue
		fi

		# ok, let's show this script already !
		printf "%20s | " ${x:0:19}
		for y in ${mylevels} ; do
			if [[ -L ${ROOT}etc/runlevels/${y}/${x} ]] ; then
				echo -n "${y} "
			else
				printf "%${#y}s " " "
			fi
		done
		echo ""
	done
}

check_is_root() {
	if [[ ${EUID} -ne 0 ]] ; then
		eerror "${argv0}: must be root to complete this operation" 1>&2
		exit 1
	fi
}

export ROOT=${ROOT%/}/
[[ ${ROOT} != "/" ]] && einfo "Working with files in root ${ROOT} ..."

verbose=0
quiet=0
action=""
opts=""
check_root=0

[[ ${RC_VERBOSE} == "yes" ]] && ((++verbose))

while [[ -n $* ]] ; do
	case "$1" in
	add|-a)
		check_root=1
		action="add"
		;;
	del|delete|-d)
		check_root=1
		action="del"
		;;
	show|-s)
		action="show"
		;;
	help|-h|--help)
		usage 0
		;;
	verbose|-v|--verbose)
		((++verbose))
		;;
	quiet|-q|--quiet)
		((++quiet))
		;;
	-*)
		echo -e "${argv0}: Unknown option $1\n" 1>&2
		usage 1
		;;
	*)
		opts="${opts} $1"
		;;
	esac
	shift
done

if [[ -z ${action} ]] ; then
	eerror "${argv0}: gimme something to do!" 1>&2
	usage 1
fi

[[ ${check_root} -eq 1 ]] && check_is_root
${action} ${opts}

# vim:ts=4
