#!/sbin/runscript # Copyright 1999-2006 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 trap ":" INT QUIT TSTP source /sbin/functions.sh umask 022 # void get_critical_services() # # Get critical services needed for bootup, and exports CRITICAL_SERVICES # 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="hostname" fi export CRITICAL_SERVICES return 0 } # void check_critical_services() # # Ensure that critical services are in the boot runlevel # check_critical_services() { local x 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 [[ ${argv1} = "sysinit" ]] then source "${svclib}"/sh/init.sh || { echo "Could not source init.sh !?" exit 1 } exit 0 fi # Sysinit ends here if [[ ${argv1} == "boot" ]] then setup_defaultlevels # $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}" fi # Ensure all critical services have are in the boot runlevel get_critical_services check_critical_services source "${svclib}/sh/rc-services.sh" 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 if [[ ${SOFTLEVEL} == "reboot" || ${SOFTLEVEL} == "shutdown" ]] ; then myscripts= 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 einfo "Device initiated services:${HILITE}${myscripts}${NORMAL}" 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 x dep needsme depservice local myservice="${1##*/}" service_stopped "${myservice}" && return 0 [[ -L ${svcdir}/softscripts.new/${service} ]] \ && return 0 if [[ ${SOFTLEVEL} != "reboot" \ && ${SOFTLEVEL} != "shutdown" ]] ; then service_coldplugged "${service}" && return 0 if net_service "${service}" ; then [[ -z ${OLDSOFTLEVEL} ]] \ || ! in_runlevel "${service}" "${OLDSOFTLEVEL}" \ && return 0 fi fi # Should not work for 'use' if [[ -z $(needsme "${myservice}") ]] ; then # Nothing depends on me stop_service "${myservice}" else # Something may depend on me needsme=0 for dep in $(needsme "${myservice}") ; do if [[ -L "${svcdir}/softscripts.new/${dep}" ]] ; then needsme=1 break fi done [[ ${needsme} -eq 0 ]] && stop_service "${myservice}" fi } # Stop services if [[ ${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 myservice="${1##*/}" for x in ${CRITICAL_SERVICES} ${LOGGER_SERVICE} ; do [[ ${myservice} == "${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 # 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 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 # 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 # Remove the cached CONSOLETYPE unset CONSOLETYPE # vim:ts=4