ACC SHELL

Path : /lib/cryptsetup/
File Upload :
Current File : //lib/cryptsetup/boot.crypto.functions

#!/bin/bash
# Copyright (C) 1996-2009 SUSE Linux Products GmbH, Nuernberg, Germany.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# Author:  Werner Fink <werner@suse.de>, 2001-2006
#          Chris Rivera <crivera@novell.com> 2006
#          Matthias Koenig <mkoenig@novell.com> 2008
#          Ludwig Nussel <lnussel@novell.com> 2007-2009
#

# Determine the base and follow a runlevel link name.
base=${0##*/}
link=${base#*[SK][0-9][0-9]}

# Redirect to real device (e.g. in case of boot logging)
: ${CRYPTOTAB:=/etc/cryptotab}
: ${CRYPTTAB:=/etc/crypttab}

# wait indefinitely in 2nd stage install to have a complete system
# for YaST.
if [ -z "$TIMEOUT" ]; then
	if [ -e /var/lib/YaST2/runme_at_boot ]; then
		TIMEOUT=0
	else
		TIMEOUT=120
	fi
fi
if test -z "$REDIRECT" ; then
    if (echo -n > /dev/tty) 2>/dev/null ; then
	REDIRECT=/dev/tty
    else
	REDIRECT=/dev/console
    fi
fi

splash=""
did_redirect=""
otty=$(stty -g)

redirect ()
{
    test -z "$did_redirect" || return 0
    did_redirect=1
    test -z "$otty" || stty "$otty" < $REDIRECT;
    stty -nl -ixon ignbrk -brkint < $REDIRECT
    if test -x /etc/init.d/kbd -a -n "$RUNLEVEL" ; then
	# boot.cleanup runs after us and presence of this file prevents kbd
	# from running
	/bin/rm -f /var/run/keymap
	/etc/init.d/kbd start
    fi
    splash_read
    splash_off
}

restore ()
{
    test -n "$did_redirect" || return 0
    test -z "$otty" || stty "$otty" < $REDIRECT;
    splash_restore
}

splash_read()
{
    splash=""
    if test -e /proc/splash ; then
	read splash  < /proc/splash
	case "$splash" in
	    *silent*) splash='silent' ;;
	    *) splash='' ;;
	esac
    fi
}

splash_off()
{
    [ -z "$splash" ] || echo verbose > /proc/splash
}

splash_restore()
{
    [ -z "$splash" ] || echo "$splash" > /proc/splash
}

setprompt ()
{
    redirect
    if [ -n "$RUNLEVEL" ]; then
	/usr/bin/setterm -msg off
    fi
    echo -e "$@"
}

unsetprompt ()
{
    if [ -n "$RUNLEVEL" ]; then
	/usr/bin/setterm -msg on
    fi
}

reverse ()
{
    local _line
    while read -r _line ; do
	case "$_line" in \#*|"") continue ;; esac
	reverse
	echo "$_line"
	break
    done
}

# we may need to initialize the random number generator if random
# keys are used as /etc/init.d/random runs later
init_random()
{
    # assume random is seeded in running system
    test "$base" != "$link" || return 0

    local random_seed=/var/lib/misc/random-seed
    test -f $random_seed || return 1
    cat $random_seed > /dev/urandom
}

check_loop_module ()
{
    if test ! -d /sys/block/loop0; then
        /sbin/modprobe -q loop
    fi
}

detachloopdev ()
{
    if [ -n "$loopdev" ]; then
	losetup -d $loopdev &> /dev/null || true
    fi
}

#
# Check for valid super blocks
#
check_superblock()
{
    local fs="$1"
    local device="$2"
    case "$fs" in
	ext[23])  tune2fs -l $device    &> /dev/null ;;
	reiserfs) debugreiserfs $device &> /dev/null ;;
	*)        true ;;
    esac
}

#
# parameters: filesys device mountpoint physdev quiet
# return value:
# 0 - ok
# 1 - enter passphrase again
# 2 - skip entry
#
paranoid_safety_checks()
{
    local filesys device mp physdev quiet choice
    filesys="$1"
    device="$2"
    mp="$3"
    physdev="$4"
    quiet="$5"

    check_superblock "$filesys" "$device"

    if test $? -gt 0; then
	echo "${warn}An error occurred. The passphrase may be wrong or the"
	echo "file system on $physdev might be corrupted.${norm}"

	while true ; do
	    echo -n "${extd}Retry entering the passphrase?${norm}"
	    choice=
	    read -p " ([${extd}yes${norm}]/${extd}no${norm}) " choice < $REDIRECT || { echo 'no'; choice='no'; }
	    case "$choice" in
		[yY][eE][sS]|[yY]|"")
		    return 1 ;;
		[nN][oO]|[nN])
		    return 2 ;;
	    esac
	done
    fi

    return 0
}

