#! /bin/sh
### BEGIN INIT INFO
# Provides:          umountfs
# Required-Start:    umountnfs urandom
# Required-Stop:
# Default-Start:     0 6
# Default-Stop:
# Short-Description: Turn off swap and unmount all local file systems.
# Description:
### END INIT INFO

PATH=/usr/sbin:/usr/bin:/sbin:/bin
. /lib/init/vars.sh

. /lib/lsb/init-functions

umask 022

# Print in order of decreasing length
#
# Algorithm: Find and print longest argument, then call self
# to print remaining arguments in order of decreasing length
#
# This function runs at one tenth the speed of the sort program
# but we use the function because we don't want to rely on any
# programs in /usr/.
#
# N.B.: Arguments must not be null and must not contain whitespace
#
pioodl() {
	[ "$1" ] || return 0
	ARGNUM=1
	ARGNUM_LONGEST=0
	ARGLENGTH_LONGEST=0
	for ARG in "$@"
	do
		ARGLENGTH="${#ARG}"
		if [ "$ARGLENGTH" -gt "$ARGLENGTH_LONGEST" ]
		then
			ARGLENGTH_LONGEST="$ARGLENGTH"
			ARGNUM_LONGEST="$ARGNUM"
		fi
		ARGNUM=$(($ARGNUM + 1))
	done
	# The method of passing prevargs assumes that args can be
	# delimited with spaces
	ARGNUM=1
	PREVARGS=""
	while [ "$ARGNUM" -lt "$ARGNUM_LONGEST" ]
	do
		PREVARGS="$PREVARGS $1"
		shift
		ARGNUM=$(($ARGNUM + 1))
	done
	echo "$1"
	shift
	pioodl $PREVARGS "$@"
}


do_stop () {
	exec 9<&0 </proc/mounts
	PROTECTED_MOUNTS="$(sed -n '0,/^\/[^ ]* \/ /p' /proc/mounts)"
	WEAK_MTPTS="" #be gentle, don't use force
	REG_MTPTS=""
	TMPFS_MTPTS=""
	while read DEV MTPT FSTYPE REST
	do
		echo "$PROTECTED_MOUNTS" | grep -qs "^$DEV $MTPT " && continue
		case "$MTPT" in
			/|/proc|/dev|/.dev|/dev/pts|/dev/shm|/proc/*|/sys|/var/run|/var/lock)
			continue
			;;
		esac
		case "$FSTYPE" in
			proc|procfs|linprocfs|devfs|sysfs|usbfs|usbdevfs|devpts|securityfs)
			continue
			;;
		  tmpfs)
			if [ -d "$MTPT" ]; then
				TMPFS_MTPTS="$TMPFS_MTPTS $MTPT"
			fi
			;;
		  *)
			REG_MTPTS="$REG_MTPTS $MTPT"
			if echo "$PROTECTED_MOUNTS" | grep -qs "^$DEV "; then
				WEAK_MTPTS="$WEAK_MTPTS $MTPT "
			fi
			;;
		esac
	done

	exec 0<&9 9<&-

	#
	# Make sure tmpfs file systems are umounted before turning off
	# swap, to avoid running out of memory if the tmpfs filesystems
	# use a lot of space.
	#
	if [ "$TMPFS_MTPTS" ]
	then
		if [ "$VERBOSE" = no ]
		then
			log_action_begin_msg "Unmounting temporary filesystems"
			umount $TMPFS_MTPTS
			log_action_end_msg $?
		else
			log_action_msg "Will now unmount temporary filesystems"
			umount -v $TMPFS_MTPTS
			ES=$?
			if [ "$ES" = 0 ]
			then
				log_success_msg "Done unmounting temporary filesystems."
			else
				log_failure_msg "Unmounting temporary filesystems failed with error code ${ES}."
			fi
		fi
	fi

	#
	# Deactivate swap
	#
	if [ "$VERBOSE" = no ]
	then
		log_action_begin_msg "Deactivating swap"
		swapoff -a >/dev/null
		log_action_end_msg $?
	else
		log_action_msg "Will now deactivate swap"
		swapoff -a -v
		ES=$?
		if [ "$ES" = 0 ]
		then
			log_success_msg "Done deactivating swap."
		else
			log_failure_msg "Swap deactivation failed with error code ${ES}."
		fi
	fi

	#
	# Unmount local filesystems
	#
	[ -z "$REG_MTPTS" ] && return
	[ "$VERBOSE" = no ] && log_action_begin_msg "Unmounting local filesystems"
	REG_MTPTS="$(pioodl $REG_MTPTS)"
	local ES2=0
	for MTPT in $REG_MTPTS; do
		if echo "$WEAK_MTPTS" | grep -qs " $MTPT "; then
			FORCE=""
		else
			FORCE="-f"
		fi
		if [ "$VERBOSE" = no ]; then
			umount $FORCE -r -d $MTPT
			ES=$?
			[ "$ES" != 0 ] && [ "$ES2" = 0 ] && ES2=$ES
		else
			log_action_begin_msg "Unmounting local filesystem $MTPT"
			umount $FORCE -v -r -d $MTPT
			ES=$?
			if [ "$ES" = 0 ]; then
				log_success_msg "Done unmounting local filesystem $MTPT."
			else
				log_failure_msg "Unmounting local filesystem $MTPT failed with error code $ES."
			fi
		fi
	done
	[ "$VERBOSE" = no ] && log_action_end_msg $ES2
}

case "$1" in
  start)
	# 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
	;;
esac

:
