#! /bin/sh ### BEGIN INIT INFO # Provides: sendsigs # Required-Start: # Required-Stop: umountnfs # Default-Start: # Default-Stop: 0 6 # Short-Description: Kill all remaining processes. # Description: ### END INIT INFO setvar PATH = "/sbin:/usr/sbin:/bin:/usr/bin" source /lib/lsb/init-functions # Make it possible to see who the misbehaving processes are proc report_unkillable { test -x /usr/share/apport/unkillable_shutdown || return if test ! -e /etc/default/apport || ! grep -q '^enabled[[:space:]]*=[[:space:]]*1' /etc/default/apport { return } /usr/share/apport/unkillable_shutdown $OMITPIDS } proc upstart_killed_jobs { initctl list | grep 'stop/killed' } proc upstart_jobs { initctl list | grep -E '(start/|stop/killed)' | sed -n -e "/process [0-9]/s/.*process //p" } proc do_stop { setvar OMITPIDS = '' for omitfile in /run/sendsigs.omit { if test -e $omitfile { for pid in $(cat $omitfile) { setvar OMITPIDS = ""${OMITPIDS:+$OMITPIDS }-o $pid"" } } } # Load sendsigs.omit.d/packagename files too, to make it # possible for scripts that need to modify the list of pids at # run time without race conditions. for omitdir in /run/sendsigs.omit.d { if test -d ${omitdir} { for pidfile in "${omitdir}/"* { test -f $pidfile || continue for pid in $(cat $pidfile) { setvar OMITPIDS = ""${OMITPIDS:+$OMITPIDS }-o $pid"" } } } } # Upstart jobs have their own "stop on" clauses that sends # SIGTERM/SIGKILL just like this, so if they're still running, # they're supposed to be if test -x /sbin/initctl { for pid in $(upstart_jobs) { setvar OMITPIDS = ""${OMITPIDS:+$OMITPIDS }-o $pid"" } } # Flush the kernel I/O buffer before we start to kill # processes, to make sure the IO of already stopped services to # not slow down the remaining processes to a point where they # are accidentily killed with SIGKILL because they did not # manage to shut down in time. sync # Kill all processes. log_action_begin_msg "Asking all remaining processes to terminate" killall5 -15 $OMITPIDS # SIGTERM log_action_end_msg 0 setvar alldead = """" setvar OMITPIDS0 = "$OMITPIDS" for seq in 1 2 3 4 5 6 7 8 9 10 { setvar OMITPIDS = "$OMITPIDS0" # use SIGCONT/signal 18 to check if there are # processes left. No need to check the exit code # value, because either killall5 work and it make # sense to wait for processes to die, or it fail and # there is nothing to wait for. # did an upstart job start since we last polled initctl? check # again on each loop and add any new jobs (e.g., plymouth) to # the list. If we did miss one starting up, this beats waiting # 10 seconds before shutting down. if test -x /sbin/initctl { for pid in $(upstart_jobs) { setvar OMITPIDS = ""${OMITPIDS:+$OMITPIDS }-o $pid"" } } if killall5 -18 $OMITPIDS { : } else { setvar alldead = '1' break } sleep 1 } # Upstart has a method to set a kill timeout and so the job author # may want us to wait longer than 10 seconds (as in the case of # mysql). (LP: #688541) # # We will wait up to 300 seconds for any jobs in stop/killed state. # Any kill timeout higher than that will be overridden by the need # to shutdown. NOTE the re-use of seq from above, since we already # waited up to 10 seconds for them. while test -n $(upstart_killed_jobs) { setvar seq = $(($seq+1)) if test $seq -ge 300 { break } sleep 1 } if test -z $alldead { #report_unkillable log_action_begin_msg "Killing all remaining processes" killall5 -9 $OMITPIDS # SIGKILL log_action_end_msg 1 } else { log_action_begin_msg "All processes ended within $seq seconds" log_action_end_msg 0 } } case (1) { start|status { # No-op } restart|reload|force-reload { echo "Error: argument '$1' not supported" >&2 exit 3 } stop { do_stop } * { echo "Usage: $0 start|stop" >&2 exit 3 } } :