run_fsck()
{
    local filesys device mp physdev
    filesys="$1"
    device="$2"
    mp="$3"
    physdev="$4"
    #
    # Checking the structure on the loop device
    #
    # If we use a serial console, don't use the fsck progress bar
    #
    FSCK_PROGRESSBAR="-V"
    [ -x /sbin/showconsole ] && [ "`/sbin/showconsole`" = "/dev/tty1" ] && FSCK_PROGRESSBAR="-C"
    if test -x /sbin/fsck.$filesys; then
	fsck $FSCK_PROGRESSBAR -T -a -t $filesys $device
    else
	true
    fi
    if test $? -gt 1; then
	echo "${extd}fsck of $device failed.  Please repair manually.${norm}"
	echo "${warn}Warning: do never try to repair if you have entered the wrong passphrase.${norm}"
	# run sulogin only during boot
	if test "$base" != "$link"; then
	    PS1="(repair filesystem) # "
	    /sbin/sulogin -t "$timeout" $REDIRECT < $REDIRECT > $REDIRECT 2>&1
	    sync

	    if ! paranoid_safety_checks "$filesys" "$device" "$mp" "$physdev" 'quiet'; then
		echo "${extd}$physdev still appears to be damaged, skipping${norm}"
		/sbin/cryptsetup remove $name || true
		detachloopdev
		return 1
	    fi
	else
	    # leave the device set up so user can fun fsck manually
	    return 1
	fi
    fi
    return 0
}

report()
{
    rc_failed "$1"
    shift
    echo -n "$*"
    rc_status -v
}

makeabsolute()
{
    local var="$1"
    eval "f=\"\$$var\""
    if [ "${f:0:1}" != '/' ]; then
	echo "${extd}Warning: please use an absolute path for $f${norm}"
	eval "$var=\"$PWD/$f\""
    fi
}

resolvelink()
{
    local var="$1"
    local dev l d
    local i=0
    eval "dev=\"\$$var\""
    while l=`readlink "$dev"`; do
	    # weird way to find real path of a relative link
	    if [ "${l:0:1}" != / ]; then
		d=${l%/*}
		test "$d" != "$l" || d=''
		if ! cd "${dev%/*}/$d"; then
		    echo "${extd}Warning: can't resolve $dev${norm}"
		    return 1
		fi
		l="$PWD/${l##*/}"
		cd - > /dev/null
	    fi
	    dev="$l"
	    i=$((i+1))
	    if [ "$i" -gt 10 ]; then
		echo "${extd}Warning: too many symbolic links for $dev${norm}"
		return 1
	    fi
    done
    eval "$var=\"$dev\""
}

