0xV3NOMx
Linux ip-172-26-7-228 5.4.0-1103-aws #111~18.04.1-Ubuntu SMP Tue May 23 20:04:10 UTC 2023 x86_64



Your IP : 18.119.112.208


Current Path : /proc/thread-self/root/lib/cryptsetup/
Upload File :
Current File : //proc/thread-self/root/lib/cryptsetup/cryptdisks.functions

#
# This file is for inclusion with
#    . /lib/cryptsetup/cryptdisks.functions
# and should not be executed directly.

PATH="/usr/sbin:/usr/bin:/sbin:/bin"
TABFILE=${TABFILE-"/etc/crypttab"}
CRYPTDISKS_ENABLE="Yes"

#set -x

# Sanity check #1
[ -x /sbin/cryptsetup ] || exit 0

. /lib/lsb/init-functions

if [ -r /etc/default/cryptdisks ]; then
	. /etc/default/cryptdisks
fi

# Sanity check #2
[ -f "$TABFILE" ] || exit 0

MOUNT="$CRYPTDISKS_MOUNT"

# Parses the option field from the crypttab file
parse_opts () {
	local opts opt IFS PARAM VALUE

	# Strip comments - https://bugs.launchpad.net/bugs/185380
	opts=$(echo -n $1 | sed 's/ *#.*//')
	PARAMS=""
	LUKSPARAMS=""
	CRYPTHEADER=""
	TCRYPTPARAMS=""
	PLAINPARAMS=""
	CHECK=""
	CHECKARGS=""
	PRECHECK=""
	TRIES="3"
	TMPFS=""
	MAKESWAP=""
	USELUKS=""
	USETCRYPT=""
	KEYSCRIPT=""
	IGNORE=""
	CRYPTTAB_OPTIONS=""
	LOUD="$DEFAULT_LOUD"

	# Parse the options field, convert to cryptsetup parameters
	# and construct the command line
	IFS=','
	for opt in $opts; do
		PARAM=$(echo "$opt" | sed 's/=.*//')
		VALUE=$(echo "$opt" | sed '/=/!d;s/^.*=//')

		case "$PARAM" in
		readonly)
			PARAMS="$PARAMS -r"
			;;
		cipher)
			if [ -z "$VALUE" ]; then
				log_warning_msg "$dst: no value for cipher option, skipping"
				return 1
			fi
			PLAINPARAMS="$PLAINPARAMS -c $VALUE"
			;;
		size)
			if [ -z "$VALUE" ] || echo "$VALUE" | grep -q "^[[:digit:]]\+$" && [ "$VALUE" -gt 0 ]; then
				PLAINPARAMS="$PLAINPARAMS -s $VALUE"
			else
				log_warning_msg "$dst: option size used with an incorrect argument, skipping"
				return 1
			fi
			;;
		hash)
			if [ -z "$VALUE" ]; then
				log_warning_msg "$dst: no value for hash option, skipping"
				return 1
			fi
			PLAINPARAMS="$PLAINPARAMS -h $VALUE"
			;;
		offset)
			if [ -z "$VALUE" ]; then
				log_warning_msg "$dst: no value for offset option, skipping"
				return 1
			fi
			PLAINPARAMS="$PLAINPARAMS -o $VALUE"
			;;
		skip)
			if [ -z "$VALUE" ]; then
				log_warning_msg "$dst: no value for skip option, skipping"
				return 1
			fi
			PLAINPARAMS="$PLAINPARAMS -p $VALUE"
			;;
		verify)
			PARAMS="$PARAMS -y"
			;;
		check)
			if [ -z "$VALUE" ]; then
				VALUE="$CRYPTDISKS_CHECK"
			fi
			if [ -x "$VALUE" ]; then
				CHECK="$VALUE"
			elif [ -x "/lib/cryptsetup/checks/$VALUE" ]; then
				CHECK="/lib/cryptsetup/checks/$VALUE"
			else
				log_warning_msg "check $VALUE is not an executable script, skipping"
				return 1
			fi
			;;
		checkargs)
			if [ -n "$VALUE" ]; then
				CHECKARGS="$VALUE"
			fi
			;;
		precheck)
			if [ -z "$VALUE" ]; then
				VALUE="$CRYPTDISKS_PRECHECK"
			fi
			if [ -x "$VALUE" ]; then
				PRECHECK="$VALUE"
			elif [ -x "/lib/cryptsetup/checks/$VALUE" ]; then
				PRECHECK="/lib/cryptsetup/checks/$VALUE"
			else
				log_warning_msg "precheck $VALUE is not an executable script, skipping"
				return 1
			fi
			;;
		tries)
			if echo "$VALUE" | grep -q "^[[:digit:]]\+$" && [ "$VALUE" -ge 0 ]; then
				TRIES="$VALUE"
			else
				log_warning_msg "$dst: option tries used with an incorrect argument - forced to $TRIES"
			fi
			;;
		discard)
			PARAMS="$PARAMS --allow-discards"
			;;
		swap)
			MAKESWAP="yes"
			;;
		tmp)
			if [ -z "$VALUE" ]; then
				TMPFS="ext4"
			else
				TMPFS="$VALUE"
			fi
			;;
		luks)
			USELUKS="yes"
			;;
		header)
			if [ -z "$VALUE" ]; then
				log_warning_msg "$dst: no value for header option, skipping"
				return 1
			fi
			LUKSPARAMS="$LUKSPARAMS --header=$VALUE"
			CRYPTHEADER="$VALUE"
			;;
		tcrypt)
			USETCRYPT="yes"
			;;
		noearly)
			if [ "$INITSTATE" = "early" ]; then
				IGNORE="yes"
			fi
			;;
		noauto)
			if [ "$INITSTATE" != "manual" ]; then
				IGNORE="yes"
			fi
			;;
		loud)
			LOUD="yes"
			;;
		quiet)
			LOUD=""
			;;
		keyscript)
			if [ -n "$KEYSCRIPT" ]; then
				log_warning_msg "$dst: multiple key decryption options are not allowed together, skipping"
				return 1
			elif [ -z "$VALUE" ]; then
				log_warning_msg "$dst: no value for keyscript option, skipping"
				return 1
			elif [ -x "$VALUE" ]; then
				KEYSCRIPT="$VALUE"
			elif [ -x "/lib/cryptsetup/scripts/$VALUE" ]; then
				KEYSCRIPT="/lib/cryptsetup/scripts/$VALUE"
			elif type "$VALUE" >/dev/null 2>&1; then
				KEYSCRIPT="$VALUE"
			else
				log_warning_msg "script $VALUE is not an executable script, skipping"
				return 1
			fi
			;;
		keyslot)
			if [ -z "$VALUE" ]; then
				log_warning_msg "$dst: no value for keyslot option, skipping"
				return 1
			fi
			LUKSPARAMS="$LUKSPARAMS --key-slot $VALUE"
			;;
		tcrypthidden)
			TCRYPTPARAMS="$TCRYPTPARAMS --tcrypt-hidden"
			;;
		veracrypt)
			TCRYPTPARAMS="$TCRYPTPARAMS --veracrypt"
			;;
		esac

		CRYPTTAB_OPTIONS="$CRYPTTAB_OPTIONS $PARAM"
		[ -z "$VALUE" ] && VALUE="yes"
		eval export CRYPTTAB_OPTION_$PARAM="\"$VALUE\""
	done
	export CRYPTTAB_OPTIONS

	return 0
}

# Sanity check for keys
check_key () {
	local GMODE OMODE OWNER GROUP

	# If the keyscript option is set, the "key" is just an argument to
	# the keyscript and not necessarily a file
	if [ -n "$KEYSCRIPT" ]; then
		return 0
	fi

	if [ -z "$key" ] || [ "$key" = "none" ]; then
		key=""
		return 0
	fi

	if [ ! -e "$key" ]; then
		log_warning_msg "$dst: keyfile not found"
		return 1
	fi

	# LUKS requires a persistent key, /dev/*random is not supported
	if [ "$USELUKS" = "yes" ] && [ "$key" != "${key%random}" ]; then
		log_warning_msg "$dst: LUKS does not work with random data as key"
		return 1
	fi

	# TCRYPT requires a persistent key, /dev/*random is not supported
	if [ "$TCRYPT" = "yes" ] && [ "$key" != "${key%random}" ]; then
		log_warning_msg "$dst: TCRYPT does not work with random data as key"
		return 1
	fi

	# Check ownership of $key
	OWNER="$(/bin/ls -l "$(readlink -f $key)" | sed 's/^.\{10\}[+\.]\?.[^[:space:]]* \([^[:space:]]*\).*/\1/')"
	if [ "$OWNER" != "root" ]; then
		log_warning_msg "$dst: INSECURE OWNER FOR $key, see /usr/share/doc/cryptsetup/README.Debian."
	fi

	# If key is random, we're done
	if [ "$key" != "${key%random}" ]; then
		return 0
	fi

	# Check owner group of $key
	GROUP="$(/bin/ls -l "$(readlink -f $key)" | sed 's/^.\{12\}[+\.]\?.[^[:space:]]* \([^[:space:]]*\).*/\1/')"
	if [ "$GROUP" != "root" ]; then
		log_warning_msg "$dst: INSECURE OWNER GROUP FOR $key, see /usr/share/doc/cryptsetup/README.Debian."
	fi

	# Check group and other permissions
	GMODE="$(/bin/ls -l "$(readlink -f $key)" | sed 's/[[:space:]].*//;s/^.\{4\}\(.\{3\}\).*/\1/')"
	OMODE="$(/bin/ls -l "$(readlink -f $key)" | sed 's/[[:space:]].*//;s/^.\{7\}\(.\{3\}\).*/\1/')"
	if [ "$GMODE" != "---" ] && [ "$OMODE" != "---" ]; then
		log_warning_msg "$dst: INSECURE MODE FOR $key, see /usr/share/doc/cryptsetup/README.Debian."
	fi

	return 0
}

