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

trap ":" INT QUIT TSTP
source /sbin/functions.sh
# Only source this when this is a livecd booting ...
[ -f /sbin/livecd-functions.sh ] && source /sbin/livecd-functions.sh
# Silly users
[[ -f /etc/conf.d/rc-extra ]] && source /etc/conf.d/rc-extra
umask 022

# Quick test to see if we can be interactive or not
if [[ ${RC_INTERACTIVE:-yes} == "yes" ]] ; then
	if tty -s && stty -a | grep -q " icanon" ; then
		RC_INTERACTIVE="yes"
	else
		RC_INTERACTIVE="no"
	fi
fi

try() {
	local errstr
	local retval=0
	
	if [ -c /dev/null ]; then
		errstr="$((eval $*) 2>&1 >/dev/null)"
	else
		errstr="$((eval $*) 2>&1)"
	fi
	retval=$?
	if [ "${retval}" -ne 0 ]
	then
		splash "critical" &

		echo -e "${ENDCOL}${NORMAL}[${BAD} oops ${NORMAL}]"
		echo
		eerror "The \"${1}\" command failed with error:"
		echo
		echo "${errstr#*: }"
		echo
		eerror "Since this is a critical task, startup cannot continue."
		echo
		sulogin ${CONSOLE}
		einfo "Unmounting filesystems"
		if [ -c /dev/null ]; then
			/bin/mount -a -o remount,ro &>/dev/null
		else
			/bin/mount -a -o remount,ro
		fi
		einfo "Rebooting"
		/sbin/reboot -f
	fi
	
	return ${retval}
}

# Check that $1 exists ...
check_statedir() {
	[ -z "$1" ] && return 0

	if [ ! -d "$1" ] ; then
		if ! mkdir -p "$1" &>/dev/null ; then
			splash "critical" &
			echo
			eerror "For Gentoo to function properly, \"$1\" needs to exist."
			if [[ ${RC_FORCE_AUTO} == "yes" ]] ; then
				eerror "Attempting to create \"$1\" for you ..."
				mount -o remount,rw /
				mkdir -p "$1"
			else
				eerror "Please mount your root partition read/write, and execute:"
				echo
				eerror "  # mkdir -p $1"
				echo; echo
				sulogin ${CONSOLE}
			fi
			einfo "Unmounting filesystems"
			/bin/mount -a -o remount,ro &>/dev/null
			einfo "Rebooting"
			/sbin/reboot -f
		fi
	fi

	return 0
}

# void noblock_read(var)
#
#   reads a line of input into var like regular read
#   but it does not block waiting for input
#
noblock_read() {
	local old_tty_settings="$(stty -g)"
	stty -icanon min 0 time 0
	read "$@"
	stty "${old_tty_settings}"
}

# bool user_want_interactive(void)
#
#   return 0 if user wants interactive mode
#
user_want_interactive() {
	[[ ${RC_INTERACTIVE} != "yes" ]] && return 1

	local user_input
	noblock_read user_input
	[[ ${user_input} == *"I"* || ${user_input} == *"i"* ]]
}

# void do_interactive
#
#   starts, skips, continues or drops to the shell
#   depending on user selection
#
do_interactive() {
	local service="$2"

	user_want_interactive && svcinteractive="yes"
	if [[ ${svcinteractive} != "yes" || ! -e "/etc/init.d/${service}" ]] ; then
		"$@"
		return $?
	fi

	local start_text="Start service"
	local skip_text="Skip service"
	local continue_text="Continue boot process"
	local shell_text="Exit to shell"
	
	echo
	echo "About to start the service ${service}"
	PS3="Enter your selection: "
	select action in "${start_text}" "${skip_text}"	"${continue_text}" \
		"${shell_text}"
	do
		case ${action} in
			"${start_text}") 
				"$@"
				break
				;;
			"${skip_text}")
				break
				;;
			"${continue_text}")
				svcinteractive="no"
				"$@"
				break
				;;
			"${shell_text}")
				echo
				sulogin "${CONSOLE}"
				;;
		esac
	done
}