start_cryptotab ()
{
    local stat=0
    local haveone=''
    timeout="$TIMEOUT"

    test -n "$tostart" || echo "Activating crypto devices using $CRYPTOTAB ... "
    while read loopdev physdev access filesys crypto mopt info rest ; do
	case "$loopdev" in
	    \#*|"") continue ;;
	esac

	name="${loopdev#/dev/}"
	name="cryptotab_${name//[^A-Za-z0-9]/_}"

	if test -n "$tostart" \
	    -a "$loopdev" != "$tostart" \
	    -a "$physdev" != "$tostart" \
	    -a "$name" != "$tostart" \
	    -a "/dev/mapper/$name" != "$tostart" \
	    -a "$access" != "$tostart"; then
		continue
	fi

	haveone=1

	makeabsolute physdev

	# key length for cryptsetup
	keylen=
	ivgen='plain'
	hashalgo='sha512'
	#

	# Does the user want to skip current entry?
	#
	doskip=0
	#
	# Does the mount point exit?
	#
	if ! test -d $access ; then
	    report 5 "$physdev: $access doesn't exist"
	    failed=1
	    continue
	fi
	if ! test -e $physdev ; then
	    report 5 "$physdev doesn't exist"
	    failed=1
	    continue
	fi
	#
	# Seeking for crypto modules
	#
	case "$crypto" in
	    twofish)       keylen=192; ivgen='null'; hashalgo='ripemd160:20' ;;
	    twofishSL92)   keylen=256; ivgen='null' ;;
	    twofish[0-9]*) keylen=${crypto#twofish}; ;;
	    #TODO add more algorithm or better detection
	    *)
		    report 2 "$physdev: unsupported algorithm \"$crypto\""
		    failed=1
		    continue
		    ;;
	esac
	cipher=twofish-cbc-$ivgen

	if [ -e "/dev/mapper/$name" ]; then
	    report 5 "$physdev: $name already mapped"
	    continue
	fi

	while true; do # setup/check loop
	    #
	    # Restore virgin state
	    #
	    if [ -b "/dev/mapper/$name" ]; then
		/sbin/cryptsetup remove $name || true
	    fi
	    detachloopdev
	    device="$loopdev"

	    #
	    # Setting up loop device
	    #
	    if test -n "$info" ; then
		local prmt="${extd}Unlocking \"$info\" ($physdev)${norm}"
	    else
		local prmt="${extd}Unlocking $physdev${norm}"
	    fi

	    # we always use a loop device to avoid block size issues
	    # with e.g. cdroms for backward compatability
	    if ! losetup $loopdev $physdev; then
		    report 1 "$physdev..."
		    failed=1
		    continue 2
	    fi
	    
	    local params="-t $timeout -c $cipher -s $keylen -h $hashalgo"

	    setprompt "$prmt"
	    /sbin/cryptsetup $params create "$name" "$device" < $REDIRECT > $REDIRECT 2>&1
	    stat=$?
	    unsetprompt

	    if test "$stat" -ne 0; then
		    detachloopdev
		    report 1 "$physdev..."
		    failed=1
		    continue 2
	    fi

	    device="/dev/mapper/$name"

	    paranoid_safety_checks "$filesys" "$device" "$access" "$physdev"
	    stat="$?"
	    if test "$stat" = 1; then # retype passphrase
		continue
	    elif test "$stat" = 2; then # skip entry
		doskip=1
	    fi
	    break
	done
	#
	# Does the user want to skip this entry?
	#
	if test $doskip -gt 0 ; then
	    /sbin/cryptsetup remove $name || true
	    report 5 "$physdev..."
	    detachloopdev
	    continue
	fi

	if ! run_fsck "$filesys" "$device" "$access" "$physdev"; then
	    report 1 "$physdev..."
	    continue
	fi

	case "$mopt" in
	    default|"") mopt=""	;;
	esac

	mount -t $filesys ${mopt:+-o $mopt} $device $access
	stat=$?
	if test $stat -gt 0 ; then
	    stat=1
	    /sbin/cryptsetup remove $name || true
	    detachloopdev
	fi
	report $stat "$physdev..."
    done < $CRYPTOTAB

    if test -z "$haveone" -a -z "$tostart"; then
	rc_failed 6
	rc_status -v1
    fi

    test -z "$haveone" || foundit="$haveone"
}

# options are alreay parsed so we ignore the option parmeter ($2)
keyscript_hashalot()
{
    local args="${hashalot_algo:+$hashalot_algo} -t $timeout ${pseed:+-s $pseed} ${itercountk:+-C $itercountk}"
    if test -n "$1"; then
	/sbin/hashalot $args < $1
    else
	/sbin/hashalot $args
    fi
}

