std.h: Don't use `extern` in function prototypes
[sunny256-utils.git] / mdisk
blobab2c87991ef1816b71f572eb553c78df6d4d1f7d
1 #!/bin/sh
3 #==============================================================================
4 # mdisk
5 # File ID: 0548a2d2-ea04-11ed-b5e0-83850402c3ce
7 # Mount a LUKS-encrypted disk under /media/
9 # Author: Øyvind A. Holm <sunny@sunbase.org>
10 # License: GNU General Public License version 2 or later.
11 #==============================================================================
13 progname=mdisk
14 VERSION=0.3.1
16 opt_help=0
17 opt_interactive=0
18 opt_quiet=0
19 opt_umount=0
20 opt_verbose=0
21 while test -n "$1"; do
22 case "$1" in
23 -a|--all) opt_all=1; shift ;;
24 -h|--help) opt_help=1; shift ;;
25 -i|--interactive) opt_interactive=1; shift ;;
26 -q|--quiet) opt_quiet=$(($opt_quiet + 1)); shift ;;
27 -u|--umount) opt_umount=1; shift ;;
28 -v|--verbose) opt_verbose=$(($opt_verbose + 1)); shift ;;
29 --version) echo $progname $VERSION; exit 0 ;;
30 --) shift; break ;;
32 if printf '%s\n' "$1" | grep -q ^-; then
33 echo "$progname: $1: Unknown option" >&2
34 exit 1
35 else
36 break
38 break ;;
39 esac
40 done
41 opt_verbose=$(($opt_verbose - $opt_quiet))
43 [ -e "$HOME/.mdiskrc" ] && . "$HOME/.mdiskrc"
45 T_BOLD=$(tput bold)
46 T_GREEN=$(tput setaf 2)
47 T_RED=$(tput setaf 1)
48 T_RESET=$(tput sgr0)
50 if test "$opt_help" = "1"; then
51 test $opt_verbose -gt 0 && { echo; echo $progname $VERSION; }
52 cat <<END
54 Mount a LUKS-encrypted disk under /media/.
56 Usage: $progname [options] DISKNAME
58 Options:
60 -a, --all
61 Loop through all directory names under /media/ and mount or unmount
62 all corresponding disks.
63 -h, --help
64 Show this help.
65 -i, --interactive
66 When used with -a/--all, ask for confirmation for each mountpoint.
67 -q, --quiet
68 Be more quiet. Can be repeated to increase silence.
69 -v, --verbose
70 Increase level of verbosity. Can be repeated.
71 -u, --umount
72 Unmount the disk.
73 --version
74 Print version information.
76 Environment variables
78 MDISK_KEY_FILE
79 Full path to text file with passphrase for encrypted drives.
81 Files and directories
83 \$HOME/.mdiskrc
84 Init file. A regular shell script that can be used to initialize
85 environment variables and run commands before normal program
86 execution.
87 .dontsleep/
88 If this directory exists at the top of the disk, the disk is
89 prevented from sleeping. When a disk with this directory is mounted,
90 a background process is started that touches a file in this
91 directory every two minutes. The current user must have write
92 permission in this directory, otherwise sleeping is not prevented.
93 When the disk is unmounted with -u/--umount, the process is killed.
95 END
96 exit 0
99 msg() {
100 test $1 -gt $opt_verbose && return;
101 shift
102 echo "$progname: $*" >&2
105 err() {
106 echo "$progname: $T_BOLD$T_RED$*$T_RESET" >&2
107 exit 1
110 is_active() {
111 sudo cryptsetup status $disk | grep -q "/dev/mapper/$disk is active"
114 is_in_blkid() {
115 sudo blkid | grep -q "LABEL=\"$1\"" && return 0
116 return 1
119 is_mounted() {
120 df | grep -q "/media/$disk\$" && return 0
121 return 1
124 strip_diskname() {
125 echo $(echo "$1" | sed 's.^/media/..; s./$..')
128 create_ds_script() {
129 echo >$ds_script || err $ds_dir/: Cannot write to directory, \
130 disk sleep is not prevented
131 cat <<'END' >$ds_script
132 #!/bin/sh
134 T_BOLD=$(tput bold)
135 T_RED=$(tput setaf 1)
136 T_RESET=$(tput sgr0)
137 outfile=.dontsleep.bin
139 rm -f $outfile
140 echo $$ >pid || {
141 echo -n "$T_BOLD$T_RED$0: Cannot write pid file to $ds_dir," >&2
142 echo " unable to prevent sleep$T_RESET" >&2
143 exit 1
145 while :; do
146 touch $outfile
147 (cd; sleep 120)
148 done
152 prevent_sleep() {
153 local disk=$1
155 msg 0 Preventing $disk from sleeping
156 cd "$ds_dir" || err $ds_dir: chdir error
157 (create_ds_script && sh $ds_script $disk) &
160 kill_prevent() {
161 local disk=$1
163 pidfile="$ds_dir/pid"
164 if [ ! -f "$pidfile" ]; then
165 echo $progname: PID file $pidfile not found >&2
166 return
168 kill $(cat $pidfile)
169 rm $pidfile
172 prompt() {
173 [ "$opt_interactive" = "0" ] && return 0
174 echo -n "$1 " >&2
175 while :; do
176 echo -n "[y/n]: " >&2
177 read choice
178 [ "$choice" = "n" ] && return 1
179 [ "$choice" = "y" ] && return 0
180 done
183 if [ "$opt_all" = "1" ]; then
184 for f in /media/*; do
185 is_in_blkid $(strip_diskname $f) || continue
186 if [ "$opt_umount" = "1" ]; then
187 prompt "Unmount $f?" && $0 -u $f
188 else
189 prompt "Mount $f?" && $0 $f
191 done
192 exit
195 disk=$(strip_diskname $1)
196 [ -z "$disk" ] && err No disk specified
198 is_in_blkid $disk || err $disk: Disk not found in blkid
200 ds_dir="/media/$disk/.dontsleep"
201 ds_script=dontsleep
203 if [ "$opt_umount" != "1" ]; then
204 is_mounted $disk && {
205 msg 0 $disk: Already mounted
206 exit 0
208 device=$(blkid -L $disk)
209 msg 1 device = \"$device\"
210 [ -z "$device" ] && err Cannot get device for $disk
211 echo "$device" | grep -q ^/dev/ || err $device: Malformed device name
212 is_active $disk \
213 || sudo cryptsetup luksOpen \
214 $([ -n "$MDISK_KEY_FILE" ] && echo "--key-file $MDISK_KEY_FILE") \
215 $device $disk && mount /media/$disk
216 is_mounted $disk \
217 && msg 0 $T_BOLD$T_GREEN$disk mounted on /media/$disk$T_RESET \
218 || err $disk: mount failed
219 [ -d "$ds_dir" ] && prevent_sleep $disk
220 else
221 [ -d "$ds_dir" ] && kill_prevent $disk
222 is_mounted $disk && umount /media/$disk
223 [ -d "$ds_dir" ] && prevent_sleep $disk
224 is_mounted $disk && err /media/$disk: umount failed
225 sudo cryptsetup luksClose $disk
226 sync
227 is_active $disk && err $disk is still active
228 msg 0 $T_BOLD$T_GREEN$disk is unmounted and closed$T_RESET
231 # vim: set ts=8 sw=8 sts=8 noet fo+=w tw=79 fenc=UTF-8 :