forked from aguslr/multibootusb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
makeUSB.sh
executable file
·323 lines (279 loc) · 8.13 KB
/
makeUSB.sh
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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
#!/bin/sh
# Description: Script to prepare multiboot USB drive
# Exit if there is an unbound variable or an error
set -o nounset
set -o errexit
# show line number when execute by bash -x makeUSB.sh
export PS4=' +\t $BASH_SOURCE:$LINENO: ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
# Defaults
scriptname=$(basename "$0")
hybrid=0
eficonfig=0
interactive=0
data_part=2
data_fmt="vfat"
efi_mnt="/mnt/MBU-EFI/"
data_mnt="/mnt/MBU-DATA/"
log_file="/dev/null"
# Show usage
showUsage() {
cat <<- EOF
Script to prepare multiboot USB drive
Usage: $scriptname [options] device [fs-type]
device Device to modify (e.g. /dev/sdb)
fs-type Filesystem type for the data partition [ext3|ext4|vfat|ntfs]
-b, --hybrid Create a hybrid MBR
-e, --efi Enable EFI compatibility
-i, --interactive Launch gdisk to create a hybrid MBR
-l, --log Save debug information to log
-h, --help Display this message
EOF
}
# Clean up when exiting
cleanUp() {
# Unmount everything
umount --force "$efi_mnt" 2>/dev/null || true
umount --force "$data_mnt" 2>/dev/null || true
# Delete mountpoints
[ -d "$efi_mnt" ] && rmdir "$efi_mnt"
[ -d "$data_mnt" ] && rmdir "$data_mnt"
# Exit
exit "${1-0}"
}
# Make sure USB drive is not mounted
unmountUSB() {
umount --force "${1}"* 2>/dev/null || true
}
# Try running a command
tryCMD() {
local msg="$1"
local cmd="$2"
printf '%s... ' "$msg"
if eval "$cmd" >> "$log_file" 2>&1; then
printf 'OK\n'
else
printf 'FAILED\n'
return 1
fi
}
# Trap kill signals (SIGHUP, SIGINT, SIGTERM) to do some cleanup and exit
trap 'cleanUp' 1 2 15
# Check arguments
[ $# -eq 0 ] && showUsage && exit 0
while [ "$#" -gt 0 ]; do
case "$1" in
# Show help
-h|--help)
showUsage
exit 0
;;
-b|--hybrid)
hybrid=1
shift
;;
-e|--efi)
eficonfig=1
data_part=3
shift
;;
-i|--interactive)
interactive=1
shift
;;
-l|--log)
log_file="${scriptname%.*}.log"
printf '' "$log_file"
shift
;;
/dev/*)
if [ -b "$1" ]; then
usb_dev="$1"
else
printf '%s: %s is not a valid device.\n' "$scriptname" "$1" >&2
cleanUp 1
fi
shift
;;
*)
data_fmt="$1"
shift
;;
esac
done
# Check for root
if [ "$(id -u)" -ne 0 ]; then
printf '%s: This script must be run as root.\n' "$scriptname" >&2
cleanUp 2
fi
# Check for required arguments
if [ ! "$usb_dev" ]; then
printf '%s: No device was provided.\n' "$scriptname" >&2
showUsage
cleanUp 1
fi
# Check for required binaries
sgdisk_cmd=$(command -v sgdisk) || cleanUp 3
dd_cmd=$(command -v dd) || cleanUp 3
wget_cmd=$(command -v wget) || cleanUp 3
gunzip_cmd=$(command -v gunzip) || cleanUp 3
tar_cmd=$(command -v tar) || cleanUp 3
command -v mkfs."${data_fmt}" >/dev/null || cleanUp 3
# Check for GRUB installation binary
grub_cmd=$(command -v grub2-install) \
|| grub_cmd=$(command -v grub-install) \
|| cleanUp 3
# Unmount device
unmountUSB "$usb_dev"
# Confirm the device
read -r -p "Are you sure you want to use $usb_dev? [y/N] " answer1
case "$answer1" in
[yY][eE][sS]|[yY])
read -r -p "THIS WILL DELETE ALL DATA ON THE DEVICE. Are you sure? [y/N] " answer2
case $answer2 in
[yY][eE][sS]|[yY])
true
;;
*)
cleanUp 3
;;
esac
;;
*)
cleanUp 3
;;
esac
# Remove partitions
tryCMD "Removing partitions from $usb_dev" \
"$sgdisk_cmd --zap-all $usb_dev"
# Create GUID Partition Table
tryCMD "Creating GUID Partition Table on $usb_dev" \
"$sgdisk_cmd --mbrtogpt $usb_dev" || cleanUp 10
# Create BIOS boot partition (1M)
tryCMD "Creating BIOS boot partition on $usb_dev" \
"$sgdisk_cmd --new 1::+1M --typecode 1:ef02 \
--change-name 1:\"BIOS boot partition\" $usb_dev" || cleanUp 10
if [ "$eficonfig" -eq 1 ]; then
# Create EFI System partition (50M)
tryCMD "Creating EFI System partition on $usb_dev" \
"$sgdisk_cmd --new 2::+50M --typecode 2:ef00 --change-name 2:\"EFI System\" \
$usb_dev" || cleanUp 10
fi
# Create data partition
case "$data_fmt" in
ext2|ext3|ext4)
type_code="8300"
part_name="Linux filesystem"
;;
msdos|fat|vfat|ntfs)
type_code="0700"
part_name="Microsoft basic data"
;;
*)
printf '%s: %s is an invalid filesystem type.\n' "$scriptname" "$data_fmt" >&2
showUsage
cleanUp 1
;;
esac
tryCMD "Creating data partition on $usb_dev" \
"$sgdisk_cmd --new ${data_part}::: --typecode ${data_part}:\"$type_code\" \
--change-name ${data_part}:\"$part_name\" $usb_dev" || cleanUp 10
# Unmount device
unmountUSB "$usb_dev"
# Create hybrid MBR
if [ "$hybrid" -eq 1 ]; then
if [ "$interactive" -eq 0 ]; then
if [ "$eficonfig" -eq 1 ]; then
tryCMD "Creating hybrid MBR on ${usb_dev}" \
"$sgdisk_cmd --hybrid 1:2:3 $usb_dev" || cleanUp 10
else
tryCMD "Creating hybrid MBR on ${usb_dev}" \
"$sgdisk_cmd --hybrid 1:2 $usb_dev" || cleanUp 10
fi
else
# Create hybrid MBR manually
# https://wiki.archlinux.org/index.php/Multiboot_USB_drive#Hybrid_UEFI_GPT_.2B_BIOS_GPT.2FMBR_boot
gdisk "$usb_dev"
fi
fi
# Set bootable flag for data partion
tryCMD "Setting bootable flag on ${usb_dev}${data_part}" \
"$sgdisk_cmd --attributes ${data_part}:set:2 $usb_dev" || cleanUp 10
# Unmount device
unmountUSB "$usb_dev"
# Format BIOS boot partition
tryCMD "Formatting BIOS boot partition on ${usb_dev}1" \
"$dd_cmd if=/dev/zero of=${usb_dev}1 bs=1M count=1" || cleanUp 10
if [ "$eficonfig" -eq 1 ]; then
# Format EFI System partition
tryCMD "Formatting EFI System partition on ${usb_dev}2" \
"mkfs.vfat -v -F 32 ${usb_dev}2" || cleanUp 10
fi
# Format data partition
if [ "$data_fmt" = "ntfs" ]; then
# Use mkntfs quick format
mkfs_args="-t $data_fmt -f"
else
mkfs_args="-t $data_fmt"
fi
tryCMD "Formatting data partition as $data_fmt on ${usb_dev}${data_part}" \
"mkfs $mkfs_args ${usb_dev}${data_part}" || cleanUp 10
# Unmount device
unmountUSB "$usb_dev"
if [ "$eficonfig" -eq 1 ]; then
# Mount EFI System partition
tryCMD "Mounting EFI System partition on $efi_mnt" \
"mkdir -p $efi_mnt \
&& mount -v ${usb_dev}2 $efi_mnt" || cleanUp 10
fi
# Mount data partition
tryCMD "Mounting data partition on $data_mnt" \
"mkdir -p $data_mnt \
&& mount -v ${usb_dev}${data_part} $data_mnt" || cleanUp 10
if [ "$eficonfig" -eq 1 ]; then
# Install GRUB for EFI
tryCMD "Installing GRUB for EFI on $usb_dev" \
"$grub_cmd --target=x86_64-efi --efi-directory=$efi_mnt \
--boot-directory=${data_mnt}boot --removable --recheck" || cleanUp 10
# Unmount EFI System partition
tryCMD "Unmounting EFI System partition on $efi_mnt" "umount -v $efi_mnt" \
|| cleanUp 10
fi
# Install GRUB for BIOS
tryCMD "Installing GRUB for BIOS on $usb_dev" \
"$grub_cmd --force --target=i386-pc \
--boot-directory=${data_mnt}boot \
--recheck $usb_dev" || cleanUp 10
# Install fallback GRUB
tryCMD "Installing fallback GRUB on ${usb_dev}${data_part}" \
"$grub_cmd --force --target=i386-pc \
--boot-directory=${data_mnt}boot \
--recheck ${usb_dev}${data_part}"
# Create necessary directories
tryCMD "Creating directories on ${data_mnt}boot" \
"mkdir -p ${data_mnt}boot/bin ${data_mnt}boot/isos" || cleanUp 10
# Detect GRUB directory name
if [ -d "${data_mnt}boot/grub2" ]; then
grub_dir="${data_mnt}boot/grub2/"
elif [ -d "${data_mnt}boot/grub" ]; then
grub_dir="${data_mnt}boot/grub/"
else
cleanUp 10
fi
# Copy files
tryCMD "Copying files to ${data_mnt}boot" \
"cp -rf ./grub.* $grub_dir" || cleanUp 10
# Download memdisk
tryCMD "Downloading memdisk to ${data_mnt}boot/grub" \
"$wget_cmd -qO - \
'https://www.kernel.org/pub/linux/utils/boot/syslinux/syslinux-6.03.tar.gz' \
| $tar_cmd -xz -C $grub_dir --no-same-owner --strip-components 3 \
'syslinux-6.03/bios/memdisk/memdisk'"
# Download Memtest86+
tryCMD "Downloading Memtest86+ to ${data_mnt}boot/bin" \
"$wget_cmd -qO - 'http://www.memtest.org/download/5.01/memtest86+-5.01.bin.gz' \
| $gunzip_cmd -c > ${data_mnt}boot/bin/memtest86+.bin"
# Unmount data partition
tryCMD "Unmounting data partition on $data_mnt" "umount -v $data_mnt" \
|| cleanUp 10
# Clean up and exit
cleanUp