start_crypttab ()
{
    local stat=0
    local haveone=''

    test -n "$tostart" || echo "Activating crypto devices using $CRYPTTAB ... "

    if test -n "$tostart" -a "${tostart:0:1}" = '/'; then
	read name < <(awk -vd="$tostart" '$2==d{print $1}' < /etc/fstab)
	if test "$?" -eq 0; then
	    tostart="$name"
	fi
    fi

    while read name physdev keyfile options dummy; do
	case "$name" in
	\#*|"") continue ;;
	esac

	if test -n "$tostart" \
	    -a "$name" != "$tostart" \
	    -a "/dev/mapper/$name" != "$tostart" \
	    -a "$physdev" != "$tostart"; then
		continue
	fi

	haveone=1

	makeabsolute physdev

	test "$keyfile" != "none" || keyfile=""
	test "$options" != "none" || options=""
	CRYPTTAB_NAME="$name"
	CRYPTTAB_SOURCE="$physdev"
	CRYPTTAB_KEY="$keyfile"
	unset ${!CRYPTTAB_OPTION_*}

	# parse the options field
	skip=""
	params=()
	makeswap=""
	maketmp=""
	noauto=""
	noearly=""
	luks=""
	check=""
	checkargs=""
	loopdev=""
	param_ro=""
	cipher=""
	keysize=""
	halgo=""
	timeout=""
	pseed=""
	itercountk=""
	precheck=""
	keyscript=""
	tries="3"
	crypttab_options=()
	while test -n "$options"; do
	    arg=${options%%,*}
	    options=${options##$arg}
	    options=${options##,}
	    param=${arg%%=*}
	    value=${arg##$param=}
	    test "$param" != "$value" || value=
	    eval "CRYPTTAB_OPTION_$param=\"\${value:-yes}\""
	    crypttab_options+=("$param")

	    case "$param" in
	    cipher)
		if test -z "$value" ; then
		    echo $"$dst: no value for cipher option, skipping"
		    skip="yes"
		fi
		cipher="$value"
		;;
	    size)
		if test -z "$value" ; then
		    echo $"$dst: no value for size option, skipping"
		    skip="yes"
		fi
		keysize="$value"
		;;
	    hash)
		if test -z "$value" ; then
		    echo $"$dst: no value for hash option, skipping"
		    skip="yes"
		fi
		halgo="$value"
		;;
	    verify) params+=(-y) ;;
	    swap)   makeswap="yes" ;;
	    tmp)    maketmp="yes" ;;
	    noauto) noauto="yes" ;;
	    noearly) noearly="yes" ;;
	    luks)   luks="yes" ;;
	    loop)   loopdev="yes" ;;
	    readonly) param_ro="-r" ;;
	    timeout)
		case "$value" in
		    [0-9]*) timeout="$value";;
		    *) echo "invalid timeout '$value' ignored" ;;
		esac
		;;
	    tries)
		if test -n "$value" ; then
		    tries="$value"
		fi
		;;
	    check)
		if test -n "$value" -a -x /lib/cryptsetup/checks/"$value" ; then
		    check="/lib/cryptsetup/checks/$value"
		else
		    check="/lib/cryptsetup/checks/vol_id"
		fi
		;;
	    checkargs)
		if test -n "$value" ; then
		    checkargs="$value"
		fi
		;;
	    pseed) pseed="$value" ;;
	    itercountk) itercountk="$value" ;;
	    precheck)
		if test -n "$value" -a -x /lib/cryptsetup/checks/"$value" ; then
		    precheck="/lib/cryptsetup/checks/$value"
		fi
		;;
	    keyscript) keyscript="$value" ;;
	    initrd) ;; # ignore here
	    loud|ssl|gpg|*)
		echo "unsupported crypttab option: '$param'"
		skip='yes'
		;;
	    esac
	done

	if test "$skip" = "yes" -o \( "$noauto" = "yes" -a -z "$tostart" \); then
	    report 5 "$name"
	    continue
	fi

	if test "$CRYPT_EARLY" = "yes" -a "$noearly" = "yes"; then
	    report 5 "$name... will be set up later"
	    continue
	fi

	# skip mapped entries
	if test -e /dev/mapper/$name; then
	    report 5 "$name: already mapped"
	    continue
	fi

	if ! test -e $physdev ; then
            if test "$CRYPT_EARLY" = "yes"; then
                report 5 "$physdev does not exist (missing noearly option in /etc/crypttab?)"
            else
                report 5 "$physdev does not exist"
            fi

	    failed=1
	    continue
	fi

	if test -n "$luks"; then
	    if test -n "$cipher" -o -n "$halgo" -o -n "$keysize" -o -n "$pseed" -o -n "$itercountk"; then
		echo "${extd}Warning: cipher, hash, size, pseed and itercountk options are ignored for LUKS${norm}"
	    fi
	fi

	if test -n "$keyscript"; then
	    if test "${keyscript:0:1}" != '/'; then
		keyscript="/lib/cryptsetup/scripts/$keyscript"
	    fi
	    if ! test -x "$keyscript"; then
		report 2 "${ext}keyscript \"$keyscript\" must be an executable${norm}"
		continue
	    fi
	fi

	if test -n "$keyfile" -a -z "$keyscript"; then
	    # make sure the keyfile exists
	    if  ! test -e "$keyfile"; then
		report 5 "$name: $keyfile does not exist"
		failed=1
		continue
	    fi
	    if test -n "$halgo" -o -n "$pseed" -o -n "$itercountk"; then
		report 2 "${ext}hash, pseed and itercountk options are unused when using a key file${norm}"
	    fi
	    if test "$keyfile" = /dev/random -o "$keyfile" = /dev/urandom &&
		! init_random; then
		report 5 "$physdev: failed to initialize random number generator. /var on separate partition?"
		failed=1
		continue
	    fi
	fi

	# run precheck if it's set
	if test -n "$precheck"; then
	    $precheck "$physdev"
	    if test $? -ne 0; then
		report 1 "$name... "
		continue
	    fi
	fi

	if test -n "$param_ro"; then
	    params+=($param_ro)
	fi

	device="$physdev"
	# if device is a regular file then it's an image
	if test -n "$loopdev" -o -f $device; then
	    loopdev=''
	    local dev
	    for dev in /dev/loop*; do
		if ! test -b "$dev"; then
		    continue
		fi

		unset loopsize
		read loopsize < /sys/block/${dev#/dev/}/size
		if test $? -eq 0 -a "$loopsize" = '0' && /sbin/losetup $param_ro "$dev" $device; then
		    device="$dev"
		    loopdev="$device"
		    break
		fi
	    done

	    if test -z "$loopdev"; then
		report 1 "$name: failed to find a usable loop device"
		failed=1
		continue
	    fi
	fi

	doskip=0
	local tried=1;

	while true; do # setup/check loop

	    if [ -b "/dev/mapper/$name" ]; then
		/sbin/cryptsetup remove $name
	    fi

	    if test -z "$keyfile" -a -z "$keyscript"; then
		setprompt "${extd}Unlocking ${name} ($physdev)${norm}"
	    fi

	    # we always want a timeout to prevent accidential hanging boot
	    if test -z "$timeout"; then
		timeout="$TIMEOUT"
	    fi
	    if test "$timeout" != 0; then
		params+=(--timeout="$timeout")
	    fi

	    local cmd
	    # map the devices
	    if test -n "$luks" || cryptsetup isLuks "$device" &> /dev/null; then
		luks='yes'
		cmd=(luksOpen "$device" "$name")
	    else
		if test -z "$keyscript" -a -z "$keyfile"; then
		    # XXX hack
		    if test -n "$pseed" -o -n "$itercountk"; then
			keyscript=keyscript_hashalot
			hashalot_algo="$halgo"
			halgo=plain
		    fi
		fi
		params+=(${halgo:+-h $halgo} ${cipher:+-c $cipher} ${keysize:+-s $keysize})
		cmd=(create "$name" "$device")
	    fi

	    if test -n "$keyscript"; then
		    CRYPTTAB_OPTIONS="${crypttab_options[*]}" # turn array into string
		    ( export ${!CRYPTTAB_*}; $keyscript "$keyfile" | /sbin/cryptsetup "${params[@]}" "${cmd[@]}"; ) < $REDIRECT &> $REDIRECT
	    else
		    /sbin/cryptsetup ${keyfile:+-d $keyfile} --tries=1 "${params[@]}" "${cmd[@]}" < $REDIRECT &> $REDIRECT
	    fi
	    stat=$?

	    if test -z "$keyfile"; then
		# we only set the prompt if keyscript was not set before but
		# since we later use keyscript for hashalot which needs the
		# prompt we unset it here always.
		unsetprompt
	    fi

	    if test $stat -ne 0; then
		# return value != 255 means some error with getting the key,
		# like timeout or ^d. No retry in that case.
		if test "$stat" -ne 255 -o \( "$tries" -ne 0 -a "$tried" -ge "$tries" \); then
		    report 1 "$name... "
		    doskip=1
		    failed=1
		    break
		else
		    tried=$((tried+1))
		    continue
		fi
	    fi

	    mountpoint=''
	    fs_type='auto'
	    infstab=''
	    read dummy mountpoint fs_type dummy dummy fs_passno < \
		<(/bin/awk -vd=/dev/mapper/$name '$1==d{print;exit}' < /etc/fstab)
	    if test "$?" -eq 0; then
		infstab='yes'
	    fi
	    test -z "$fs_passno" && fs_passno=0

	    # run check if it's set
	    if test -n "$check"; then
		if $check "/dev/mapper/$name" $checkargs; then
		    break
		else
		    if test "$tries" -ne 0 -a "$tried" -ge "$tries"; then
			report 1 "$name... "
			doskip=1
			failed=1
			break
		    else
			tried=$((tried+1))
			continue
		    fi
		fi
	    else
		# no need for paranoid checks with luks as cryptsetup is able to
		# verify the passphrase itself then
		#
		# if the device is not in fstab we can't do paranoid checks as we
		# don't know what the intention of the device is
		if test "$makeswap" != 'yes' \
			-a "$maketmp" != 'yes' \
			-a -z "$luks" \
			-a -n "$infstab"; then
		    if ! check_superblock "$fs_type" "/dev/mapper/$name"; then
			echo "${warn}An error occurred. The passphrase could be wrong or the file system on"
			echo "$physdev might be corrupted.${norm}"

			if test "$tries" -ne 0 -a "$tried" -ge "$tries"; then
			    report 1 "$name... "
			    doskip=1
			    failed=1
			    break
			else
			    tried=$((tried+1))
			    continue
			fi
		    fi
		fi
	    fi

	    break;
	done # setup/check loop

	if test "$doskip" -gt 0; then
	    if test -b "/dev/mapper/$name"; then
		/sbin/cryptsetup remove "$name"
	    fi
	    detachloopdev
	    continue
	fi

	# run mkfs if the tmp option was given
	if test "$maketmp" = "yes"; then
	    echo "Creating filesystem on /dev/mapper/$name..."
	    if test "$fs_type" = 'auto'; then
		fs_type='ext2'
	    fi
	    /sbin/mkfs -t "$fs_type" /dev/mapper/$name

	    if test $? -ne 0; then
		report 1 "$phsdev: failed to create temporary file system."
		doskip=1
		failed=1
		/sbin/cryptsetup remove "$name"
		detachloopdev
		continue
	    fi
	fi

	# run mkswap if necessary. boot.swap with enable this later
	if test "$makeswap" = "yes"; then
	    mkswap "/dev/mapper/$name"
	    stat="$?"
	    test $stat -eq 0 || stat=1
	    report $stat "$name..."
	    continue
	fi

	# if called from boot.crypto-early skip the rest,
	# since fsck and mount is done in boot.localfs
	if test "$CRYPT_EARLY" = "yes"; then
	    report 0 "$name..."
	    continue
	fi

	if test -z "$infstab"; then
	    report 0 "$name..."
	    continue
	fi

	if test $fs_passno -gt 0; then
	    if ! run_fsck "$fs_type" "/dev/mapper/$name" "$mp" "$physdev"; then
	        report 1 "$name..."
	        continue
	    fi
	fi

	mount /dev/mapper/$name
	stat="$?"

	if test $stat -gt 0 ; then
	    stat=1
	    /sbin/cryptsetup remove $name || true
	    detachloopdev
	fi

	# set permissions for tmp dirs
	if test "$maketmp" = "yes"; then
	    chmod 1777 $mountpoint
	fi

	report $stat "$name..."

    done < $CRYPTTAB

    if test -z "$haveone" -a -z "$tostart"; then
	rc_failed 6
	rc_status -v1
    fi

    test -z "$haveone" || foundit="$haveone"
}

