#!/bin/bash
#
# Copyright (c) 2001-2002 SuSE Linux AG, Nuernberg, Germany.
# All rights reserved.
#
# Author:  Werner Fink <werner@suse.de>, 2001
#
# /etc/init.d/boot.crypto
#
### BEGIN INIT INFO
# Provides:          boot.crypto
# Required-Start:    boot.localfs boot.klog
# Should-Start: boot.md boot.lvm
# Required-Stop:
# Default-Start:     B
# Default-Stop:
# Description:       Enable crypto file systems before leaving boot phase
### END INIT INFO

. /etc/rc.status

trap "echo" SIGINT SIGSEGV
set +e

# Redirect to real device (e.g. in case of boot logging)
: ${CRYPTOTAB:=/etc/cryptotab}
: ${TIMEOUT:=120}
if test -z "$REDIRECT" ; then
    if (echo -n > /dev/tty) 2>/dev/null ; then
	REDIRECT=/dev/tty
    else
	REDIRECT=/dev/console
    fi
fi
test -s $CRYPTOTAB || exit 0
type -p losetup &> /dev/null || exit 0

redirect ()
{
    otty=$(stty -g)
    stty $otty < $REDIRECT
    stty -nl -ixon ignbrk -brkint < $REDIRECT
    if test -x /etc/init.d/kbd -a -n "$RUNLEVEL" ; then
	/etc/init.d/kbd start < $REDIRECT > $REDIRECT 2>&1
    fi
}

restore () { stty $otty < $REDIRECT; }

ppid=0
prmt=""
setprompt ()
{
    if test -t 1 -a "$TERM" != "raw" -a "$TERM" != "dumb" && stty size <&1 > /dev/null 2>&1
    then
	(
	    trap "exit 0" SIGTERM
	    trap "echo" SIGINT SIGSEGV
	    usleep 10000
	    while test $TIMEOUT -gt 0 ; do
		echo -en "\r${prmt}"
		sleep 2
		: $((TIMEOUT-=2))
	    done
	) & ppid=$!
    else
	usleep 10000
	echo -en "\r${prmt}"
	ppid=0
    fi
}

unsetprompt ()
{
    local ret=$?
    test $ppid -gt 0 && kill -15 $ppid
    ppid=0
    return $ret
}

rc_reset
main_status=0
case "$1" in
    start|b)
	redirect
	echo "Activating crypto devices using $CRYPTOTAB ... "
	while read loopdev physdev access filesys crypto mopt info rest ; do
	    case "$loopdev" in
		\#*|"") continue ;;
	    esac
	    #
	    # Each loop is a new try
	    #
	    rc_status
	    if test $? -gt 0 ; then
		main_status=1
	    fi
	    rc_reset
	    #
	    # Does the user want to skip current entry?
	    #
	    doskip=0
	    #
	    # Seeking for crypto modules
	    #
	    case "$crypto" in
		twofish)	modprobe loop_fish2 ;;
		twofishSL92)	modprobe loop_fish2 ;;
		twofish[0-9]*)	modprobe cryptoloop && modprobe twofish ;;
	    esac
	    rc_status
	    test $? -ne 0 && continue
	    #
	    #
	    #
	    while true; do
		#
		# Restore virgin state
		#
		losetup -d $loopdev &> /dev/null || true

		#
		# Setting up loop device
		#
		if test -n "$info" ; then
		    prmt="${extd}Please enter passphrase for \"$info\" ($physdev): ${norm}"
		else
		    prmt="${extd}Please enter passphrase for $physdev: ${norm}"
		fi
		setprompt
		losetup -t $TIMEOUT -e $crypto $loopdev $physdev < $REDIRECT > $REDIRECT 2>&1
		unsetprompt
		rc_status
		test $? -ne 0 && continue 2

		#
		# Check if we've success
		#
		if   mount -t $filesys -n -o ro $loopdev $access &> /dev/null ; then
		    umount -n $access &> /dev/null || true
		    break
		else
		    umount -n $access &> /dev/null || true
		    echo    "${warn}An error occured.  Maybe the wrong passphrase was"
		    echo    "entered or the file system on $physdev is corrupted.${norm}"
		    while true ; do
			echo    "${extd}Do you want to retry entering the passphrase or${norm}"
			echo -n "${extd}do you want to continue with a file system check?${norm}"
			read -p " ([${extd}yes${norm}]/${extd}no${norm}/${extd}check${norm}/) " prolo < $REDIRECT
			case "$prolo" in
			    [yY][eE][sS]|[yY]|"")
				continue 2 ;;
			    [nN][oO]|[nN])
				doskip=1
				break    2 ;;
			    [Cc][hH][eE][Cc][kK]|[Cc])
				break    2 ;;
			esac
		    done
		fi
		break
	    done
	    #
	    # Does the user have skipped this entry?
	    #
	    if test $doskip -gt 0 ; then
		losetup -d $loopdev &> /dev/null || true
		continue
	    fi
	    #
	    # Check for valid super blocks
	    #
	    case "$filesys" in
		ext2)	  tune2fs -l $loopdev	 &> /dev/null ;;
		reiserfs) debugreiserfs $loopdev &> /dev/null ;;
		*)	  true ;;
	    esac
	    rc_status
	    if test $? -gt 0 ; then
		losetup -d $loopdev &> /dev/null || true
		continue
	    fi
	    #
	    # Checking the structure on the loop device
	    #
	    fsck -a -t $filesys $loopdev
	    FSCK_RETURN=$?
	    test $FSCK_RETURN -lt 2
	    rc_status
	    if test $FSCK_RETURN -gt 1; then
		echo "fsck of $loopdev failed.  Please repair manually."
		echo "${warn}Warning: do never try to repair if you have entered the wrong passphrase.${norm}"
		PS1="(repair filesystem) # "
		/sbin/sulogin $REDIRECT < $REDIRECT > $REDIRECT 2>&1
		sync
	    fi
	    #
	    # Mounting loop device to mount point WITHOUT entry in /etc/mtab
	    #
	    case "$mopt" in
		default|"") mopt=""	;;
	    esac
	    mount -t $filesys -n ${mopt:+-o $mopt} $loopdev $access
	    rc_status
	    if test $? -gt 0 ; then
		losetup -d $loopdev &> /dev/null
	    else
		#
		# Generate entry in /etc/mtab (to enable umount to run losetup -d)
		#
		loopopt="loop=${loopdev},encryption=${crypto}"
		case "$mopt" in
		    default|"") mopt="${loopopt}"		;;
		    *)		mopt="${loopopt},${mopt}"	;;
		esac
		mount -t $filesys -f -o $mopt $physdev $access
		rc_status
	    fi
	done < $CRYPTOTAB
	test $main_status -gt 0 && rc_failed 1 || true
	rc_status -v1
	restore
	;;
    stop)
	reverse ()
	{
	    local _line
	    while read -r _line ; do
		case "$_line" in \#*|"") continue ;; esac
		reverse
		echo "$_line"
		break
	    done
	}
	echo "Turning off crypto devices using $CRYPTOTAB ... "
	while read loopdev physdev access filesys crypto mopt rest ; do
	    case "$loopdev" in
		\#*|"") continue ;;
	    esac
	    #
	    # Each loop is a new try
	    #
	    rc_status
	    if test $? -gt 0 ; then
		main_status=1
	    fi
	    rc_reset
	    #
	    # Umount loop device
	    #
	    umount $access
	    rc_status
	    #
	    # If /etc/mtab is linked to /proc/mounts
	    # we've to run losetup to detach loop device
	    #
	    if test -L /etc/mtab ; then
		losetup -d $loopdev
		rc_status
	    fi
	done < <(reverse < $CRYPTOTAB)
	test $main_status -gt 0 && rc_failed 1 || true
	rc_status -v1
	;;
    status)
	rc_failed 4
	rc_status -v
	;;
    restart)
	$0 stop
	$0 start
	rc_status
	;;
    *)
	echo "Usage: $0 {start|stop|status|restart}"
	exit 1
	;;
esac
rc_exit
