aboutsummaryrefslogtreecommitdiff
path: root/luks-shield
blob: 9080f35283acf64bc2257614bf26494b5bbba949 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#!/usr/bin/env bash
set -euo pipefail

UUID="6659e638-d52a-4c32-9781-9dcedd44db35"
NAME="shield"
MNT="/mnt/shield"

DEV_BY_UUID="/dev/disk/by-uuid/${UUID}"
MAPPER="/dev/mapper/${NAME}"

die() { echo "Error: $*" >&2; exit 1; }

need_cmd() {
  command -v "$1" >/dev/null 2>&1 || die "Missing command: $1"
}

resolve_blockdev() {
  # Resolve the UUID symlink to an absolute /dev/... node
  local target
  target="$(readlink -f "$DEV_BY_UUID")" || return 1
  [[ -b "$target" ]] || return 1
  echo "$target"
}

is_mapped() {
  [[ -e "$MAPPER" ]]
}

is_mounted() {
  mountpoint -q "$MNT"
}

show_busy() {
  echo "Mount appears busy. Processes using $MNT:"
  # lsof is optional but useful; show what we can.
  if command -v lsof >/dev/null 2>&1; then
    sudo lsof +f -- "$MNT" || true
  else
    echo "(Install lsof: sudo apt install lsof)"
    sudo fuser -vm "$MNT" || true
  fi
}

do_open() {
  need_cmd cryptsetup
  need_cmd mount
  need_cmd mountpoint
  need_cmd readlink

  [[ -e "$DEV_BY_UUID" ]] || die "UUID device not found: $DEV_BY_UUID (is the drive plugged in?)"

  local dev
  dev="$(resolve_blockdev)" || die "Could not resolve block device for UUID: $UUID"

  if is_mapped; then
    echo "Mapper already exists: $MAPPER"
  else
    sudo cryptsetup open "$dev" "$NAME"
  fi

  if [[ ! -d "$MNT" ]]; then
    sudo mkdir -p "$MNT"
  fi

  if is_mounted; then
    echo "Already mounted: $MNT"
  else
    sudo mount "$MAPPER" "$MNT"
  fi

  sudo sync
  echo "OK: unlocked and mounted at $MNT"
}

do_close() {
  need_cmd cryptsetup
  need_cmd umount
  need_cmd mountpoint
  need_cmd readlink

  if is_mounted; then
    sudo sync
    if ! sudo umount "$MNT"; then
      show_busy
      die "Unmount failed"
    fi
  fi

  if is_mapped; then
    sudo cryptsetup close "$NAME"
  fi

  # Best-effort power-off
  if [[ -e "$DEV_BY_UUID" ]]; then
    local dev
    dev="$(resolve_blockdev)" || true
    if [[ -n "${dev:-}" ]]; then
      if command -v udisksctl >/dev/null 2>&1; then
        sudo udisksctl power-off -b "$dev" || true
      fi
    fi
  fi

  echo "OK: unmounted, closed, and powered off (if supported)"
}

do_status() {
  echo "UUID device: $DEV_BY_UUID"
  if [[ -e "$DEV_BY_UUID" ]]; then
    echo "Resolved:   $(readlink -f "$DEV_BY_UUID")"
  else
    echo "Resolved:   (not present)"
  fi

  echo -n "Mapper:     "
  if is_mapped; then echo "OPEN ($MAPPER)"; else echo "CLOSED"; fi

  echo -n "Mount:      "
  if is_mounted; then echo "MOUNTED ($MNT)"; else echo "NOT MOUNTED"; fi
}

usage() {
  cat <<EOF
Usage: $0 {open|close|status}

open   - unlock LUKS by UUID and mount to $MNT
close  - sync, unmount, close mapper, power-off block device (best-effort)
status - show current state
EOF
}

main() {
  case "${1:-}" in
    open)   do_open ;;
    close)  do_close ;;
    status) do_status ;;
    *) usage; exit 2 ;;
  esac
}

main "$@"