umount_or_swapoff()
{
    # unmount device
    if /bin/grep -q "^/dev/mapper/$name[ \t]" /proc/mounts; then
	umount "/dev/mapper/$name"
	if test $? -gt 0 ; then
	    return 1
	fi
    elif /bin/grep -q "^/dev/mapper/$name[ \t]" /proc/swaps; then
	swapoff "/dev/mapper/$name"
	if test $? -gt 0 ; then
	    return 1
	fi
    fi

    return 0
}


stop_cryptotab ()
{
    local haveone=''

    test -n "$tostop" || echo "Turning off crypto devices using $CRYPTOTAB ... "

    while read loopdev physdev access filesys crypto mopt rest ; do
	case "$loopdev" in
	    \#*|"") continue ;;
	esac

	name="${loopdev#/dev/}"
	name="cryptotab_${name//[^A-Za-z0-9]/_}"

	if test -n "$tostop" \
	    -a "$loopdev" != "$tostop" \
	    -a "$physdev" != "$tostop" \
	    -a "$name" != "$tostop" \
	    -a "/dev/mapper/$name" != "$tostop" \
	    -a "$access" != "$tostop"; then
		continue
	fi

	haveone=1

	makeabsolute physdev

	if test -b "/dev/mapper/$name"; then

	    if ! umount_or_swapoff; then
		report 1 "$physdev..."
		failed=1
		continue
	    fi

	    cryptsetup remove "$name" || rc_failed 1
	fi

	if losetup $loopdev >/dev/null 2>&1; then
	    losetup -d $loopdev || { rc_failed 1; failed=1; }
	fi

	echo -n "$physdev..."
	rc_status -v

    done < <(reverse < $CRYPTOTAB)
    
    if test -z "$haveone" -a -z "$tostop"; then
	rc_status -v1
    fi

    test -z "$haveone" || foundit="$haveone"
}

