--- /dev/null
+#!/bin/bash
+
+#########################################################################
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the version 3 of the GNU General Public License #
+# as published by the Free Software Foundation. #
+# #
+# 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, see <http://www.gnu.org/licenses/>. #
+# #
+# Written by and Copyright (C) Francois Fleuret #
+# Contact <francois.fleuret@idiap.ch> for comments & bug reports #
+#########################################################################
+
+set -e
+# set -o pipefail
+
+function print_help () {
+ cat <<EOF
+$(basename $0) [--help | clean | sync <source file> <dest file> | fsck [-f] <file|device> | mount <dir> | umount <dir>]
+
+clean
+
+ 1. umounts all the volumes using a /dev/dm-* device
+ 2. LUKS-close all the volumes appearing in /dev/mapper
+ 3. Delete all the loop devices
+
+sync
+
+ Mounts both files as LUKS volumes, runs a dry-run rsync, and asks for
+ interactive confirmation before synchronizing.
+
+fsck
+
+ LUKS-open the provided file and run fsck on it.
+
+mount|umount
+
+ Automagically figures out from /etc/fstab what is the /dev/mapper/
+ device associated to the dir, and both LUKS-opens/mounts or
+ umount/LUKS-closes it.
+
+EOF
+}
+
+######################################################################
+
+if [[ "$@" == "" ]]; then
+ print_help >&2
+ exit 1
+fi
+
+if [[ ! $(id -u) == 0 ]]; then
+ echo "This command should be run as root (no offense, but you are $(id -un))." >&2
+ exit 1
+fi
+
+######################################################################
+
+case $1 in
+
+ clean)
+
+ # mount | grep ^'/dev/dm-[0-9]*' | sed -e 's/^.* on \([^ ]*\) .*$/\1/' | \
+
+ mount | grep ^'/dev/mapper' | sed -e 's/^.* on \([^ ]*\) .*$/\1/' | \
+ while read line; do
+ echo "umount ${line}"
+ umount ${line}
+ done
+
+ \ls /dev/mapper | grep -v ^control$ | \
+ while read line; do
+ echo "cryptsetup luksClose ${line[0]}"
+ cryptsetup luksClose "${line[0]}"
+ done
+
+ losetup -a | sed -e "s/:.*$//" | \
+ while read line; do
+ echo "losetup -d ${line}"
+ losetup -d ${line}
+ done
+
+ exit 0
+
+ ;;
+
+ ######################################################################
+
+ sync)
+
+ shift
+
+ [[ -f "$1" ]] && [[ -f "$2" ]] || (echo "$(basename $0) sync <source file> <dest file>" >&2 && exit 1)
+
+ [[ -e "/dev/mapper/crypt-src" ]] && (echo "/dev/mapper/crypt-src already exists." >&2 && exit 1)
+
+ [[ -e "/dev/mapper/crypt-dst" ]] && (echo "/dev/mapper/crypt-dst already exists." >&2 && exit 1)
+
+ ######################################################################
+ # Mount the volumes
+
+ echo "Please confirm that $2 can be modified (press 'y')"
+
+ read -n 1 KEY
+
+ if [[ ! "${KEY}" == "y" ]]; then
+ echo "Cancelled!"
+ exit 1
+ fi
+
+ echo
+
+ LOOP_SRC="$(losetup -f)"
+ losetup "${LOOP_SRC}" "$1"
+ cryptsetup luksOpen "${LOOP_SRC}" crypt-src
+ DIR_MOUNT_SRC="$(mktemp -d /tmp/sync-luks.XXXXXX)"
+ mount -o ro /dev/mapper/crypt-src "${DIR_MOUNT_SRC}"
+
+ LOOP_DST="$(losetup -f)"
+ losetup "${LOOP_DST}" "$2"
+ cryptsetup luksOpen "${LOOP_DST}" crypt-dst
+ DIR_MOUNT_DST="$(mktemp -d /tmp/sync-luks.XXXXXX)"
+ mount /dev/mapper/crypt-dst "${DIR_MOUNT_DST}"
+
+ ######################################################################
+ # First, show the changes
+
+ echo "**********************************************************************"
+ echo "* Dry-run"
+
+ rsync -n --itemize-changes --delete --progress -axz "${DIR_MOUNT_SRC}/" "${DIR_MOUNT_DST}/"
+
+ ######################################################################
+ # Ask for confirmation and synchronize
+
+ echo "**********************************************************************"
+ echo "* Press 'y' to synchronize, anything else to cancel."
+
+ read -n 1 KEY
+
+ if [[ "${KEY}" == "y" ]]; then
+ echo
+ rsync --itemize-changes --delete --progress -axz "${DIR_MOUNT_SRC}/" "${DIR_MOUNT_DST}/"
+ else
+ echo "No synchronization."
+ fi
+
+ umount "${DIR_MOUNT_SRC}" && rmdir "${DIR_MOUNT_SRC}" && unset DIR_MOUNT_SRC
+ cryptsetup luksClose crypt-src
+ losetup -d "${LOOP_SRC}" && unset LOOP_SRC
+
+ umount "${DIR_MOUNT_DST}" && rmdir "${DIR_MOUNT_DST}" && unset DIR_MOUNT_DST
+ cryptsetup luksClose crypt-dst
+ losetup -d "${LOOP_DST}" && unset LOOP_DST
+
+ exit 0
+
+ ;;
+
+
+ ######################################################################
+
+ fsck)
+
+ shift
+
+ if [[ "$1" == "-f" ]]; then
+ force="-f"
+ shift
+ fi
+
+ if [[ ! -a "$1" ]]; then
+ echo "Cannot find file \`$1'." >&2
+ exit 1
+ fi
+
+ [[ -e "/dev/mapper/crypt-dst" ]] && (echo "/dev/mapper/crypt-dst already exists." >&2 && exit 1)
+
+ if [[ -f "$1" ]]; then
+ LOOP_DST="$(losetup -f)"
+ losetup "${LOOP_DST}" "$1"
+ DEVICE="${LOOP_DST}"
+ else
+ DEVICE="$1"
+ fi
+
+ cryptsetup luksOpen "${DEVICE}" crypt-dst
+
+ fsck ${force} /dev/mapper/crypt-dst
+
+ sleep 1
+
+ cryptsetup luksClose crypt-dst
+
+ if [[ "${LOOP_DST}" ]]; then
+ losetup -d "${LOOP_DST}" && unset LOOP_DST
+ fi
+
+ exit 0
+
+ ;;
+
+ ######################################################################
+
+ mount|umount)
+
+ if [[ "$1" == "umount" ]]; then
+ umount=yes
+ fi
+
+ shift
+
+ mount_point=$(echo $1 | sed -e "s;/*$;;")
+ device=$(grep ^/ /etc/fstab | awk '{ print $2" "$1 }' | grep ^${mount_point} | cut -f 2 -d " ")
+
+ if [[ ${device} =~ ^/dev/mapper ]]; then
+
+ mapped_device=${device/'/dev/mapper/'/}
+
+ if [[ ${umount} ]]; then
+ cat <<EOF
+Attempting to unmount
+ ${mount_point}.
+EOF
+ umount ${mount_point} && cryptdisks_stop "${mapped_device}"
+ else
+ cat <<EOF
+Attempting to mount
+ ${device}
+on
+ ${mount_point}
+EOF
+ cryptdisks_start "${mapped_device}" && mount ${mount_point}
+ fi
+
+ else
+
+ echo "\`${device}' does not look like a LUKS one"
+
+ fi
+
+ exit 0
+
+ ;;
+
+ ######################################################################
+
+ -h|--help)
+ print_help
+ ;;
+
+ *)
+ echo "Unknown argument \`$1', aborting." >&2
+ ;;
+
+esac