# Setup a luks mapping
do_luks () {
	local tried keyscriptarg
	tried=0
	keyscriptarg=""

	if ! cryptsetup isLuks "${CRYPTHEADER:-$src}" >/dev/null 2>&1; then
		log_warning_msg "$dst: device '${CRYPTHEADER:-$src}' is not a LUKS partition, skipping"
		return 1
	fi

	if [ -n "$KEYSCRIPT" ]; then
		# keyscript => "key" is just an argument to the keyscript
		keyscriptarg="$key"
		key="-"
	elif [ -z "$key" ]; then
		# no keyscript, no key => password
		keyscriptarg="$promptmsg"
		key="-"
		KEYSCRIPT="/lib/cryptsetup/askpass"
	elif [ "$key" != "${key%/dev/*}" ]; then
		# no keyscript, device key => special treatment
		keyscriptarg=""
		key="$key"
		KEYSCRIPT=""
	else
		# no keyscript, key => file input
		keyscriptarg="$key"
		key="-"
		KEYSCRIPT="cat"
	fi

	PARAMS="$PARAMS --key-file=$key"

	while [ "$tried" -lt "$TRIES" ] || [ "$TRIES" -eq "0" ]; do
		export CRYPTTAB_TRIED="$tried"
		if [ -n "$KEYSCRIPT" ]; then
			if $KEYSCRIPT "$keyscriptarg" | cryptsetup $PARAMS $LUKSPARAMS open --type luks "$src" "${dst}_unformatted"; then
				break
			fi
		else
			if cryptsetup $PARAMS $LUKSPARAMS open --type luks "$src" "${dst}_unformatted"; then
				break
			fi
		fi

		tried=$(( $tried + 1 ))
		if [ "$tried" -ge "$TRIES" ] && [ "$TRIES" -ne "0" ]; then
			return 1
		fi
	done

	if [ -n "$CHECK" ] && ! "$CHECK" "/dev/mapper/${dst}_unformatted" $CHECKARGS; then
		log_warning_msg "$dst: the check for '/dev/mapper/$dst' failed"
		cryptsetup luksClose "${dst}_unformatted"
		return 1
	fi

	return 0
}