stop_crypttab ()
{
    local haveone=''

    test -n "$tostop" || echo "Turning off crypto devices using $CRYPTTAB ... "

    if test -n "$tostop" -a "${tostop:0:1}" = '/'; then
	read name < <(awk -vd="$tostop" '$2==d{print $1}' < /etc/fstab)
	if test "$?" -eq 0; then
	    tostop="$name"
	fi
    fi

    while read name physdev keyfile options dummy; do
	case "$name" in
	\#*|"") continue ;;
	esac

	if test -n "$tostop" \
	    -a "$name" != "$tostop" \
	    -a "/dev/mapper/$name" != "$tostop" \
	    -a "$physdev" != "$tostop"; then
		continue
	fi

	haveone=1

	makeabsolute physdev

	loopdev=""
	device="$physdev"

	if test -b "/dev/mapper/$name"; then
	    if ! umount_or_swapoff; then
		report 1 "$name..."
		failed=1
		continue
	    fi

	    /sbin/cryptsetup remove "$name" || { rc_failed 1; failed=1; }
	fi

	linkdev="$physdev"
	! test -L "$linkdev" || resolvelink linkdev
	# delete the loop device
	while read line; do
	    case "$line" in
	    *\(${physdev}\)*) device=${line%%:*}; loopdev='yes'; break ;;
	    *\(${linkdev}\)*) device=${line%%:*}; loopdev='yes'; break ;;
	    esac
	done < <(/sbin/losetup -a)

	if test -n "$loopdev" && losetup $device >/dev/null 2>&1; then
	    /sbin/losetup -d $device ||  { rc_failed 1; failed=1; }
	fi

	echo -n "$name..."
	rc_status -v

    done < <(reverse < $CRYPTTAB)

    if test -z "$haveone" -a -z "$tostop"; then
	rc_status -v1
    fi

    test -z "$haveone" || foundit="$haveone"
}

