diff options
Diffstat (limited to 'cryptfs.bin.in')
-rw-r--r-- | cryptfs.bin.in | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/cryptfs.bin.in b/cryptfs.bin.in new file mode 100644 index 0000000..fde3bd0 --- /dev/null +++ b/cryptfs.bin.in @@ -0,0 +1,236 @@ +#!/bin/bash +# +# #BINDIR#/cryptfs: mount/umount encrypted partitions +# + +set -e + +if [ $# -eq 1 ] && [ "x$1" = 'x-u' ]; then + unmount=true +elif [ $# -eq 0 ]; then + unmount=false +else + >&2 printf 'Usage: %s [-u]\n' "$0" + exit 1 +fi + +give_all_parent_dirs() { + local odir + local dir + odir="$1" + odir="/${odir#/}" + dir="${odir%/*}" + while [ "${dir}" != '' ]; do + printf '%s %s\n' "${odir}" "${dir}" + dir="${dir%/*}" + done +} + +inner_fs_to_mountorder() { + { + echo "${fstab}" | \ + grep "^$1 " | \ + awk '{print "x " $3}' + echo "${fstab}" | \ + sed -n ' + s|^\(\S\+\) \S\+ \(\S\+\)\( .*\)\?$|\1 \2| + T + p + ' | \ + while read -r order dir; do + give_all_parent_dirs "${dir}" | \ + awk '{print "'"${order}"' " $1 " " $2}' + done | \ + sort -k3,3 -k2r,2 | \ + uniq -f2 | \ + cut -d' ' -f1,3 + } | \ + sort -k2r,2 -k1,1 | \ + uniq -f1 -d | \ + cut -d' ' -f1 +} + +mountpoint_to_file() { + { + echo "${fstab}" | \ + awk '{print $1 " " $3}' + give_all_parent_dirs "$1" | \ + awk '{print "x " $2}' + } | \ + sort -k2r,2 -k1,1 | \ + uniq -f1 -d | \ + cut -d' ' -f1 | \ + head -n1 +} + +mountorder_to_device() { + { + printf 'x %s\n' "$1" + echo "${fstab}" | \ + awk '{print $1 " " $2}' | \ + sort -k2,2 -u + } | \ + sort -k2,2 -k1,1 | \ + uniq -f1 -d | \ + cut -d' ' -f1 +} + +crypttab=$( + sed ' + s|^\s*#CONF_PREFIXES#\s*|| + /^\s*#/d + /^\s*$/d + s/\s\+/ /g + ' '#ETCDIR#/crypttab' | \ + sort -u | \ + sed ' + s|UUID=|#UUIDDIR#/| + s/\s\+/ /g + s/^ // + ' +) +fstab=$( + sed ' + s|^\s*#CONF_PREFIXES#\s*|| + /^\s*#/d + /^\s*\S\+\s\+[^\/[:space:]]/d + /^\s*$/d + s/\s\+/ /g + ' '#ETCDIR#/fstab' | \ + sort -u | \ + cat -n | \ + sed ' + s|UUID=|#UUIDDIR#/| + s/\s\+/ /g + s/^ // + s/ \+$// + ' +) + +mount_details() { + echo "${fstab}" | \ + grep "^$2 " | \ + while read -r _ source dest fs opts _; do + case "$1" in + 'mp') + printf '%s\n' "${dest}" + ;; + 'dev') + printf '%s\n' "${source}" + ;; + 'fs') + printf '%s\n' "${fs}" + ;; + 'all') + printf -- '-t %s ' "${fs}" + if [ -n "${opts}" ] && \ + [ "${opts}" != 'defaults' ]; then + printf -- '-o %s ' "${opts}" + fi + printf '%s %s\n' "${source}" "${dest}" + ;; + *) + >&2 printf 'unknown mount_details "%s"\n' "$1" + exit 42 + ;; + esac + done +} + +is_mounted() { + mountpoint -q "$(mount_details mp "$1")" +} + +is_unlocked() { + cryptsetup status "$1" >/dev/null 2>&1 +} + +do_mount() { + local inner_fs + if is_mounted "$1"; then + return + fi + inner_fs=$(inner_fs_to_mountorder "$1") + + case "$(mount_details fs "$1")" in + 'ext'*) + e2fsck $(mount_details dev "$1") + ;; + 'fuse.sshfs'|'fuse.ftps') + local max_wait + local host + max_wait=$(($(date +%s)+120)) + host=$( + mount_details dev "$1" | \ + sed 's>^\([^:@]*@\)\?\([^:@]\+\):\S*$>\2>" + ) + while [ $(date +%s) -lt ${max_wait} ] && \ + ! /bin/ping6 -c1 ${host} >/dev/null 2>&1 && \ + ! /bin/ping -c1 ${host} >/dev/null 2>&1; do + >&2 printf ',' + sleep 1 + done + ;; + esac + + if [ -n "${inner_fs}" ]; then + do_unmount -l "${inner_fs}" + fi + mount $(mount_details all "$1") + if [ -n "${inner_fs}" ]; then + do_mount "${inner_fs}" + fi +} + +do_unmount() { + local inner_fs + local lazy + if [ "x$1" = 'x-l' ]; then + lazy='-l' + shift + else + lazy='' + fi + if ! is_mounted "$1"; then + return + fi + inner_fs=$(inner_fs_to_mountorder "$1") + if [ -n "${inner_fs}" ]; then + do_unmount -l "${inner_fs}" + fi + umount ${lazy} $(mount_details mp "$1") + if [ -n "${inner_fs}" ]; then + do_mount "${inner_fs}" + fi +} + +do_crypt_close() { + if is_unlocked "$1"; then + cryptsetup luksClose "$1" + fi +} + +do_crypt_open() { + if ! is_unlocked "$1"; then + cryptsetup luksOpen "$1" "$2" --key-file="$3" + fi +} + +echo "${crypttab}" | \ + while read -r name raw key; do + key="${key%% *}" + key_mount=$(mountpoint_to_file "${key}") + mount_order=$(mountorder_to_device "#MAPDIR#/${name}") + + if ${unmount}; then + do_unmount "${mount_order}" + do_crypt_close "${name}" + else + do_mount "${key_mount}" + do_crypt_open "${name}" "${raw}" "${key}" + do_unmount -l "${key_mount}" + do_mount "${mount_order}" + fi + done + +# End of file |