get_critical_services() {
	local x=
	CRITICAL_SERVICES=
	
	if [ -f "/etc/runlevels/${BOOTLEVEL}/.critical" ]
	then
		for x in $(< /etc/runlevels/${BOOTLEVEL}/.critical)
		do
			CRITICAL_SERVICES="${CRITICAL_SERVICES} ${x##*/}"
		done
	else
		CRITICAL_SERVICES="checkroot modules checkfs localmount clock bootmisc"
	fi

	export CRITICAL_SERVICES

	return 0
}

check_critical_services() {
	local x

	# Ensure that critical services are in the boot runlevel
	for x in ${CRITICAL_SERVICES} ; do
		if [[ ! -L "/etc/runlevels/${BOOTLEVEL}/${x}" ]] ; then
			ewarn "WARNING:  Adding critical service ${x} to the ${BOOTLEVEL} runlevel"
			ln -snf "/etc/init.d/${x}" "/etc/runlevels/${BOOTLEVEL}/${x}"
		fi
	done
}

# Save $1
argv1="$1"

# First time boot stuff goes here.  Note that 'sysinit' is an internal runlevel
# used to bring up local filesystems, and should not be started with /sbin/rc
# directly ...
if [[ ( ${RUNLEVEL} == "S" || ${RUNLEVEL} == "1" ) && ${argv1} = "sysinit" ]]
then
	# Setup initial $PATH just in case
	PATH="/bin:/sbin:/usr/bin:/usr/sbin:${PATH}"

	# Help users recover their systems incase these go missing
	[ -c /dev/null ] && dev_null=1 || dev_null=0
	[ -c /dev/console ] && dev_console=1 || dev_console=0

	# Set the console loglevel to 1 for a cleaner boot
	# the logger should anyhow dump the ring-0 buffer at start to the
	# logs, and that with dmesg can be used to check for problems
	${RC_DMESG_LEVEL+/bin/dmesg -n ${RC_DMESG_LEVEL}}

	echo
	echo -e "${GOOD}Gentoo Linux${GENTOO_VERS}; ${BRACKET}http://www.gentoo.org/${NORMAL}"
	echo -e " Copyright 1999-2009 Gentoo Foundation; Distributed under the GPLv2"
	echo
	if [[ ${RC_INTERACTIVE} == "yes" ]] ; then
		echo -e "Press ${GOOD}I${NORMAL} to enter interactive boot mode"
		echo
    fi
	check_statedir /proc

	# make sure /proc/ isn't full of crap #291916
	do_mnt=1
	if is_mounted /proc ; then
		do_mnt=0
	elif ! is_clean /proc ; then
		ewarn "You have crap in your /proc/; please clean it; see #291916"
	fi

	if [[ ${do_mnt} == 1 ]] ; then
		ebegin "Mounting proc at /proc"
		if [[ ${RC_USE_FSTAB} = "yes" ]] ; then
			mntcmd=$(get_mount_fstab /proc)
		else
			unset mntcmd
		fi
		try mount -n ${mntcmd:--t proc proc /proc -o noexec,nosuid,nodev}
		eend $?
	else
		einfo "Skipping mount of /proc as it's already mounted"
	fi

	# Start profiling init now we have /proc
	profiling start

	# Read off the kernel commandline to see if there's any special settings
	# especially check to see if we need to set the  CDBOOT environment variable
	# Note: /proc MUST be mounted
	[ -f /sbin/livecd-functions.sh ] && livecd_read_commandline

	if [ "$(get_KV)" -ge "$(KV_to_int '2.6.0')" ] ; then
		if [[ -d /sys ]] ; then
			# make sure /sys/ isn't full of crap #291916
			do_mnt=1
			if is_mounted /sys ; then
				do_mnt=0
			elif ! is_clean /sys ; then
				ewarn "You have crap in your /sys/; please clean it; see #291916"
			fi

			if [[ ${do_mnt} == 1 ]] ; then
				ebegin "Mounting sysfs at /sys"
				if [[ ${RC_USE_FSTAB} = "yes" ]] ; then
					mntcmd=$(get_mount_fstab /sys)
				else
					unset mntcmd
				fi
				try mount -n ${mntcmd:--t sysfs sysfs /sys -o noexec,nosuid,nodev}
				eend $?
			else
				einfo "Skipping mount of /sys as it's already mounted"
			fi
		else
			ewarn "No /sys to mount sysfs needed in 2.6 and later kernels!"
		fi
	fi

	check_statedir /dev

	# Fix weird bug where there is a /dev/.devfsd in a unmounted /dev
	devfs_automounted="no"
	if [ -e "/dev/.devfsd" ]
	then
		mymounts="$(awk '($3 == "devfs") { print "yes"; exit 0 }' /proc/mounts)"
		if [ "${mymounts}" != "yes" ]
		then
			rm -f /dev/.devfsd
		else
			devfs_automounted="yes"
		fi
	fi

	# Try to figure out how the user wants /dev handled
	#  - check $RC_DEVICES from /etc/conf.d/rc
	#  - check boot parameters
	#  - make sure the required binaries exist
	#  - make sure the kernel has support
	if [ "${RC_DEVICES}" = "static" ]
	then
		ebegin "Using existing device nodes in /dev"
		eend 0
	else
		fellback_to_devfs="no"
		case "${RC_DEVICES}" in
			devfs)	devfs="yes"
					udev="no"
					;;
			udev)	devfs="yes"
					udev="yes"
					fellback_to_devfs="yes"
					;;
			auto|*)	devfs="yes"
					udev="yes"
					;;
		esac

		# Check udev prerequisites and kernel params
		if [ "${udev}" = "yes" ]
		then
			if get_bootparam "noudev" || ! has_addon udev-start.sh || \
			   [ ${devfs_automounted} = "yes" ] || \
			   [ "$(get_KV)" -lt "$(KV_to_int '2.6.0')" ]
			then
				udev="no"
			fi
		fi

		# Check devfs prerequisites and kernel params
		if [ "${devfs}" = "yes" ]
		then
			if get_bootparam "nodevfs" || [ "${udev}" = "yes" ] || \
			   ! has_addon devfs-start.sh
			then
				devfs="no"
			fi
		fi

		# Actually start setting up /dev now
		if [[ ${udev} == "yes" ]] ; then
			start_addon udev

		# With devfs, /dev can be mounted by the kernel ...
		elif [[ ${devfs} == "yes" ]] ; then
			start_addon devfs

			# Did the user want udev in the config file but for 
			# some reason, udev support didnt work out ?
			if [[ ${fellback_to_devfs} == "yes" ]] ; then
				ewarn "You wanted udev but support for it was not available!"
				ewarn "Please review your system after it's booted!"
			fi
		fi

		# OK, if we got here, things are probably not right :)
		if [[ ${devfs} == "no" && ${udev} == "no" ]] ; then
			echo
			einfo "The Gentoo Linux system initialization scripts have detected that"
			einfo "your system does not support UDEV.  Since Gentoo Linux has been"
			einfo "designed with dynamic /dev in mind, it is highly suggested that you"
			einfo "emerge sys-fs/udev and configure your system to use it."
			einfo "Please read the Gentoo Handbook for more information!"
			echo
			einfo "    http://www.gentoo.org/doc/en/handbook/"
			echo
			einfo "Thanks for using Gentoo! :)"
			echo
			read -t 15 -p "(hit Enter to continue or wait 15 seconds ...)"
		fi
	fi

	# From linux-2.5.68 we need to mount /dev/pts again ...
	if [ "$(get_KV)" -ge "$(KV_to_int '2.5.68')" ]
	then
		have_devpts="$(awk '($2 == "devpts") { print "yes"; exit 0 }' /proc/filesystems)"

		if [ "${have_devpts}" = "yes" ]
		then
			# Only try to create /dev/pts if we have /dev mounted dynamically,
			# else it might fail as / might be still mounted readonly.
			if [ ! -d /dev/pts ] && \
			   [ "${devfs}" = "yes" -o "${udev}" = "yes" ]
			then
				# Make sure we have /dev/pts
				mkdir -p /dev/pts &>/dev/null || \
					ewarn "Could not create /dev/pts!"
			fi

			if [[ -d /dev/pts ]] ; then
				if ! is_mounted /dev/pts ; then
					ebegin "Mounting devpts at /dev/pts"
					if [[ ${RC_USE_FSTAB} = "yes" ]] ; then
						mntcmd=$(get_mount_fstab /dev/pts)
					else
						unset mntcmd
					fi
					try mount -n ${mntcmd:--t devpts devpts /dev/pts -o gid=5,mode=0620,noexec,nosuid}
					eend $?
				else
					einfo "Skipping mount of /dev/pts as it's already mounted"
				fi
			fi
		fi
	fi

	# Start logging console output since we have all /dev stuff setup
	bootlog start

	start_critical_service() {
		local service="$1"
		(
		local retval=
		# Needed for some addons like dm-crypt that starts in critical services
		local myservice="${service}"

		profiling name "/etc/init.d/${service} start"
		splash "svc_start" "${service}"
		
		source "/etc/init.d/${service}"
		retval=$?
		if [[ ${retval} -ne 0 ]] ; then
			eerror "Failed to source /etc/init.d/${service}"
			return "${retval}"
		fi

		local conf="$(add_suffix /etc/conf.d/${service})"
		[[ -e ${conf} ]] && source "${conf}"
		conf="$(add_suffix /etc/rc.conf)"
		[[ -e ${conf} ]] && source "${conf}"

		start
		)
		
		if [[ $? == "0" ]] ; then
			splash "svc_started" "${service}" "0"
			return 0
		fi

		eerror "Failed to start /etc/init.d/${service}"
		splash "critical" &>/dev/null &
		echo
		eerror "One or more critical startup scripts failed to start!"
		eerror "Please correct this, and reboot ..."
		echo; echo
		sulogin ${CONSOLE}
		einfo "Unmounting filesystems"
		/bin/mount -a -o remount,ro &>/dev/null
		einfo "Rebooting"
		/sbin/reboot -f
	}

	# $BOOT can be used by rc-scripts to test if it is the first time
	# the 'boot' runlevel is executed.  Now also needed by some stuff in
	# the 'sysinit' runlevel ...
	export BOOT="yes"

	# We set the forced softlevel from the kernel command line
	# It needs to be run right after proc is mounted for the
	# boot runlevel
	setup_defaultlevels

	# We first try to find a locally defined list of critical services
	# for a particular runlevel.  If we cannot find it, we use the
	# defaults.
	get_critical_services

	splash "rc_init" "${argv1}"

	# Start checkroot and modules before we load volumes
	export START_CRITICAL="yes"
	for x in checkroot modules ; do
		[[ " ${CRITICAL_SERVICES} " != *" ${x} "* ]] && continue
		start_critical_service "${x}"
	done
	
	# Start RAID/LVM/EVMS/DM volumes for /usr, /var, etc.
	for x in ${RC_VOLUME_ORDER} ; do
		start_addon "${x}"
	done

	# We do not want to break compatibility, so we do not fully integrate
	# these into /sbin/rc, but rather start them by hand ...
	for x in ${CRITICAL_SERVICES} ; do
		[[ ${x} == "checkroot" || ${x} == "modules" ]] && continue
		start_critical_service "${x}"
	done

	unset START_CRITICAL

	# /var/log should be writable now, so starting saving the boot output
	bootlog sync

	# Check that $svcdir exists ...
	check_statedir "${svcdir}"

	# Should we use tmpfs/ramfs/ramdisk for caching dependency and 
	# general initscript data?  Note that the 'gentoo=<fs>' kernel 
	# option should override any other setting ...
	for fs in tmpfs ramfs ramdisk
	do
		if get_bootparam "${fs}"
		then
			svcmount="yes"
			svcfstype="${fs}"
			break
		fi
	done
	if [ "${svcmount}" = "yes" ]
	then
		ebegin "Mounting ${svcfstype} at ${svcdir}"
		case "${svcfstype}" in
		ramfs)
			try mount -t ramfs svcdir "${svcdir}" \
				-o rw,mode=0755,size="${svcsize}"k
			;;
		ramdisk)
			try dd if=/dev/zero of=/dev/ram0 bs=1k count="${svcsize}"
			try /sbin/mke2fs -i 1024 -vm0 /dev/ram0 "${svcsize}"
			try mount -t ext2 /dev/ram0 "${svcdir}" -o rw
			;;
		tmpfs|*)
			try mount -t tmpfs svcdir "${svcdir}" \
				-o rw,mode=0755,size="${svcsize}"k
			;;
		esac
		eend 0
	fi

	# If booting off CD, we want to update inittab before setting the runlevel
	if [ -f "/sbin/livecd-functions.sh" -a -n "${CDBOOT}" ]
	then
		ebegin "Updating inittab"
		livecd_fix_inittab
		eend $?
		/sbin/telinit q &>/dev/null
	fi

	# Clear $svcdir from stale entries, but leave the caches around, as it
	# should help speed things up a bit
	rm -rf $(ls -d1 "${svcdir:-/lib/rcscripts/init.d}/"* 2>/dev/null | \
	         grep -ve '\(depcache\|deptree\|envcache\)')

	echo "sysinit" > "${svcdir}/softlevel"

	# Ensure all critical services have are in the boot runlevel
	check_critical_services

	# Update the dependency cache
	/sbin/depscan.sh

	# Now that the dependency cache are up to date, make sure these
	# are marked as started ...
	(
		profiling name "mark started"

		# Needed for mark_service_started()
		source "${svclib}/sh/rc-services.sh"

		for x in ${CRITICAL_SERVICES}
		do
			mark_service_started "${x}"
		done
	)

	# If the user's /dev/null or /dev/console are missing, we 
	# should help them out and explain how to rectify the situation
	if [ ${dev_null} -eq 0 -o ${dev_console} -eq 0 ] \
	    && [ -e /usr/share/baselayout/issue.devfix ]
	then
		# Backup current /etc/issue
		if [ -e /etc/issue -a ! -e /etc/issue.devfix ]
		then
			mv /etc/issue /etc/issue.devfix
		fi

		cp /usr/share/baselayout/issue.devfix /etc/issue
	fi

	# Setup login records ... this has to be done here because when 
	# we exit this runlevel, init will write a boot record to utmp
	# If /var/run is readonly, then print a warning, not errors
	if touch /var/run/utmp 2>/dev/null
	then
		> /var/run/utmp
		touch /var/log/wtmp
		chgrp utmp /var/run/utmp /var/log/wtmp
		chmod 0664 /var/run/utmp /var/log/wtmp
		# Remove /var/run/utmpx (bug from the past)
		rm -f /var/run/utmpx
	else
		ewarn "Skipping /var/run/utmp initialization (ro root?)"
	fi

	# Check and save if the user wants interactive
	user_want_interactive && svcinteractive="yes"
	echo "${svcinteractive:-no}" > "${svcdir}/interactive"

	# sysinit is now done, so allow init scripts to run normally
	[[ -e /dev/.rcsysinit ]] && rm -f /dev/.rcsysinit

	# All done logging
	bootlog quit

	exit 0
fi # Sysinit ends here

if [[ ( ${RUNLEVEL} == "S" || ${RUNLEVEL} == "1" ) && ${argv1} == "boot" ]]
then
	setup_defaultlevels

	if [ -n "${DEFAULTLEVEL}" -a "${DEFAULTLEVEL}" != "default" ]
	then
		# Setup our default runlevel runlevel that will be run
		# the first time /sbin/rc is called with argv1 != sysinit|boot
		echo "${DEFAULTLEVEL}" > "${svcdir}/ksoftlevel"
	fi

	# $BOOT can be used by rc-scripts to test if it is the first time
	# the 'boot' runlevel is executed
	export BOOT="yes"

	# We reset argv1 to the bootlevel given on the kernel command line
	# if there is one
	argv1="${BOOTLEVEL}"
	
elif [[ ${RUNLEVEL} != "S" && ${RUNLEVEL} != "1" && -e ${svcdir}/ksoftlevel ]]
then
	argv1="$(< ${svcdir}/ksoftlevel)"
	rm -f "${svcdir}/ksoftlevel"
elif [[ ${RUNLEVEL} != "S" && ${RUNLEVEL} != "1" && ${argv1} == "single" ]]
then
	/sbin/telinit S
	exit 0
elif [[ ( ${RUNLEVEL} == "S" || ${RUNLEVEL} == "1" ) && ${argv1} != "single" ]]
then
	level=$(awk -v level="${argv1}" '
		$2 == level {
			split($0, fields, ":")
			print fields[2]
			exit
		}' /etc/inittab 2>/dev/null)
	[[ -z ${level} ]] && level=3
	/sbin/telinit "${level}"
	exit 0
fi

# Ensure that critical services are in the boot runlevel
get_critical_services
check_critical_services

source "${svclib}/sh/rc-services.sh"
[[ -e "${svcdir}/interactive" ]] \
	&& svcinteractive="$(<${svcdir}/interactive)"

if [ -f "${svcdir}/softlevel" ]
then
	# Set OLDSOFTLEVEL if we had a valid SOFTLEVEL
	export OLDSOFTLEVEL="$(< ${svcdir}/softlevel)"
else
	export OLDSOFTLEVEL=
fi
	
if [ -z "${argv1}" ]
then
	if [ -f "${svcdir}/softlevel" ]
	then
		export SOFTLEVEL="$(< ${svcdir}/softlevel)"
	else
		export SOFTLEVEL="${BOOTLEVEL}"
	fi
else
	export SOFTLEVEL="${argv1}"
fi

if [ ! -f "${svcdir}/softlevel" ]
then
	echo "${SOFTLEVEL}" > "${svcdir}/softlevel"
fi

# For keeping a list of services that fails during boot/halt
if [ ! -d "${svcdir}/failed" ]
then
	mkdir -p -m 0755 "${svcdir}/failed"
else
	rm -rf "${svcdir}"/failed/*
fi

splash "rc_init" "${argv1}"


if [ "${SOFTLEVEL}" = "reboot" -o "${SOFTLEVEL}" = "shutdown" ]
then
	myscripts=

elif [ "${SOFTLEVEL}" = "single" ]
then

	myscripts="${CRITICAL_SERVICES}"
	
elif [ ! -d "/etc/runlevels/${SOFTLEVEL}" ]
then
	eerror "ERROR:  runlevel ${SOFTLEVEL} does not exist; exiting ..."
	exit 1
else
	myscripts=
	if [ "${SOFTLEVEL}" != "${BOOTLEVEL}" ]
	then
		# Normal runlevels *include* boot scripts
		mylevels="$(dolisting "/etc/runlevels/${SOFTLEVEL}/")"
		mylevels="${mylevels} $(dolisting /etc/runlevels/${BOOTLEVEL}/)"
	else
		# Non-normal runlevels don't include boot scripts as default
		mylevels="$(dolisting "/etc/runlevels/${SOFTLEVEL}/")"

		# As we're in the bootlevel, add any services that failed due
		# to /dev/.rcsysinit existing to the list
		if [[ -d /dev/.rcboot ]] ; then
			COLDPLUG_SERVICES=
			for x in $(dolisting /dev/.rcboot/) ; do
				[[ -L ${x} ]] && COLDPLUG_SERVICES="${COLDPLUG_SERVICES} ${x##*/}"
			done
			for x in ${COLDPLUG_SERVICES} ; do
				if [[ ! -e /etc/runlevels/"${BOOTLEVEL}"/"${x}" \
				&& ! -e /etc/runlevels/"${DEFAULTLEVEL}"/"${x}" ]] ; then
					myscripts="${myscripts} ${x}"
					mark_service_coldplugged "${x}"
				fi
			done
			if [[ -n ${myscripts} ]] ; then
				einfo "Device initiated services:${HILITE}${myscripts}${NORMAL}"
			fi
			rm -rf /dev/.rcboot
		fi
	fi
	
	for x in ${mylevels}
	do
		[ -L "${x}" ] && myscripts="${myscripts} ${x##*/}"
	done