status_cryptotab()
{
    local state str
    local haveone=''
    while read loopdev physdev access filesys crypto mopt info rest ; do
	case "$loopdev" in
	    \#*|"") continue ;;
	esac

	if test -n "$tostatus" \
	    -a "$loopdev" != "$tostatus" \
	    -a "$physdev" != "$tostatus" \
	    -a "$access" != "$tostatus"; then
		continue
	fi

	haveone=1

	makeabsolute physdev

	name="${loopdev#/dev/}"
	name="cryptotab_${name//[^A-Za-z0-9]/_}"

	echo -n "$physdev"
	state=0
	str=''

	if losetup "$loopdev" > /dev/null 2>&1; then
	    str="$str ${loopdev#/dev/}"
	    state=$((state+1))
	fi
	if test -b "/dev/mapper/$name"; then
	    str="$str mapped"
	    state=$((state+1))
	fi
	if /bin/grep -q "^/dev/mapper/$name[ \t]" /proc/mounts; then
	    str="$str mounted"
	    state=$((state+1))
	fi

	if test "$state" = 3; then
	    rc_failed 0
	elif test "$state" != 0; then 
	    rc_failed 4
	else
	    rc_failed 3
	fi

	if test -n "$str"; then
	    echo -n " [$str ]"
	fi
	rc_status -v

    done < $CRYPTOTAB

    if test -z "$haveone" -a -z "$tostatus"; then
	report 3 "$CRYPTOTAB"
    fi

    test -z "$haveone" || foundit="$haveone"
}