# Setup a tcrypt mapping
do_tcrypt () {
	local tried keyscriptarg
	tried=0
	keyscriptarg=""

	if ! pre_out="$($PRECHECK "$src" 2>/dev/null)" && \
	   ! /lib/cryptsetup/checks/blkid "$src" swap >/dev/null; then
		log_warning_msg "$dst: the precheck for '$src' failed: $pre_out"
		return 1
	fi

	if [ -n "$KEYSCRIPT" ]; then
		# keyscript => "key" is just an argument to the keyscript
		keyscriptarg="$key"
		key="-"
	elif [ -z "$key" ]; then
		# no keyscript, no key => password
		keyscriptarg="$promptmsg"
		key="-"
		KEYSCRIPT="/lib/cryptsetup/askpass"
	elif [ "$key" != "${key%/dev/*}" ]; then
		# no keyscript, device key => special treatment
		keyscriptarg=""
		key="$key"
		KEYSCRIPT=""
	else
		# no keyscript, key => file input
		keyscriptarg="$key"
		key="-"
		KEYSCRIPT="cat"
	fi

	PARAMS="$PARAMS --key-file=$key"

	while [ "$tried" -lt "$TRIES" ] || [ "$TRIES" -eq "0" ]; do
		export CRYPTTAB_TRIED="$tried"
		if [ -n "$KEYSCRIPT" ]; then
			if $KEYSCRIPT "$keyscriptarg" | cryptsetup $PARAMS $TCRYPTPARAMS open --type tcrypt "$src" "${dst}_unformatted"; then
				break
			fi
		else
			if cryptsetup $PARAMS $TCRYPTPARAMS open --type tcrypt "$src" "${dst}_unformatted"; then
				break
			fi
		fi

		tried=$(( $tried + 1 ))
		if [ "$tried" -ge "$TRIES" ] && [ "$TRIES" -ne "0" ]; then
			return 1
		fi
	done

	if [ -n "$CHECK" ] && ! "$CHECK" "/dev/mapper/${dst}_unformatted" $CHECKARGS; then
		log_warning_msg "$dst: the check for '/dev/mapper/$dst' failed"
		cryptsetup luksClose "${dst}_unformatted"
		return 1
	fi

	return 0
}

# Setup a regular mapping
do_noluks () {
	local pre_out tried keyscriptarg
	tried=0
	keyscriptarg=""

	if [ -z "$PRECHECK" ]; then
		PRECHECK="/lib/cryptsetup/checks/un_blkid"
	fi

	if ! pre_out="$($PRECHECK "$src" 2>/dev/null)" && \
	   ! /lib/cryptsetup/checks/blkid "$src" swap >/dev/null; then
		log_warning_msg "$dst: the precheck for '$src' failed: $pre_out"
		return 1
	fi

	if [ -n "$KEYSCRIPT" ]; then
		# keyscript => "key" is just an argument to the keyscript
		keyscriptarg="$key"
		key="-"
	elif [ -z "$key" ]; then
		# no keyscript, no key => password
		keyscriptarg="$promptmsg"
		key="-"
		KEYSCRIPT="/lib/cryptsetup/askpass"
	else
		# no keyscript, key => file input
		keyscriptarg=""
		key="$key"
		KEYSCRIPT=""
	fi

	PARAMS="$PARAMS --key-file=$key"

	while [ "$tried" -lt "$TRIES" ]; do
		export CRYPTTAB_TRIED="$tried"
		if [ -n "$KEYSCRIPT" ]; then
			$KEYSCRIPT "$keyscriptarg" | cryptsetup $PLAINPARAMS $PARAMS open --type plain "$src" "${dst}_unformatted"
		else
			cryptsetup $PLAINPARAMS $PARAMS open --type plain "$src" "${dst}_unformatted"
		fi

		if [ -z "$CHECK" ] || "$CHECK" "/dev/mapper/${dst}_unformatted" $CHECKARGS; then
			break
		else
			log_warning_msg "$dst: the check for '/dev/mapper/$dst' failed - maybe the password is wrong"
			cryptsetup remove "${dst}_unformatted"
		fi

		tried=$(( $tried + 1 ))
		if [ "$tried" -ge "$TRIES" ]; then
			return 1
		fi
	done

	return 0
}

