#! /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
	}
}

: