#! /bin/sh # # rc # # Starts/stops services on runlevel changes. # # Optimization: A start script is not run when the service was already # configured to run in the previous runlevel. A stop script is not run # when the the service was already configured not to run in the previous # runlevel. # # Authors: # Miquel van Smoorenburg # Bruce Perens setglobal PATH = '/sbin:/usr/sbin:/bin:/usr/bin' export PATH # Un-comment the following for interactive debugging. Do not un-comment # this for debugging a real boot process as no scripts will be executed. # debug=echo # Make sure the name survive changing the argument list setglobal scriptname = $0 umask 022 proc on_exit { echo "error: '$scriptname' exited outside the expected code flow." } trap on_exit EXIT # Enable emergency handler # Ignore CTRL-C only in this shell, so we can interrupt subprocesses. trap ":" INT QUIT TSTP # Set onlcr to avoid staircase effect. stty onlcr !0 > !1 # Now find out what the current and what the previous runlevel are. setglobal runlevel = $RUNLEVEL # Get first argument. Set new runlevel to this argument. test $1 != "" && setglobal runlevel = $1 if test $runlevel = "" { echo "Usage: $scriptname " > !2 exit 1 } setglobal previous = $PREVLEVEL test $previous = "" && setglobal previous = 'N' export runlevel previous if test -f /etc/default/rcS { source /etc/default/rcS } export VERBOSE if test -f /lib/lsb/init-functions { source /lib/lsb/init-functions } else { proc log_action_msg { echo $ifsjoin(Argv); } proc log_failure_msg { echo $ifsjoin(Argv); } proc log_warning_msg { echo $ifsjoin(Argv); } } # # Check if we are able to use make like booting. It require the # insserv package to be enabled. Boot concurrency also requires # startpar to be installed. # #CONCURRENCY=makefile # disable startpar, incompatible with "task" upstart jobs setglobal CONCURRENCY = 'none' test -s /etc/init.d/.depend.boot || setglobal CONCURRENCY = '"none'" test -s /etc/init.d/.depend.start || setglobal CONCURRENCY = '"none'" test -s /etc/init.d/.depend.stop || setglobal CONCURRENCY = '"none'" if test -e /etc/init.d/.legacy-bootordering { setglobal CONCURRENCY = '"none'" } if ! test -e /proc/stat { # startpar requires /proc/stat if test $[uname] = "GNU/kFreeBSD" { mount -t linprocfs linprocfs /proc } elif test $[uname] = "GNU" { mount -t proc none /proc } } if test -x /lib/startpar/startpar { setglobal STARTPAR = '/lib/startpar/startpar' } else { setglobal STARTPAR = 'startpar' } $STARTPAR -v > /dev/null !2 > !1 || setglobal CONCURRENCY = '"none'" # # Start script or program. # match $CONCURRENCY { with makefile|startpar|shell # startpar and shell are obsolete setglobal CONCURRENCY = 'makefile' log_action_msg "Using makefile-style concurrent boot in runlevel $runlevel" proc startup { eval $[$STARTPAR -p 4 -t 20 -T 3 -M $1 -P $previous -R $runlevel] if test -n $failed_service { log_failure_msg "startpar: service(s) returned failure: $failed_service" } if test -n $skipped_service_not_installed { log_warning_msg "startpar: service(s) skipped, program is not installed: $skipped_service_not_installed" } if test -n $skipped_service_not_configured { log_warning_msg "startpar: service(s) skipped, program is not configured: $skipped_service_not_configured" } unset failed_service skipped_service_not_installed skipped_service_not_configured } with none|* proc startup { setglobal action = $1 shift setglobal scripts = @Argv for script in [$scripts] { $debug $script $action } } } # Is there an rc directory for this new runlevel? if test -d /etc/rc$runlevel.d { match $runlevel { with 0|6 setglobal ACTION = 'stop' with S setglobal ACTION = 'start' with * setglobal ACTION = 'start' } # First, run the KILL scripts. if test makefile = $CONCURRENCY { if test $ACTION = "start" && test $previous != N { startup stop } } elif test $previous != N { # Run all scripts with the same level in parallel setglobal CURLEVEL = ''"" for s in [/etc/rc$runlevel.d/K*] { # Extract order value from symlink setglobal level = $(s#/etc/rc$runlevel.d/K) setglobal level = $(level%%[a-zA-Z]*) if test $level = $CURLEVEL { continue } setglobal CURLEVEL = $level setglobal SCRIPTS = ''"" for i in [/etc/rc$runlevel.d/K$level*] { # Check if the script is there. test ! -f $i && continue # # Find stop script in previous runlevel but # no start script there. # setglobal suffix = $(i#/etc/rc$runlevel.d/K[0-9][0-9]) setglobal previous_stop = "/etc/rc$previous.d/K[0-9][0-9]$suffix" setglobal previous_start = "/etc/rc$previous.d/S[0-9][0-9]$suffix" # # If there is a stop script in the previous level # and _no_ start script there, we don't # have to re-stop the service. # test -f $previous_stop && test ! -f $previous_start && continue # Stop the service. setglobal SCRIPTS = ""$SCRIPTS $i"" } startup stop $SCRIPTS } } if test makefile = $CONCURRENCY { if test S = $runlevel { startup boot } else { startup $ACTION } } else { # Now run the START scripts for this runlevel. # Run all scripts with the same level in parallel setglobal CURLEVEL = ''"" for s in [/etc/rc$runlevel.d/S*] { # Extract order value from symlink setglobal level = $(s#/etc/rc$runlevel.d/S) setglobal level = $(level%%[a-zA-Z]*) if test $level = $CURLEVEL { continue } setglobal CURLEVEL = $level setglobal SCRIPTS = ''"" for i in [/etc/rc$runlevel.d/S$level*] { test ! -f $i && continue setglobal suffix = $(i#/etc/rc$runlevel.d/S[0-9][0-9]) if test $previous != N { # # Find start script in previous runlevel and # stop script in this runlevel. # setglobal stop = "/etc/rc$runlevel.d/K[0-9][0-9]$suffix" setglobal previous_start = "/etc/rc$previous.d/S[0-9][0-9]$suffix" # # If there is a start script in the previous level # and _no_ stop script in this level, we don't # have to re-start the service. # if test start = $ACTION { test -f $previous_start && test ! -f $stop && continue } else { # Workaround for the special # handling of runlevels 0 and 6. setglobal previous_stop = "/etc/rc$previous.d/K[0-9][0-9]$suffix" # # If there is a stop script in the previous level # and _no_ start script there, we don't # have to re-stop the service. # test -f $previous_stop && test ! -f $previous_start && continue } } setglobal SCRIPTS = ""$SCRIPTS $i"" } startup $ACTION $SCRIPTS } } } trap - EXIT # Disable emergency handler exit 0