# Premounts file systems
mount_fs () {
	local point
	MOUNTED=""

	for point in $MOUNT; do
		if mount "$point" >/dev/null; then
			MOUNTED="$MOUNTED $point"
		fi
	done
}

# Postunmounts file systems
umount_fs () {
	local point

	for point in $MOUNTED; do
		umount "$point" >/dev/null
	done
}

# Prepares swap partitions using random keys
do_swap () {
	local swap_out

	if [ "$MAKESWAP" != "yes" ] || [ ! -b "/dev/mapper/${dst}_unformatted" ]; then
		return 0
	fi

	if swap_out="$(/lib/cryptsetup/checks/un_blkid "/dev/mapper/${dst}_unformatted" 2>/dev/null)" || \
	   /lib/cryptsetup/checks/blkid "/dev/mapper/${dst}_unformatted" swap >/dev/null 2>&1; then
		mkswap "/dev/mapper/${dst}_unformatted" >/dev/null 2>&1
	else
		log_warning_msg "$dst: the check for '/dev/mapper/$dst' failed. /dev/mapper/$dst contains data: $swap_out"
		do_close
		return 1
	fi

	return 0
}

# Prepares tmp partitions using random keys
do_tmp () {
	if [ "x$TMPFS" = "x" ] || [ ! -b "/dev/mapper/${dst}_unformatted" ]; then
		return 0
	fi

	mkfs -t $TMPFS -q "/dev/mapper/${dst}_unformatted" >/dev/null 2>&1 || return 1
	mkdir -p "/var/run/cryptsetup/$dst"
	mount -t $TMPFS "/dev/mapper/${dst}_unformatted" "/var/run/cryptsetup/$dst" || return 1
	chmod 1777 "/var/run/cryptsetup/$dst"
	umount "/var/run/cryptsetup/$dst"
	return 0
}

# Rename the device from its temp name to its final name, which will
# trigger mountall
finalize_device () {
	if command -v udevadm >/dev/null 2>&1; then
        	udevadm settle
    	fi
    	dmsetup rename "${dst}_unformatted" "$dst"
}

# Removes a mapping
do_close () {
	local found IFS opt

	found="no"
	IFS=','
	for opt in $opts; do
		if [ "$opt" = "luks" ]; then
			found="yes"
			break
		fi
	done

	if [ "$found" = "yes" ]; then
		cryptsetup luksClose "$dst"
	else
		cryptsetup remove "$dst"
	fi
	return $?
}

load_optimized_module () {
	local module optmodule
	module="$1"

	optmodule=$(find "/lib/modules/$(uname -r)/kernel/arch" -name "${module}*.ko" 2>/dev/null)
	if [ -n "$optmodule" ] && [ "$(echo -n "$optmodule" | wc -l)" -eq 1 ]; then
		modprobe "$optmodule" 2>/dev/null && return 0
	fi

	modprobe "$module" 2>/dev/null || return 1
	return 0
}