fi

# The softscripts dir contains all scripts that belong to the
# runlevel specified in ${svcdir}/softlevel
# It needs to be a new directory, else when stopping the services
# and the old directory is not intact, things get broken

mkdir -p -m 0755 "${svcdir}/softscripts.new"

for x in ${myscripts} ; do
	if [[ ! -e /etc/init.d/${x} ]] ; then
		ewarn "WARNING:  /etc/init.d/${x} missing; skipping ..."
		continue
	fi
	# The -f eliminates a warning if the symlink already exists,
	# which can happen if a service is in both the boot level and
	# the current "normal" runlevel
	ln -snf "/etc/init.d/${x}" "${svcdir}/softscripts.new/${x}"
done

get_stop_services() {
	local x list

	for x in $(dolisting "${svcdir}/inactive/") \
		$(dolisting "${svcdir}/started/") ; do
		list="${list} ${x##*/}"
	done

	reverse_list $(trace_dependencies ${list})
}

dep_stop() {
	local dep needsme service="${1##*/}"

	service_stopped "${service}" && return 0
	
	# Candidate for zapping ?
	[[ -L "${svcdir}/softscripts.new/${service}" ]] \
		&& return 0

	if [[ ${SOFTLEVEL} != "reboot" \
	      && ${SOFTLEVEL} != "shutdown" \
	      && ${SOFTLEVEL} != "single" ]] ; then
	      	service_coldplugged "${service}" && return 0
		if net_service "${service}" ; then
			[[ -z ${OLDSOFTLEVEL} ]] \
			|| ! in_runlevel "${service}" "${OLDSOFTLEVEL}" \
				&& return 0
		fi
	fi

	# Something may depend on me
	needsme=0
	for dep in $(needsme "${service}") ; do
		if [[ -L "${svcdir}/softscripts.new/${dep}" ]] \
		|| service_coldplugged "${dep}" ; then
			# This dep is valid
			needsme=1
			break
		fi
	done
	[[ ${needsme} -eq 0 ]] && stop_service "${service}"
}

# Stop services
if [[ ${SOFTLEVEL} != "single" && \
      ${SOFTLEVEL} != "reboot" && \
      ${SOFTLEVEL} != "shutdown" ]]
then
	for i in $(get_stop_services) ; do
		dep_stop "${i}"
	done

	# Wait for any services that may still be stopping ...
	[ "${RC_PARALLEL_STARTUP}" = "yes" ] && wait
else
	get_critical_services

	is_critical_service() {
		local x
		local service=${1##*/}

		for x in ${CRITICAL_SERVICES} ${LOGGER_SERVICE} ; do
			[[ ${service} == "${x}" ]] && return 0
		done

		return 1
	}

	# First stop non critical services
	for i in $(get_stop_services) ; do
		is_critical_service "${i}" || dep_stop "${i}"
	done

	# Wait for any services that may still be stopping ...
	[ "${RC_PARALLEL_STARTUP}" = "yes" ] && wait

	export STOP_CRITICAL="yes"
	# Now stop the rest
	for i in $(get_stop_services) ; do
		dep_stop "${i}"
	done
	unset STOP_CRITICAL
fi

# Only change softlevel AFTER all the services have been stopped,
# else they will not get the depend's right (wrong SOFTLEVEL)

echo "${SOFTLEVEL}" > "${svcdir}/softlevel"

if [[ ${SOFTLEVEL} == "reboot" || ${SOFTLEVEL} == "shutdown" ]] ; then
	# Clear $svcdir from stale entries, but leave the caches around, as it
	# should help speed things up a bit
	rm -rf $(ls -d1 "${svcdir}/"* 2>/dev/null | \
	         grep -ve '\(depcache\|deptree\|envcache\)')

	# Call halt.sh with LC_ALL=C so that bash doesn't load any locales
	# which could interfere with unmounting /usr
	LC_ALL=C exec /etc/init.d/halt.sh "${SOFTLEVEL}"
	
	# Should never get here
	exit 0
fi

if [[ ${SOFTLEVEL} == "single" ]] ; then
	rm -rf "${svcdir}/softscripts.new"
	[[ ${RUNLEVEL} == "S" ]] && sulogin ${CONSOLE}
	exit 0
fi

# Move the old softscritps directory to a different one
# and make the new softscripts directory the current

mv -f "${svcdir}/softscripts" "${svcdir}/softscripts.old"
mv -f "${svcdir}/softscripts.new" "${svcdir}/softscripts"

get_start_services() {
	local x list

	get_critical_services
	list=${CRITICAL_SERVICES}

	[[ -n ${LOGGER_SERVICE} && \
	   -L ${svcdir}/softscripts/${LOGGER_SERVICE} ]] && \
		list="${list} ${LOGGER_SERVICE}"

	for x in $(dolisting "${svcdir}/softscripts/") ; do
		list="${list} ${x##*/}"
	done

	trace_dependencies ${list}
}

# Start scripts
for i in $(get_start_services) ; do
	if service_stopped "${i}" ; then
		do_interactive start_service "${i}"
	fi
done

# Wait for any services that may still be running ...
[[ ${RC_PARALLEL_STARTUP} == "yes" ]] && wait

# Clean the old runlevel
rm -rf "${svcdir}/softscripts.old" &>/dev/null

# Depends gets nuked, so update them
# (this problem should be solved now, but i think it will be a good idea
#  to recreate the deps after a change in runlevel)

#/sbin/depscan.sh &>/dev/null

# We want devfsd running after a change of runlevel (this is mostly if we return
# from runlevel 'single')
if [ -z "`ps --no-heading -C 'devfsd'`" -a \
     -n "`gawk '/\/dev devfs/ { print }' /proc/mounts 2>/dev/null`" ]
then
	if [ "${RC_DEVFSD_STARTUP}" != "no" ]
	then
		/sbin/devfsd /dev &>/dev/null
	fi
fi

# Runlevel end, so clear stale fail list
rm -rf "${svcdir}/failed" &>/dev/null

# If we were in the boot runlevel, it is done now ...
if [[ -n ${BOOT} ]]; then
	unset BOOT
	# Save our interactive mode into the default runlevel
	user_want_interactive && svcinteractive="yes"
	echo "${svcinteractive}" > "${svcdir}/interactive"
else
	# As we're not boot, we remove the interactive file
	[[ -e "${svcdir}/interactive" ]] && rm -f "${svcdir}/interactive"
fi

# Remove the cached CONSOLETYPE
unset CONSOLETYPE

splash "rc_exit"

# vim:ts=4
