forked from NeonHorizon/SDBackup
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsdrestore
executable file
·198 lines (173 loc) · 4.88 KB
/
sdrestore
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#!/bin/bash
#--------------------------------------------------------------------------------
# SDRestore
# A script to decompress and restore an image onto a device such as an SD Card
#--------------------------------------------------------------------------------
# Daniel Bull
# daniel@neonhorizon.co.uk
#------------------------------------------------------------------------------*/
# Settings
thisapp="$(basename "$0")"
settingsfile=~/.sdbackup
defaultdev=""
# Automatically install what we need
if [[ ! $(type -P "unp") || ! $(type -P "ddrescue") || ! $(type -P "lshw") ]]; then
echo "It looks like this is the first time $thisapp has been run."
echo "Installing required packages..."
echo
sudo apt-get install unp gddrescue lshw || { echo "Error: Please install unp, gddrescue and lshw" 1>&2; exit 1;}
echo "Done..."
echo
fi
# Create the temporary folder if it doesn't already exist
if ! tempfolder="$(mktemp -td sdbackup.tmp.XXXXXXXX)"; then
echo "Error: Cannot create temporary folder" 1>&2
exit 1
fi
# Check filename parameter is present
if [[ "$1" = "" ]]; then
echo "Usage: $thisapp <filename> [<device>]" 1>&2
exit
fi
# Check the source file exists
file="$1"
if [[ ! -f "$file" ]]; then
# Try with a .gz extension
if [[ ! -f "$file.gz" ]]; then
echo "Error: $1 doesnt exist?" 1>&2
exit 1
fi
file+=".gz"
fi
# Get a device name
if [[ "$2" != "" ]]; then
# Supplied on CLI
dev="$2"
else
# Get the default
if [[ -f "$settingsfile" ]]; then
defaultdev="$(cat "$settingsfile")"
fi
# Scan for disks
echo "Scanning drives..."
declare -a line
declare -a devices
declare -a sizes
declare -a names
device=0;
while IFS=":" read -r -a line; do
case "${line[0]}" in
*"description")
device=$((device+1))
devices[$device]=""
sizes[$device]=""
names[$device]=""
;;
*"logical name")
devices[$device]="${line[1]# }"
;;
*"size")
sizes[$device]+="${line[1]# }"
;;
*"product")
names[$device]+="${line[1]# }"
;;
esac
done < <(sudo lshw -class disk 2> /dev/null)
unset line
# Display a list of options
echo
defaultselect=0
for i in "${!devices[@]}"; do
if [[ "${sizes[$i]}" ]]; then
echo "$i) ${devices[$i]} ${names[$i]} (${sizes[$i]})"
else
echo "$i) ${devices[$i]} ${names[$i]} (currently empty)"
fi
if [[ "${devices[$i]:1}" = "$defaultdev" ]]; then
defaultselect=$i
fi
done
echo "0) Cancel"
# Ask the user to select
echo
dev=""
while ! [[ "$dev" ]]; do
read -rp "Please select your device [$defaultselect]: " selected
if ! [[ "$selected" ]]; then
selected=$defaultselect
fi
if [[ "$selected" = 0 ]]; then
exit;
fi
if [[ "$selected" =~ ^[01234567890]$ ]]; then
dev="${devices["$selected"]:1}"
fi
done
fi
# Check the device exists
if [[ ! -b "$dev" ]]; then
echo "Error: $dev is not a block device?" 1>&2
exit 1;
fi
# Confirm
read -rp "Restore from $file to $dev is that correct? [y/N]: " -n1 agree
if ! [[ "$agree" =~ ^[yY]$ ]]; then
exit
fi
echo
echo
# Filenames
lockfile="/tmp/sdbackup${dev////_}.lock"
tempfile="$tempfolder/${file}_${dev////_}.tempfile"
errfile="$tempfolder/${file}_${dev////_}.error"
# Test and create lockfile
if [[ -f $lockfile ]]; then
echo "Error: There is a $(cat "$lockfile") currently running on $dev" 1>&2;
exit 1;
fi
echo "$thisapp ($$)" > "$lockfile"
# Trap for failure
trap 'rm "$lockfile" 2> /dev/null; rm "$tempfile" 2> /dev/null; rm "$errfile" 2> /dev/null; rmdir "$tempfolder" 2> /dev/null' EXIT
# Clean up anything left over from a previous attempt
sudo rm "/tmp/sdbackup.tmp."*/*.tempfile 2> /dev/null
sudo rm "/tmp/sdbackup.tmp."*/*.error 2> /dev/null
sudo rmdir "/tmp/sdbackup.tmp."* 2> /dev/null
# Unmount the card
echo "Unmounting any mounted partitions..."
for partition in "$dev"*; do
if [[ -b "$partition" ]]; then
if grep -Eqs ^"$partition " /proc/mounts; then
sudo umount "$partition" 2> /dev/null || { echo "Error: Cannot unmount $partition" 1>&2; exit 1; }
fi
fi
done
# See if the file needs decompressing
if file \"$file\" | grep -q 'compressed\|archive'; then
# Decompress the file
echo "Decompressing..."
ucat "$file" > "$tempfile" 2> "$errfile" || { echo "Error: Cannot decompress $file" 1>&2; exit 1; }
if [[ -s "$errfile" ]]; then
echo "Error: Cannot decompress $file" 1>&2;
exit 1;
fi
restorefile="$tempfile"
else
# No temp file needed
restorefile="$file"
fi
# Check its not still compressed
if file \"$restorefile\" | grep -q 'compressed\|archive'; then
echo "Error: Cannot decompress $file" 1>&2;
exit 1;
fi
# Restore the file
echo "Restoring $(stat -c %s "$restorefile") bytes to $dev..."
echo
sudo ddrescue --force --synchronous "$restorefile" "$dev" || exit 1;
echo
echo "Syncing the card ready for ejection..."
sync
echo "Restore complete."
# Set device as default
echo "$dev" > "$settingsfile"