# Sets up all entries in crypttab
handle_crypttab_line_start () {
	dst=$1
	src=$2
	key=$3
	opts=$4

	# Make sure that all fields are present
	if [ -z "$dst" ]; then
		return 1
	elif [ -z "$src" ] || [ -z "$key" ] || [ -z "$opts" ]; then
		device_msg "$dst" "skipped, missing parameters"
		return 1
	fi

	# parse UUID= symlinks
	if [ "${src#UUID=}" != "$src" ]; then
		src="/dev/disk/by-uuid/${src#UUID=}"
	elif [ "${src#LABEL=}" != "$src" ]; then
		src="/dev/disk/by-label/$(printf '%s' "${src#LABEL=}" | sed 's,/,\\x2f,g')"
	fi

	# Do the preparatory steps
	if ! parse_opts "$opts"; then
		device_msg "$dst" "invalid opts"
		return 1
	fi

	# Ignore noauto devices
	if [ "$IGNORE" = "yes" ] && [ -z "$FORCE_START" ]; then
		device_msg "$dst" "ignored"
		return 0
	fi

	if ! check_key; then
		device_msg "$dst" "invalid key"
		return 1
	fi

	# Export crypttab fields as environment variables
	export CRYPTTAB_NAME="$dst"
	export CRYPTTAB_SOURCE="$src"
	export CRYPTTAB_KEY="$key"

	# Make sure source device exists
	if [ ! -r "$src" ]; then
		if [ "$LOUD" = "yes" ]; then
			device_msg "$dst" "skipped, device $src does not exist"
			return 1
		fi
		return 0
	fi

	# Make sure that target device doesn't exist
	if [ -b "/dev/mapper/${dst}_unformatted" ] || [ -b "/dev/mapper/$dst" ]; then
		device_msg "$dst" "running"
		return 0
	fi

	# Prepare the unlocking prompt
	if [ "${src#/dev/disk/by-uuid/}" != "$src" ]; then
		# UUIDs are not very helpful
		diskname="$dst"
	else
		diskname="$src ($dst)"
	fi
	promptmsg="Please unlock disk $diskname: "

	# All checks passed, do the real setup
	log_action_msg "$dst (starting).."
	result="ok"
	if [ "$USELUKS" = "yes" ]; then
		do_luks || result="fail"
	elif [ "$USETCRYPT" = "yes" ]; then
		do_tcrypt || result="fail"
	else
		do_noluks || result="fail"
	fi

	# Finish up
	if [ "$result" != "ok" ]; then
		device_msg "$dst" "failed"
		return 1
	else
		do_swap
		do_tmp
		finalize_device
		device_msg "$dst" "started"
	fi

	return 0
}

handle_crypttab_line_stop () {
	dst=$1
	src=$2
	key=$3
	opts=$4

	if [ ! -b "/dev/mapper/$dst" ]; then
		device_msg "$dst" "stopped"
		return 0
	fi

	opencount=$(dmsetup info -c --noheadings -o open "$dst" 2>/dev/null || true)
	if [ -z "$opencount" ]; then
		device_msg "$dst" "error"
		return 1
	elif [ "$opencount" != "0" ]; then
		device_msg "$dst" "busy"
		if [ "$INITSTATE" = "early" ] || [ "$INITSTATE" = "manual" ]; then
			return 1
		elif [ "$INITSTATE" = "remaining" ]; then
			return 2
		fi
		return 0
	fi

	#major=$(dmsetup info -c --noheadings -o major "$dst" 2>/dev/null || true)
	#minor=$(dmsetup info -c --noheadings -o minor "$dst" 2>/dev/null || true)
	src_major="$(dmsetup deps "$dst" 2>/dev/null | sed -e 's/^.*(\([0-9]*\), [0-9]*)$/\1/g' || true)"
	src_minor="$(dmsetup deps "$dst" 2>/dev/null | sed -e 's/^.*([0-9]*, \([0-9]*\))$/\1/g' || true)"

	if [ -z "$src_major" ] || [ -z "$src_minor" ]; then
		device_msg "$dst" "error"
		return 1
	fi

	do_close || return $?

	device_msg "$dst" "stopping"

	return 0
}

crypttab_start_one_disk () {
	local dst src key opts result
	local ret=0

	egrep -v "^[[:space:]]*(#|$)" "$TABFILE" | while read dst src key opts; do
		if [ "xUUID=$ID_FS_UUID" = "x$src" ]; then
			src="/dev/disk/by-uuid/${src#UUID=}"
		elif [ "xLABEL=$ID_FS_LABEL_ENC" = "x$src" ]; then
			src="/dev/disk/by-label/$(printf '%s' "${src#LABEL=}" | sed 's,/,\\x2f,g')"
		elif [ "x$1" != "x$src" ]; then
			found=
			for link in $DEVLINKS; do
				if [ "x$link" = "x$src" ]; then
					found=1
					break
				fi
			done
			if [ -z "$found" ]; then
				continue
			fi
		fi
		modprobe -qb dm-mod || true
		modprobe -qb dm-crypt || true
		dmsetup mknodes > /dev/null 2>&1 || true
		# FIXME: no locking
		mount_fs
		handle_crypttab_line_start "$dst" "$src" "$key" "$opts" || ret=$?
		umount_fs
	done
	return $ret
}

# Starts all mappings in crypttab
do_start () {
	local dst src key opts result

	modprobe -qb dm-mod || true
	modprobe -qb dm-crypt || true
	dmsetup mknodes >/dev/null 2>&1 || true
	if [ "$INITSTATE" != "init" ]; then
		log_action_begin_msg "Starting $INITSTATE crypto disks"
	fi
	mount_fs

	egrep -v "^[[:space:]]*(#|$)" "$TABFILE" | while read dst src key opts; do
		dev_match="$src"
		if [ "${dev_match#UUID=}" != "$dev_match" ]; then
			dev_match="$(readlink -f /dev/disk/by-uuid/${dev_match#UUID=})"
		elif [ "${dev_match#LABEL=}" != "$dev_match" ]; then
			dev_match="$(readlink -f "/dev/disk/by-label/$(printf '%s' "${dev_match#LABEL=}" | sed 's,/,\\x2f,g')")"
		fi
		# only required for the (ubuntu) upstart init system:
		# if there's already a udev-triggered job running for this
		# device, wait for it to finish, then re-process to confirm
		# that it's started successfully.  In the general case this
		# will just be a no-op, but we don't want to defer to the
		# other job entirely because this is the fallback for fixing
		# up any ordering-dependent decrypting.
		[ -x /sbin/status ] && while /sbin/status cryptdisks-udev DEVNAME="$dev_match" 2>&1 | grep -q "\<start"; do
			sleep 1
		done
		handle_crypttab_line_start "$dst" "$src" "$key" "$opts" <&3 || log_action_end_msg $?
	done 3<&1
	umount_fs

	log_action_end_msg 0
}

# Removes all mappings in crypttab
do_stop () {
	local dst src key opts opencount major minor

	dmsetup mknodes
	log_action_begin_msg "Stopping $INITSTATE crypto disks"

	egrep -v "^[[:space:]]*(#|$)" "$TABFILE" | while read dst src key opts; do
		for i in 1 2 4 8 16 32; do
			handle_crypttab_line_stop "$dst" "$src" "$key" "$opts" <&3 && break || ret=$?
			if [ $ret -eq 1 ] || [ $ret -eq 2 -a $i -gt 16 ]; then
				log_action_end_msg $ret
				break
			fi
			log_action_cont_msg "$dst busy..."
			sleep $i
		done 3<&1
	done

	log_action_end_msg 0
}

# Convenience function to handle $VERBOSE
device_msg () {
	local dst msg
	dst="$1"
	msg="$2"

	if [ "$VERBOSE" != "no" ]; then
		log_action_cont_msg "$dst ($msg)"
	fi
}