#!/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 extract_ssh_host() { { printf '%s\n' "$1" if [ -f ~/.ssh/config ]; then sed ' /^Host\s\+'"$1"'$/,/^Host\s/ { s/^\s*Hostname\s\+// t } d ' ~/.ssh/config fi } \ | tail -n1 } 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() { { printf '%s\n' "${fstab}" | \ grep "^$1 " | \ awk '{print "x " $3}' printf '%s\n' "${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() { { printf '%s\n' "${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" printf '%s\n' "${fstab}" | \ awk '{print $1 " " $2}' | \ sort -k2,2 -u } | \ sort -k2,2 -k1,1 | \ uniq -f1 -d | \ cut -d' ' -f1 } raid_device_to_disk() { printf '%s\n' "${mdadm_conf}" | \ grep -F " $1 " | \ cut -d' ' -f1 } crypttab=$( sed ' s|^\s*#CONF_PREFIXES#\s*|| /^\s*#/d /^\s*$/d s/\s\+/ /g s|UUID=|#UUIDDIR#/|g s/^ // ' '#ETCDIR#/crypttab' | \ sort -u ) 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/ $// ' ) mdadm_conf=$( sed ' s|^\s*#CONF_PREFIXES#\s*|| /^\s*#/d ' #ETCDIR#/mdadm.conf | \ sed -n ' /^ARRAY / { N s,^ARRAY \(\S\+\) [^\n]\+\n\s*devices=\(\S\+\)$,\1 \2 , y/,/ / s|UUID=|#UUIDDIR#/| p } ' | \ sort -u ) mount_details() { printf '%s\n' "${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 local max_tries local mount_paramters if is_mounted "$1"; then return fi inner_fs=$(inner_fs_to_mountorder "$1") case "$(mount_details fs "$1")" in 'ext'*) e2fsck -p $(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>' ) host=$(extract_ssh_host "${host}") while [ $(date +%s) -lt ${max_wait} ] && \ ! #PING6# -c1 "${host}" >/dev/null 2>&1 && \ ! 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 max_tries=10 mount_parameters=$(mount_details all "$1") while ! mount ${mount_parameters}; do max_tries=$((max_tries-1)) if [ ${max_tries} -le 0 ]; then exit 1 fi sleep 1 done if [ -n "${inner_fs}" ]; then do_mount "${inner_fs}" fi } do_unmount() { local inner_fs local lazy local mount_point 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 mount_point=$(mount_details mp "$1") while ! umount ${lazy} "${mount_point}"; do fuser -k -M -m "${mount_point}" sleep 1 done if [ -n "${inner_fs}" ]; then do_mount "${inner_fs}" fi } do_crypt_close() { if is_unlocked "$1"; then while ! cryptsetup luksClose "$1"; do sleep 1 done fi } do_crypt_open() { local key local max_tries local name local raw name="$1" raw="$2" key="$3" shift 3 if ! is_unlocked "${name}"; then max_tries=10 while ! cryptsetup luksOpen "${raw}" "${name}" --key-file="${key}" "$@"; do sleep 1 max_tries=$((max_tries-1)) if [ ${max_tries} -le 0 ]; then exit 1 fi done fi } do_integrity_close() { if is_unlocked "$1"; then while ! integritysetup close "$1" && ! dmsetup remove "$1"; do sleep 1 done fi } do_integrity_open() { local name local raw name="$1" raw="$2" if ! is_unlocked "${name}"; then max_tries=10 while ! integritysetup open "${raw}" "${name}"; do sleep 1 max_tries=$((max_tries-1)) if [ ${max_tries} -le 0 ]; then exit 1 fi done fi } do_mdadm_stop() { device="$1" if mdadm --detail "${device}" | \ grep -q '^\s*State : \(active\|clean\)\s*$'; then mdadm --stop "${device}" fi } printf '%s\n' "${crypttab}" | \ grep -vxF '' | \ while read -r name raw key options; do if [ "x${options}" = 'xro' ]; then options='--readonly' else unset options fi if [ "${key#\[*]}" != "${key}" ]; then key_slot_option="${key%%]*}" key_slot_option='--key-slot='"${key_slot_option#\[}"'' key="${key#\[*]}" else unset key_slot_option fi key_mount=$(mountpoint_to_file "${key}") raid_device=$(raid_device_to_disk "#MAPDIR#/${name}") if [ -n "${raid_device}" ]; then mount_order=$(mountorder_to_device "${raid_device}") else mount_order=$(mountorder_to_device "#MAPDIR#/${name}") fi if ${unmount}; then if [ -n "${mount_order}" ]; then printf '0 do_unmount %s\n' "${mount_order}" fi if [ -n "${raid_device}" ]; then printf '1 do_mdadm_stop %s\n' "${raid_device}" fi if [ -n "${key}" ]; then printf '3 do_crypt_close %s\n' "${name}" else printf '2 do_integrity_close %s\n' "${name}" fi else if [ -n "${key}" ]; then printf '0 do_mount %s\n' "${key_mount}" printf '1 do_crypt_open %s\n' "${name} ${raw} ${key} ${key_slot_option} ${options}" printf '2 do_unmount -l %s\n' "${key_mount}" else printf '3 do_integrity_open %s\n' "${name} ${raw}" fi if [ -n "${mount_order}" ]; then printf '4 do_mount %s\n' "${mount_order}" fi fi done | \ sort -u | \ sort -k1n,1 | \ while read -r _ aktion params; do ${aktion} ${params} done # End of file