#! /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 PATH=/sbin:/usr/sbin:/bin:/usr/bin export PATH # Un-comment the following for debugging. # debug=echo # Specify method used to enable concurrent init.d scripts. # Valid options are 'none', 'shell' and 'startpar' CONCURRENCY=none # Make sure the name survive changing the argument list scriptname="$0" umask 022 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 # Decide if usplash progress bar should be activated or not. Override # in /etc/default/rcS if required. if type usplash_write >/dev/null 2>&1; then SPLASH=true else SPLASH=false fi # Now find out what the current and what the previous runlevel are. runlevel=$RUNLEVEL # Get first argument. Set new runlevel to this argument. [ "$1" != "" ] && runlevel=$1 if [ "$runlevel" = "" ] then echo "Usage: $scriptname " >&2 exit 1 fi previous=$PREVLEVEL [ "$previous" = "" ] && previous=N export runlevel previous . /etc/default/rcS export VERBOSE if [ -f /lib/lsb/init-functions ] ; then . /lib/lsb/init-functions else log_daemon_msg() { echo $@; } fi # # Stub to do progress bar ticks (currently just for usplash) on startup # startup_progress() { $@ if [ "$SPLASH" = true ] ; then step=$(($step + $step_change)) progress=$(($step * $progress_size / $num_steps + $first_step)) $debug usplash_write "PROGRESS $progress" || true fi } # # Start script or program. # case "$CONCURRENCY" in shell) log_daemon_msg "Using shell-style concurrent boot" startup() { action=$1 shift scripts="$@" sh=sh # Debian Policy §9.3.1 requires .sh scripts in runlevel S to be sourced # However, some important packages currently contain .sh scripts # that do "exit" at some point, thus killing this process. Bad! #[ S = "$runlevel" ] && sh=. backgrounded=0 for script in $scripts ; do case "$script" in *.sh) if [ "." = "$sh" ] ; then set "$action" RC_SAVE_PATH="$PATH" startup_progress $debug . "$script" PATH="$RC_SAVE_PATH" else startup_progress $debug $sh "$script" $action fi ;; *) startup_progress $debug "$script" $action & backgrounded=1 ;; esac done [ 1 = "$backgrounded" ] && wait } ;; startpar) log_daemon_msg "Using startpar-style concurrent boot" startup() { action=$1 shift scripts="$@" sh=sh # Debian Policy §9.3.1 requires .sh scripts in runlevel S to be sourced # However, some important packages currently contain .sh scripts # that do "exit" at some point, thus killing this process. Bad! #[ S = "$runlevel" ] && sh=. # Make sure .sh scripts are sourced in runlevel S if [ "." = "$sh" ] ; then newscripts= for script in $scripts ; do case "$script" in *.sh) set "$action" RC_SAVE_PATH="$PATH" startup_progress $debug . "$script" PATH="$RC_SAVE_PATH" ;; *) newscripts="$newscripts $script" ;; esac done scripts="$newscripts" fi # startpar is not able to handle time jumps. So the # hwclock.sh scripts should not be executed from # within startpar. The .sh hack above make this # problem irrelevant. [pere 2005-09-10] [ -n "$scripts" ] && startup_progress $debug startpar -a $action $scripts } ;; none|*) startup() { action=$1 shift scripts="$@" sh=sh # Debian Policy §9.3.1 requires .sh scripts in runlevel S to be sourced # However, some important packages currently contain .sh scripts # that do "exit" at some point, thus killing this process. Bad! #[ S = "$runlevel" ] && sh=. for script in $scripts ; do case "$script" in *.sh) if [ "." = "$sh" ] ; then set "$action" RC_SAVE_PATH="$PATH" startup_progress $debug . "$script" PATH="$RC_SAVE_PATH" else startup_progress $debug $sh "$script" $action fi ;; *) startup_progress $debug "$script" $action ;; esac done } ;; esac # Is there an rc directory for this new runlevel? if [ -d /etc/rc$runlevel.d ] then # Find out where in the progress bar the initramfs got to. PROGRESS_STATE=0 if [ -f /dev/.initramfs/progress_state ]; then . /dev/.initramfs/progress_state fi # Split the remaining portion of the progress bar into thirds progress_size=$(((100 - $PROGRESS_STATE) / 3)) case "$runlevel" in 0|6) ACTION=stop # Count down from 0 to -100 and use the entire bar first_step=0 progress_size=100 step_change=-1 ;; S) ACTION=start # Begin where the initramfs left off and use 2/3 # of the remaining space first_step=$PROGRESS_STATE progress_size=$(($progress_size * 2)) step_change=1 ;; *) ACTION=start # Begin where rcS left off and use the final 1/3 of # the space (by leaving progress_size unchanged) first_step=$(($progress_size * 2 + $PROGRESS_STATE)) step_change=1 ;; esac if [ "$SPLASH" = true ] ; then # Count the number of scripts we need to run (for usplash # progress bar) num_steps=0 for s in /etc/rc$runlevel.d/[SK]*; do case "${s##/etc/rc$runlevel.d/S??}" in gdm|xdm|kdm|ltsp-client|reboot|halt) break ;; esac num_steps=$(($num_steps + 1)) done step=0 fi # First, run the KILL scripts. if [ "$previous" != N ] then # Run all scripts with the same level in parallel CURLEVEL="" for s in /etc/rc$runlevel.d/K* do level=$(echo $s | sed 's/.*\/K\([0-9][0-9]\).*/\1/') if [ "$level" = "$CURLEVEL" ] then continue fi CURLEVEL=$level SCRIPTS="" for i in /etc/rc$runlevel.d/K$level* do # Check if the script is there. [ ! -f $i ] && continue # # Find stop script in previous runlevel but # no start script there. # suffix=${i#/etc/rc$runlevel.d/K[0-9][0-9]} previous_stop=/etc/rc$previous.d/K[0-9][0-9]$suffix 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. # [ -f $previous_stop ] && [ ! -f $previous_start ] && continue # Stop the service. SCRIPTS="$SCRIPTS $i" done startup stop $SCRIPTS done fi # Now run the START scripts for this runlevel. # Run all scripts with the same level in parallel CURLEVEL="" for s in /etc/rc$runlevel.d/S* do level=$(echo $s | sed 's/.*\/S\([0-9][0-9]\).*/\1/') if [ "$level" = "$CURLEVEL" ] then continue fi CURLEVEL=$level SCRIPTS="" for i in /etc/rc$runlevel.d/S$level* do [ ! -f $i ] && continue if [ "$previous" != N ] then # # Find start script in previous runlevel and # stop script in this runlevel. # suffix=${i#/etc/rc$runlevel.d/S[0-9][0-9]} stop=/etc/rc$runlevel.d/K[0-9][0-9]$suffix 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. # [ -f $previous_start ] && [ ! -f $stop ] && continue fi SCRIPTS="$SCRIPTS $i" done startup $ACTION $SCRIPTS done fi if [ S = "$runlevel" ] then # # For compatibility, run the files in /etc/rc.boot too. # [ -d /etc/rc.boot ] && run-parts /etc/rc.boot fi trap - EXIT # Disable emergency handler exit 0