#!/sbin/runscript # Copyright 1999-2005 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 } # Save $1 argv1=$1 # we need this to prevent a warning below [[ ! -e ${svcdir}/softlevel ]] && touch ${svcdir}/softlevel # 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" || ( ${argv1} = "boot" && "$(<${svcdir}/softlevel)" != "sysinit" ) ]] then source "${svclib}"/sh/init.sh || { echo "Could not source init.sh !?" exit 1 } [[ ${argv1} = "boot" ]] || 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 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}/") 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 # Candidate for zapping ? [[ ! -L ${svcdir}/softscripts.new/${myservice} ]] || \ return 0 # If this is a 'net' service, we do not want to stop it if it was # not in the previous runlevel, and we are not shutting down, # rebooting or going to single runlevel. This is because the user # (or hotplut) might have started it (net.ppp?) ... if net_service "${myservice}" && \ [[ ${SOFTLEVEL} != "reboot" && \ ${SOFTLEVEL} != "shutdown" && \ ${SOFTLEVEL} != "single" ]] ; then if [[ -z ${OLDSOFTLEVEL} ]] || \ ! in_runlevel "${myservice}" "${OLDSOFTLEVEL}" ; then # This service is not in the previous runlevel, so # do not stop it ... 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 service_started "${dep}" && \ if [[ -L ${svcdir}/softscripts.new/${dep} ]] ; then # This dep is valid 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 source /sbin/functions.sh # 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\)') # Need try(), etc source "${svclib}"/sh/init-functions.sh source /etc/init.d/halt.sh # we just die here since we have no init # and we should be the last running process if [[ ${RC_INITSTYLE_HACK} == "yes" ]] ; then exit 0 fi 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 -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 ... if [[ -n ${BOOT} ]] ; then unset BOOT if [[ "${RC_INITSTYLE_HACK}" = "yes" ]]; then /sbin/rc default fi fi # Remove the cached CONSOLETYPE unset CONSOLETYPE # vim:ts=4