status_crypttab()
{
    local state str
    local haveone=''

    if test -n "$tostatus" -a "${tostatus:0:1}" = '/'; then
	read name < <(awk -vd="$tostatus" '$2==d{print $1}' < /etc/fstab)
	if test "$?" -eq 0; then
	    tostatus="$name"
	fi
    fi

    while read name physdev keyfile options dummy; do
	case "$name" in
	\#*|"") continue ;;
	esac

	if test -n "$tostatus" \
	    -a "$name" != "$tostatus" \
	    -a "/dev/mapper/$name" != "$tostatus" \
	    -a "$physdev" != "$tostatus"; then
		continue
	fi

	haveone=1

	makeabsolute physdev

	echo -n "$name"
	state=0
	str=''

	loopdev=''
	linkdev="$physdev"
	! test -L "$linkdev" || resolvelink linkdev
	# find the loop device
	while read line; do
	    case "$line" in
	    *\(${physdev}\)*) loopdev=${line%%:*}; break ;;
	    *\(${linkdev}\)*) loopdev=${line%%:*}; break ;;
	    esac
	done < <(/sbin/losetup -a)

	if test -n "$loopdev" && losetup "$loopdev" > /dev/null 2>&1; then
	    str="$str ${loopdev#/dev/}"
	    state=$((state|1))
	fi
	if test -b "/dev/mapper/$name"; then
	    str="$str mapped"
	    state=$((state|2))
	fi
	if /bin/grep -q "^/dev/mapper/$name[ \t]" /proc/mounts; then
	    str="$str mounted"
	    state=$((state|4))
	elif /bin/grep -q "^/dev/mapper/$name[ \t]" /proc/swaps; then
	    str="$str swap"
	    state=$((state|4))
	fi

	if test -n "$str"; then
	    echo -n " [$str ]"
	fi
	if test "$state" != 0; then
	    if test $((state&2)) = 0; then
		rc_failed 4
	    else
		if ! test -e "$physdev"; then
		    rc_failed 1
		else
		    rc_failed 0
		fi
	    fi
	else
	    rc_failed 3
	fi
	rc_status -v

    done < $CRYPTTAB

    if test -z "$haveone" -a -z "$tostatus"; then
	report 3 "$CRYPTTAB"
    fi

    test -z "$haveone" || foundit="$haveone"
}

#
# Customize_{start,stop}_hook are for interactive usage only
#
customize_start_hook ()
{
    local srv

    test "$base" != "$link"             && return 0
    test -s /etc/sysconfig/boot.crypto  || return 0
    . /etc/sysconfig/boot.crypto

    for srv in $TRY_RESTART_AT_START ; do
	test -n "$srv" || break
	test -x /etc/init.d/$srv || continue
	/etc/init.d/$srv try-restart
    done

    for srv in $RESTART_AT_START ; do
	test -n "$srv" || break
	test -x /etc/init.d/$srv || continue
	/etc/init.d/$srv restart
    done

    for srv in $RELOAD_AT_START ; do
        test -n "$srv" || break
        test -x /etc/init.d/$srv || continue
        /etc/init.d/$srv reload
    done
}


customize_pre_stop_hook ()
{
    local srv

    test "$base" != "$link"             && return 0
    test -s /etc/sysconfig/boot.crypto  || return 0
    . /etc/sysconfig/boot.crypto

    for srv in $STOP_BEFORE_STOP ; do
	test -n "$srv" || break
	test -x /etc/init.d/$srv || continue
	/etc/init.d/$srv stop
    done
}

customize_stop_hook ()
{
    local srv

    test "$base" != "$link"             && return 0
    test -s /etc/sysconfig/boot.crypto  || return 0
    . /etc/sysconfig/boot.crypto

    for srv in $TRY_RESTART_AT_STOP ; do
	test -n "$srv" || break
	test -x /etc/init.d/$srv || continue
	/etc/init.d/$srv try-restart
    done

    for srv in $RESTART_AT_STOP ; do
	test -n "$srv" || break
	test -x /etc/init.d/$srv || continue
	/etc/init.d/$srv restart
    done

    for srv in $RELOAD_AT_STOP ; do
	test -n "$srv" || break
	test -x /etc/init.d/$srv || continue
	/etc/init.d/$srv reload
    done
}

ACC SHELL 2018