#!/bin/sh
### BEGIN INIT INFO
# Provides:          checkfs-loop
# Required-Start:    checkroot
# Required-Stop:
# Should-Start:      udev devfsd raid2 mdadm lvm
# Should-Stop:
# Default-Start:     S
# Default-Stop:
# Short-Description: Check loop-encrypted filesystems.
### END INIT INFO
#
# NOTE: This script duplicates much of checkfs.sh as we need to
# work on the decrypted loop devices, which fsck -A doesn't know
# about. The maintainer of this script should track changes in
# checkfs.sh and make sure they are applied.
#
# $Id$

PATH=/sbin:/bin
FSCK_LOGFILE=/var/log/fsck/loop
[ "$FSCKFIX" ] || FSCKFIX=no
. /lib/init/vars.sh
. /lib/lsb/init-functions

[ -r /etc/default/checkfs-loop ] && . /etc/default/checkfs-loop

case "$CHECKFS_LOOP_ENABLE" in
  [Yy]*)
  	;;
  *)
  	exit 0
	;;
esac

# We need to check that the /sbin/losetup binary comes from 
# loop-aes-utils and not mount. Assume that if /sbin/losetup.orig
# exists the diversion is in place.
if [ ! -x /sbin/losetup.orig ]
then
	exit 0
fi

list_fsck_loops () {
	grep -v '^#' /etc/fstab |
	while read dev mnt fstype opts freq passno; do
		fsck=yes
		loopdev=

		for opt in $(IFS=, && echo $opts)
		do
			case $opt in
			noauto|sw|phash=random*)
				fsck=no
				;;
			loop=/dev/loop*)
				loopdev=${opt#loop=}
				;;
			esac
		done

		if [ -z "$loopdev" ] || [ "$mnt" = / ] || [ "$fsck" = no ]
		then
			continue
		fi

		echo $loopdev:$mnt
	done
}

retries=3

do_losetup () {
	loop=${1%:*}
	mnt=${1#*:}

	log_action_msg "Setting up $loop ($mnt)"

	try=0
	while [ $try -lt $retries ]
	do
		if losetup -F $loop
		then
			return 0
		fi
		try=$((try+1))
	done
	return 1
}

# TODO We can't do anything about FSCKTYPES settings other than "none"

do_fsck () {
	loopdevs="$@"

	# See if we're on AC Power
	# If not, we're not gonna run our check
	if which on_ac_power >/dev/null 2>&1
	then
		on_ac_power >/dev/null 2>&1
		if [ $? -eq 1 ]
		then
			[ "$VERBOSE" = no ] || log_success_msg "Running on battery power, so skipping loop file system check."
			BAT=yes
		fi
	fi

	#
	# Check loop-encrypted file systems.
	#
	if [ ! -f /fastboot ] && [ ! "$BAT" ] && [ "$FSCKTYPES" != "none" ]
	then
		if [ -f /forcefsck ]
		then
			force="-f"
		else
			force=""
		fi
		if [ "$FSCKFIX" = yes ]
		then
			fix="-y"
		else
			fix="-a"
		fi
		spinner="-C"
		case "$TERM" in
		  dumb|network|unknown|"")
			spinner=""
			;;
		esac
		[ "$(uname -m)" = s390 ] && spinner=""  # This should go away
		handle_failed_fsck() {
			log_failure_msg "File system check failed. 
A log is being saved in ${FSCK_LOGFILE} if that location is writable. 
Please repair the file system manually."
			log_warning_msg "A maintenance shell will now be started. 
CONTROL-D will terminate this shell and resume system boot."
			# Start a single user shell on the console
			if ! sulogin $CONSOLE
			then
				log_failure_msg "Attempt to start maintenance shell failed. 
Continuing with system boot in 5 seconds."
				sleep 5
			fi
		}

		failed=
		for device in $loopdevs
		do
			if [ "$VERBOSE" = no ]
			then
				logsave -s $FSCK_LOGFILE fsck $spinner $fix $force $device
				FSCKCODE=$?
				if [ "$FSCKCODE" -gt 1 ]
				then
					failed=1
				fi
			else
				logsave -s $FSCK_LOGFILE fsck $spinner -V $fix $force $device
				FSCKCODE=$?
				if [ "$FSCKCODE" -gt 1 ]
				then
					failed=1
				fi
			fi
		done

		if [ "$failed" ]
		then
			handle_failed_fsck
		else
			if [ "$VERBOSE" = yes ]
			then
				log_success_msg "Done checking loop-encrypted file systems. 
A log is being saved in ${FSCK_LOGFILE} if that location is writable."
			fi
		fi
	fi
	# Do not delete those, we are running before checkfs and it will
	# still need them
	#rm -f /fastboot /forcefsck
}

do_start () {
	log_action_msg "Checking loop-encrypted file systems"

	modprobe -q loop || true

	check_loops=
	for device in $(list_fsck_loops)
	do
		if do_losetup $device
		then
			check_loops="$check_loops ${device%:*}"
		fi
	done
	do_fsck $check_loops
}

case "$1" in
  start|"")
	do_start
	;;
  restart|reload|force-reload)
	echo "Error: argument '$1' not supported" >&2
	exit 3
	;;
  stop)
	# No-op
	;;
  *)
	echo "Usage: checkfs-loop [start|stop]" >&2
	exit 3
	;;
esac

:

