#!/bin/bash
# Copyright 1999-2002 Gentoo Technologies, Inc.
# Distributed under the terms of the GNU General Public License v2
# $Header: /home/cvsroot/gentoo-src/rc-scripts/sbin/rc,v 1.37 2002/11/27 21:32:40 azarah Exp $


trap ":" INT QUIT TSTP
source /sbin/functions.sh
umask 022

try() {
	local retval=0
	# this works fine in test, but real life booting, fails for mounting /proc
	# for instance, if we only check $?, thus we need to [ -n "${errstr}" ]
	# as well
	local errstr
	errstr="$((eval $*) 2>&1 >/dev/null)"
	retval=$?
	if [ "${retval}" -ne 0 ] || \
	   ([ -n "$(echo $* | egrep 'mount')" -a -n "${errstr}" ])
	then
		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
		/sbin/sulogin ${CONSOLE}
		/sbin/reboot -f
	fi
	return ${retval}
}

# save $1
argv1="$1"

# first time boot stuff goes here
if [ "${RUNLEVEL}" = "S" -a "${argv1}" = "boot" ]
then
	# setup initial $PATH just in case
	PATH="/bin:/sbin:/usr/bin:/usr/sbin:${PATH}"

	echo
	echo -e "${GOOD}Gentoo Linux${GENTOO_VERS}; \e[34;01mhttp://www.gentoo.org/${NORMAL}"
	echo -e " Copyright 2001-2002 Gentoo Technologies, Inc.; Distributed under the GPL"
	echo

	ebegin "Mounting /proc"; \
	try mount -n /proc; \
	eend $?

	# check if the user disabled devfs
	devfs="yes"
	get_bootparam "nodevfs"
	if [ "$?" -eq 0 ]
	then
		devfs="no"
	fi
	
	# fix weird bug where there is a /dev/.devfsd in a unmounted /dev
	mymounts="$(awk '$3 ~ "devfs" { print $0 }' /proc/mounts)"
	if [ -e /dev/.devfsd -a -z "${mymounts}" ]
	then
		rm -f /dev/.devfsd &>/dev/null
	fi

	# with the new way, /dev can be mounted by the kernel ...
	if [ "${devfs}" = "yes" -a ! -e /dev/.devfsd ]
	then
		mymounts="$(awk '$2 ~ "devfs" { print $0 }' /proc/filesystems)"
		# is devfs support compiled in?
		if [ -n "${mymounts}" ]
		then
			ebegin "Mounting devfs at /dev"; \
			try mount -n -t devfs none /dev; \
			eend $?
		else
			clear
			echo
			einfo "The Gentoo Linux system initialization scripts have detected that your"
			einfo "kernel has been compiled without DEVFS support.  Because Gentoo Linux"
			einfo "has been designed to work with DEVFS, it is required that you compile"
			einfo "support for it into your kernel.  Please read the 'Gentoo Linux from"
			einfo "source (build) CD Installation Guide' at:"
			echo
			einfo "    http://www.gentoo.org/doc/build.html"
			echo
			einfo "for more information on how to do this."
			echo
			read -t 15 -p "(hit Enter to continue or wait 15 seconds...)"
		fi
	fi

	# need devfsd running now so that /dev/ram0 exists if we need it
	mymounts="$(cat /proc/mounts)"
	if [ "${devfs}" = "yes" -a -e /dev/.devfsd -a \
	     "${mymounts/devfs//}" != "${mymounts}" ]
	then
		ebegin "Starting devfsd"
		/sbin/devfsd /dev &>/dev/null
		eend $?
	fi

	if [ ! -d ${svcdir} ]
	then
		echo
		eerror "For Gentoo Linux to function properly, \"${svcdir}\" need to exist."
		eerror "Please mount your root partition read/write, and execute:"
		echo
		eerror "  # mkdir -p ${svcdir}"
		echo
		echo
		/sbin/sulogin ${CONSOLE}
		mount -a -o remount,ro &>/dev/null
		/sbin/reboot -f
	fi
	
	# mount either a ramdisk or tmpfs and do dep scan
	
	# should we use tmpfs or a ramdisk ?
	if ! get_bootparam "notmpfs" && \
	   ([ "${svcfstype}" = "tmpfs" -o "${svcfstype}" != "ramfs" ])
	then
		ebegin "Mounting tmpfs at ${svcdir}"; \
		try mount -n -t tmpfs tmpfs ${svcdir} \
			-o rw,mode=0644,size=${svcsize}k; \
		eend 0
	else
		ebegin "Mounting ramdisk 0 at ${svcdir}"; \
		try dd if=/dev/zero of=/dev/ram0 bs=1k count=${svcsize}; \
		try /sbin/mke2fs -i 1024 -vm0 /dev/ram0 ${svcsize}; \
		try mount -n -t ext2 /dev/ram0 ${svcdir} -o rw; \
		eend 0
	fi

	if ! get_bootparam "notmpfs" && get_bootparam "ngpt"
	then
		# POSIX shared memory support
		ebegin "Mounting POSIX shared memory"
		mkdir -p /dev/shm
		try mount -n -t tmpfs tmpfs /dev/shm
		eend $?

		# NGPT support (http://www-124.ibm.com/developerworks/oss/pthreads/)
		if [ -x /usr/bin/ngptinit ]
		then
			ebegin "Initializing NGPT"
			/usr/bin/ngptinit &> /dev/null || :
			eend $?
		fi
	fi
	
	/sbin/depscan.sh

	# Saving the kernel attributed hostname to a file for future
	# initialisation selection: see /etc/init.d/switch.
	get_bootparam "adelie" && cat /proc/sys/kernel/hostname > ${svcdir}/hostname

	get_bootparam "adelie" && einfo "Server/Node low-level initialisation..."
	if checkserver
	then
		get_bootparam "adelie" && einfo "Server detected."
		
		# swap needs to be activated *after* devfs has been mounted and *after*
		# devfsd has been started, so that the fstab can be properly parsed
		# and only if the server is initialized
		ebegin "Activating swap"
		/sbin/swapon -a &>/dev/null
		eend 0
	else
		#
		# Low-level Node Initialisation
		#
		einfo "Node detected."
		ebegin "Importing local userspace on node"
		
		try mount -t tmpfs none ${shmdir}
		
		for DIR in /etc /var /root;
		do

			if grep -q -v "^${DIR}[[:space:]]" /etc/exports
			then
				mount -o nolock -n server:${DIR} ${DIR}
			fi
	
			if [ -e /etc/conf.d/exclude/${DIR} ] 
			then
				find ${DIR} -type d | grep -v -f /etc/conf.d/exclude/${DIR} > ${shmdir}/${DIR}.lst
			else
				find ${DIR} -type d > ${shmdir}/${DIR}.lst
			fi
			
			for SUBDIR in $(cat ${shmdir}/${DIR}.lst); 
			do
				mkdir ${shmdir}/${SUBDIR}
				chmod --reference=${SUBDIR} ${shmdir}/${SUBDIR}
				cp -dp ${SUBDIR}/* ${shmdir}/${SUBDIR} &>/dev/null
			done
			
			if [ -e /etc/conf.d/exclude/${DIR} ]
			then
				for EMPTYDIR in $(cat /etc/conf.d/exclude/${DIR});
				do
					mkdir ${shmdir}/${EMPTYDIR}
					chmod --reference=${SUBDIR} ${shmdir}/${SUBDIR}
				done
			fi

			umount -n ${DIR} > /dev/null
			mount -n -o bind ${shmdir}/${DIR} ${DIR}
		done
		
		mkdir ${shmdir}/tmp
		chmod 0777 ${shmdir}/tmp
		mount -n -o bind ${shmdir}/tmp /tmp
		
		cat /proc/mounts > /etc/mtab
		
		cp -f /etc/inittab.node /etc/inittab
		[ -e /etc/fstab.node ] && cp -f /etc/fstab.node /etc/fstab
		killall -1 init
		
		eend 0
	fi

	# 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
	
	/bin/dmesg -n 1

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

if [ -z "${argv1}" ]
then
	if [ -f ${svcdir}/softlevel ]
	then
		export SOFTLEVEL="$(cat ${svcdir}/softlevel)"
	else
		export SOFTLEVEL="boot"
	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
	install -d -m0755 ${svcdir}/failed
else
	rm -rf ${svcdir}/failed/*
fi

if [ "${SOFTLEVEL}" = "reboot" -o "${SOFTLEVEL}" = "shutdown" ]
then
	myscripts=""
elif [ ! -d /etc/runlevels/${SOFTLEVEL} ]
then
	eerror "ERROR:  runlevel ${SOFTLEVEL} does not exist; exiting..."
	exit 1
else
	myscripts=""
	if [ "${SOFTLEVEL}" != "boot" ]
	then
		# normal runlevels *include* boot scripts
		mylevels="$(dolisting /etc/runlevels/${SOFTLEVEL}/)"
		mylevels="${mylevels} $(dolisting /etc/runlevels/boot/)"
	else
		# non-normal runlevels don't include boot scripts as default
		mylevels="$(dolisting /etc/runlevels/${SOFTLEVEL}/)"
	fi
	for x in ${mylevels}
	do
		if [ -L ${x} ]
		then
			myscripts="${myscripts} ${x##*/}"
		fi
	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

install -d -m0755 ${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 -sf /etc/init.d/${x} ${svcdir}/softscripts.new/${x}
done

dep_stop() {
	local x=""
	local needsme=""
	local myservice=""
	local depservice=""
	[ ! -L $1 ] && continue
	if [ ! -e $1 ]
	then
		# remove dud symlinks
		rm $1
		continue
	fi
	myservice="${1##*/}"
	
	if [ ! -L ${svcdir}/softscripts.new/${myservice} ]
	then
		# candidate for zapping

		# should not work for 'use'
		if [ ! -d ${svcdir}/need/${myservice} ]
		then
			# nothing depends on me
			if [ -L ${svcdir}/started/${myservice} ]
			then
				$1 stop
			fi
		else
			# something may depend on me
			needsme=0
			for dep in $(dolisting ${svcdir}/need/${myservice}/)
			do
				if [ -L ${svcdir}/softscripts.new/${dep##*/} -a -e ${dep} ]
				then
					# this dep is valid
					needsme=1
					break
				fi
			done
			if [ "${needsme}" -eq 0 ]
			then
				if [ -L ${svcdir}/started/${myservice} ]
				then
					$1 stop
				fi
			fi
		fi
	fi
}

# stop services
for i in $(dolisting ${svcdir}/started/)
do
	dep_stop ${i}
done

# 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" -o "${SOFTLEVEL}" = "shutdown" ]
then
	source /sbin/functions.sh
	source /etc/init.d/halt.sh
	if [ "${SOFTLEVEL}" = "reboot" ]
	then
		source /etc/init.d/reboot.sh 
	else
		source /etc/init.d/shutdown.sh
	fi
	# should never get here
	exit 0
fi

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

mv ${svcdir}/softscripts ${svcdir}/softscripts.old &>/dev/null
mv ${svcdir}/softscripts.new ${svcdir}/softscripts &>/dev/null

dep_start() {
	local x=""
	local myservice=""
	local depservice=""
	if [ ! -L $1 ]
	then
		continue
	fi
	# only start a script if it isn't already running
	myservice="${1##*/}"
	if [ ! -L ${svcdir}/started/${myservice} ]
	then
		$1 start
	fi
}

# start scripts
for i in $(dolisting ${svcdir}/softscripts/)
do
	dep_start ${i}
done

# 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 -A | egrep 'devfsd')" -a \
     -n "$(cat /proc/mounts | egrep '/dev devfs')" ]
then
	/sbin/devfsd /dev &>/dev/null
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 ...
[ -n "${BOOT}" ] && unset BOOT


# vim:ts=4
