]> Sergey Matveev's repositories - nnn.git/blob - plugins/nmount
nmount: add support for luks volumes for udisksctl
[nnn.git] / plugins / nmount
1 #!/usr/bin/env sh
2
3 # Description: Toggle mount status of a device using pmount
4 #              If the device is not mounted, it will be mounted.
5 #              If the device is mounted, it will be unmounted and powered down.
6 #
7 # Dependencies: lsblk, pmount (optional), udisks2
8 #
9 # Usage: Runs `lsblk` on 'l', exits on 'Return`.
10 #
11 # Notes:
12 #   - The script uses Linux-specific lsblk to list block devices. Alternatives:
13 #       macOS: "diskutil list"
14 #       BSD: "geom disk list"
15 #   - The script uses udisksctl (from udisks2) to power down devices. This is also Linux-specific.
16 #     Users on non-Linux platforms can comment it and use an alternative to power-down disks.
17 #
18 # Shell: POSIX compliant
19 # Author: Arun Prakash Jana
20
21 prompt="device name [e.g. sdXn] ('l'ist, 'q'uit): "
22
23 lsblk
24
25 printf "\nEnsure you aren't still in the mounted device.\n"
26 printf "%s" "$prompt"
27 read -r dev
28
29 while [ -n "$dev" ]; do
30     if [ "$dev" = "l" ]; then
31         lsblk
32     elif [ "$dev" = "q" ]; then
33         exit
34     else
35         # LUKS volumes mounted with udisksctl appear differently than with pmount
36         if grep -qs "$dev " /proc/mounts || [ -n "$(lsblk -n "/dev/$dev" -o MOUNTPOINT)" ]; then
37             sync "$(lsblk -n "/dev/$dev" -o MOUNTPOINT | sed "/^$/d")"
38             if type pumount >/dev/null 2>&1; then
39                 pumount "/dev/$dev"
40                 exit_code="$?"
41             else
42                 # Unlike pmount, udisksctl does not transparently handle LUKS volumes
43                 # We need to manually get the unlocked device, unmount it, and then lock the volume
44                 if lsblk -n "/dev/$dev" -o FSTYPE | grep "crypto_LUKS" >/dev/null; then
45                     dev_map="$(udisksctl info -b /dev/"$dev" | grep "CleartextDevice" | grep -o "dm_2d[[:digit:]]*" | sed "s/_2d/-/")"
46                     udisksctl unmount -b "/dev/$dev_map" --no-user-interaction >/dev/null
47                     exit_code="$?"
48                     udisksctl lock -b "/dev/$dev" --no-user-interaction >/dev/null
49                 else
50                     udisksctl unmount -b "/dev/$dev" --no-user-interaction >/dev/null
51                     exit_code="$?"
52                 fi
53             fi
54             if [ $exit_code -eq 0 ]; then
55                 echo "/dev/$dev unmounted."
56                 if udisksctl power-off -b "/dev/$dev" --no-user-interaction; then
57                     echo "/dev/$dev ejected."
58                 fi
59             fi
60         elif [ -b "/dev/$dev" ]; then
61             if type pmount >/dev/null 2>&1; then
62                 pmount "/dev/$dev"
63                 exit_code="$?"
64             else
65                 # Unlike pmount, udisksctl does not transparently handle LUKS volumes
66                 # We need to manually get the unlocked device and mount that instead of the volume itself
67                 if [ "$(lsblk "/dev/$dev" -n -o FSTYPE)" = "crypto_LUKS" ]; then
68                     dev_map=$(udisksctl unlock -b "/dev/$dev" --no-user-interaction | grep -o "dm-[[:digit:]]*")
69                     udisksctl mount -b "/dev/$dev_map" --no-user-interaction >/dev/null
70                     exit_code="$?"
71                 else
72                     udisksctl mount -b "/dev/$dev" --no-user-interaction >/dev/null
73                     exit_code="$?"
74                 fi
75             fi
76             if [ $exit_code -eq 0 ]; then
77                 sleep 1
78                 echo "/dev/$dev mounted to $(lsblk -n "/dev/$dev" -o MOUNTPOINT | sed "/^$/d")."
79             fi
80         else
81             echo "/dev/$dev does not exist or is not a block device."
82         fi
83     fi
84
85     echo
86     printf "%s" "$prompt"
87     read -r dev
88 done